Annotate

mod_pubsub_forgejo/mod_pubsub_forgejo.lua @ 6310:30adcea825c3

mod_conversejs: Fix hostname set as default username (thanks roughnecks) In login mode, it seems jid is used as default value in the login field but it was only needed in anonymous mode.
author Kim Alvefur <zash@zash.se>
date Wed, 18 Jun 2025 14:28:38 +0200
parent 6203:131b8bfbefb4
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6203
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
1 module:depends("http")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
2 local pubsub_service = module:depends("pubsub").service
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
3
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
4 local st = require "util.stanza"
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
5 local json = require "util.json"
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
6 local hashes = require "util.hashes"
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
7 local from_hex = require"util.hex".from
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
8 local hmacs = {
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
9 sha1 = hashes.hmac_sha1,
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
10 sha256 = hashes.hmac_sha256,
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
11 sha384 = hashes.hmac_sha384,
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
12 sha512 = hashes.hmac_sha512
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
13 }
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
14
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
15 local format = module:require "format"
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
16 local default_templates = module:require "templates"
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
17
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
18 -- configuration
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
19 local forgejo_secret = module:get_option("forgejo_secret")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
20
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
21 local default_node = module:get_option("forgejo_node", "forgejo")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
22 local node_prefix = module:get_option_string("forgejo_node_prefix", "forgejo/")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
23 local node_mapping = module:get_option_string("forgejo_node_mapping")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
24 local forgejo_actor = module:get_option_string("forgejo_actor") or true
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
25
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
26 local skip_commitless_push = module:get_option_boolean(
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
27 "forgejo_skip_commitless_push", true)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
28 local custom_templates = module:get_option("forgejo_templates")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
29
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
30 local forgejo_templates = default_templates
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
31
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
32 if custom_templates ~= nil then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
33 for k, v in pairs(custom_templates) do forgejo_templates[k] = v end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
34 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
35
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
36 -- used for develoment, should never be set in prod!
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
37 local insecure = module:get_option_boolean("forgejo_insecure", false)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
38 -- validation
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
39 if not insecure then assert(forgejo_secret, "Please set 'forgejo_secret'") end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
40
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
41 local error_mapping = {
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
42 ["forbidden"] = 403,
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
43 ["item-not-found"] = 404,
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
44 ["internal-server-error"] = 500,
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
45 ["conflict"] = 409
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
46 }
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
47
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
48 local function verify_signature(secret, body, signature)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
49 if insecure then return true end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
50 if not signature then return false end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
51 local algo, digest = signature:match("^([^=]+)=(%x+)")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
52 if not algo then return false end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
53 local hmac = hmacs[algo]
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
54 if not algo then return false end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
55 return hmac(secret, body) == from_hex(digest)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
56 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
57
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
58 function handle_POST(event)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
59 local request, response = event.request, event.response
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
60
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
61 if not verify_signature(forgejo_secret, request.body,
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
62 request.headers.x_hub_signature) then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
63 module:log("debug", "Signature validation failed")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
64 return 401
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
65 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
66
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
67 local data = json.decode(request.body)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
68 if not data then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
69 response.status_code = 400
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
70 return "Invalid JSON. From you of all people..."
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
71 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
72
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
73 local forgejo_event = request.headers.x_forgejo_event or data.object_kind
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
74
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
75 if skip_commitless_push and forgejo_event == "push" and data.total_commits == 0 then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
76 module:log("debug", "Skipping push event with 0 commits")
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
77 return 501
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
78 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
79
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
80 if forgejo_templates[forgejo_event] == nil then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
81 module:log("debug", "Unsupported forgejo event %q", forgejo_event)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
82 return 501
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
83 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
84
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
85 local item = format(data, forgejo_templates[forgejo_event])
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
86
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
87 if item == nil then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
88 module:log("debug", "Formatter returned nil for event %q", forgejo_event)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
89 return 501
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
90 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
91
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
92 local node = default_node
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
93 if node_mapping then node = node_prefix .. data.repository[node_mapping] end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
94
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
95 create_node(node)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
96
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
97 local ok, err = pubsub_service:publish(node, forgejo_actor, item.attr.id, item)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
98 if not ok then return error_mapping[err] or 500 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
99
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
100 response.status_code = 202
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
101 return "Thank you forgejo.\n" .. tostring(item:indent(1, " "))
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
102 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
103
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
104 module:provides("http", {route = {POST = handle_POST}})
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
105
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
106 function create_node(node)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
107 if not pubsub_service.nodes[node] then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
108 local ok, err = pubsub_service:create(node, true)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
109 if not ok then
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
110 module:log("error", "Error creating node: %s", err)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
111 else
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
112 module:log("debug", "Node %q created", node)
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
113 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
114 end
131b8bfbefb4 mod_pubsub_forgejo: new module for forgejo webhooks
nicoco <nicoco@nicoco.fr>
parents:
diff changeset
115 end