Software / code / prosody-modules
Annotate
mod_pubsub_forgejo/mod_pubsub_forgejo.lua @ 6342:3eb0255b41b3
mod_http_oauth2: Update README to mention XEP-0493
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Tue, 15 Jul 2025 23:06:10 +0200 |
| parent | 6203:131b8bfbefb4 |
| 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 |