mod_pubsub_github/mod_pubsub_github.lua
author Matthew Wild <mwild1@gmail.com>
Thu, 28 Jan 2021 07:04:11 +0000
changeset 4413 44f6537f6427
parent 3535 3bece2db869c
permissions -rw-r--r--
mod_invites_adhoc: Fail contact invite if user is not on current host Only the username was being used, and the host of the requester ignored. Luckily this only affects admins of the host. If they want to create an account they can use the other command. If they want to create a contact they should request from their account on this host.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     1
module:depends("http");
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     2
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     3
local st = require "util.stanza";
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     4
local json = require "util.json";
3524
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
     5
local hashes = require "util.hashes";
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
     6
local from_hex = require "util.hex".from;
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
     7
local hmacs = {
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
     8
	sha1 = hashes.hmac_sha1;
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
     9
	sha256 = hashes.hmac_sha256;
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    10
	sha384 = hashes.hmac_sha384;
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    11
	sha512 = hashes.hmac_sha512;
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    12
};
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
local pubsub_service = module:depends("pubsub").service;
3525
a200fbce0ecb mod_pubsub_github: Add some spacing to improve readability
Kim Alvefur <zash@zash.se>
parents: 3524
diff changeset
    15
a200fbce0ecb mod_pubsub_github: Add some spacing to improve readability
Kim Alvefur <zash@zash.se>
parents: 3524
diff changeset
    16
-- configuration
3521
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
    17
local default_node = module:get_option("github_node", "github");
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
    18
local node_prefix = module:get_option_string("github_node_prefix", "github/");
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
    19
local node_mapping = module:get_option_string("github_node_mapping");
3518
8811b7dbe6e2 mod_pubsub_github: Add support for specifying an actor with less privileges
Kim Alvefur <zash@zash.se>
parents: 3517
diff changeset
    20
local github_actor = module:get_option_string("github_actor") or true;
3529
8c1a3b989990 mod_pubsub_github: Rename variable to avoid name clash [luacheck]
Kim Alvefur <zash@zash.se>
parents: 3526
diff changeset
    21
local github_secret = module:get_option("github_secret");
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    22
3525
a200fbce0ecb mod_pubsub_github: Add some spacing to improve readability
Kim Alvefur <zash@zash.se>
parents: 3524
diff changeset
    23
-- validation
3529
8c1a3b989990 mod_pubsub_github: Rename variable to avoid name clash [luacheck]
Kim Alvefur <zash@zash.se>
parents: 3526
diff changeset
    24
assert(github_secret, "Please set 'github_secret'");
3519
f756e051fa02 mod_pubsub_github: Require a secret to be set (BC)
Kim Alvefur <zash@zash.se>
parents: 3518
diff changeset
    25
3513
94414cadfcaa mod_pubsub_github: Return appropriate status code on failure to publish
Kim Alvefur <zash@zash.se>
parents: 3512
diff changeset
    26
local error_mapping = {
94414cadfcaa mod_pubsub_github: Return appropriate status code on failure to publish
Kim Alvefur <zash@zash.se>
parents: 3512
diff changeset
    27
	["forbidden"] = 403;
94414cadfcaa mod_pubsub_github: Return appropriate status code on failure to publish
Kim Alvefur <zash@zash.se>
parents: 3512
diff changeset
    28
	["item-not-found"] = 404;
94414cadfcaa mod_pubsub_github: Return appropriate status code on failure to publish
Kim Alvefur <zash@zash.se>
parents: 3512
diff changeset
    29
	["internal-server-error"] = 500;
94414cadfcaa mod_pubsub_github: Return appropriate status code on failure to publish
Kim Alvefur <zash@zash.se>
parents: 3512
diff changeset
    30
	["conflict"] = 409;
94414cadfcaa mod_pubsub_github: Return appropriate status code on failure to publish
Kim Alvefur <zash@zash.se>
parents: 3512
diff changeset
    31
};
94414cadfcaa mod_pubsub_github: Return appropriate status code on failure to publish
Kim Alvefur <zash@zash.se>
parents: 3512
diff changeset
    32
3524
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    33
local function verify_signature(secret, body, signature)
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    34
	if not signature then return false; end
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    35
	local algo, digest = signature:match("^([^=]+)=(%x+)");
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    36
	if not algo then return false; end
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    37
	local hmac = hmacs[algo];
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    38
	if not algo then return false; end
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    39
	return hmac(secret, body) == from_hex(digest);
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    40
end
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    41
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
function handle_POST(event)
3512
a98a3922bc01 mod_pubsub_github: Send sensible status codes
Kim Alvefur <zash@zash.se>
parents: 3269
diff changeset
    43
	local request, response = event.request, event.response;
3524
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    44
3529
8c1a3b989990 mod_pubsub_github: Rename variable to avoid name clash [luacheck]
Kim Alvefur <zash@zash.se>
parents: 3526
diff changeset
    45
	if not verify_signature(github_secret, request.body, request.headers.x_hub_signature) then
3524
37e89a76c7d7 mod_pubsub_github: Lift signature validation from mod_pubsub_post
Kim Alvefur <zash@zash.se>
parents: 3523
diff changeset
    46
		module:log("debug", "Signature validation failed");
3268
f48bedd1d433 mod_pubsub_github: Add support for signed requests
Kim Alvefur <zash@zash.se>
parents: 3267
diff changeset
    47
		return 401;
f48bedd1d433 mod_pubsub_github: Add support for signed requests
Kim Alvefur <zash@zash.se>
parents: 3267
diff changeset
    48
	end
3525
a200fbce0ecb mod_pubsub_github: Add some spacing to improve readability
Kim Alvefur <zash@zash.se>
parents: 3524
diff changeset
    49
3267
a65f4297264b mod_pubsub_github: Unpack request from event
Kim Alvefur <zash@zash.se>
parents: 1624
diff changeset
    50
	local data = json.decode(request.body);
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
	if not data then
3512
a98a3922bc01 mod_pubsub_github: Send sensible status codes
Kim Alvefur <zash@zash.se>
parents: 3269
diff changeset
    52
		response.status_code = 400;
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    53
		return "Invalid JSON. From you of all people...";
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
	end
1343
7dbde05b48a9 all the things: Remove trailing whitespace
Florian Zeitz <florob@babelmonkeys.de>
parents: 860
diff changeset
    55
3530
bcfd6e5bb0f5 mod_pubsub_github: Reorder code to prepare for more code reordering
Kim Alvefur <zash@zash.se>
parents: 3529
diff changeset
    56
	local node = default_node;
bcfd6e5bb0f5 mod_pubsub_github: Reorder code to prepare for more code reordering
Kim Alvefur <zash@zash.se>
parents: 3529
diff changeset
    57
	if node_mapping then
bcfd6e5bb0f5 mod_pubsub_github: Reorder code to prepare for more code reordering
Kim Alvefur <zash@zash.se>
parents: 3529
diff changeset
    58
		node = node_prefix .. data.repository[node_mapping];
bcfd6e5bb0f5 mod_pubsub_github: Reorder code to prepare for more code reordering
Kim Alvefur <zash@zash.se>
parents: 3529
diff changeset
    59
	end
bcfd6e5bb0f5 mod_pubsub_github: Reorder code to prepare for more code reordering
Kim Alvefur <zash@zash.se>
parents: 3529
diff changeset
    60
3533
6ac98c4dbbd3 mod_pubsub_github: Get event type from payload (should work with gitlab)
Kim Alvefur <zash@zash.se>
parents: 3530
diff changeset
    61
	local github_event = request.headers.x_github_event or data.object_kind;
3535
3bece2db869c mod_pubsub_github: Assume unspecified event is 'push' if there are commits in payload
Kim Alvefur <zash@zash.se>
parents: 3534
diff changeset
    62
	if not github_event and data.commits then
3bece2db869c mod_pubsub_github: Assume unspecified event is 'push' if there are commits in payload
Kim Alvefur <zash@zash.se>
parents: 3534
diff changeset
    63
		github_event = "push"; -- curl?
3bece2db869c mod_pubsub_github: Assume unspecified event is 'push' if there are commits in payload
Kim Alvefur <zash@zash.se>
parents: 3534
diff changeset
    64
	end
3534
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    65
	module:log("debug", "Handling '%s' event: \n%s\n", github_event, tostring(request.body));
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    66
3517
9556e92b2ec4 mod_pubsub_github: Abort on unknown github events
Kim Alvefur <zash@zash.se>
parents: 3514
diff changeset
    67
	if github_event == "push" then
3534
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    68
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    69
		for _, commit in ipairs(data.commits) do
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    70
			local ok, err = pubsub_service:publish(node, github_actor, commit.id,
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    71
				st.stanza("item", { id = commit.id, xmlns = "http://jabber.org/protocol/pubsub" })
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    72
				:tag("entry", { xmlns = "http://www.w3.org/2005/Atom" })
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    73
					:tag("id"):text(commit.id):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    74
					:tag("title"):text(commit.message:match("^[^\r\n]*")):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    75
					:tag("summary"):text(("Commit to %s by %s: %s"):format(data.repository.name, commit.author.name, commit.message:match("^[^\r\n]*"))):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    76
					:tag("content"):text(commit.message):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    77
					:tag("link", { rel = "alternate", href = commit.url }):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    78
					:tag("published"):text(commit.author.date):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    79
					:tag("author")
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    80
						:tag("name"):text(commit.author.name):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    81
						:tag("email"):text(commit.author.email):up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    82
						:up()
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    83
			);
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    84
			if not ok then
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    85
				return error_mapping[err] or 500;
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    86
			end
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    87
		end
552d4944d1ca mod_pubsub_github: Rearrange code to make it easier to handle other event types
Kim Alvefur <zash@zash.se>
parents: 3533
diff changeset
    88
3517
9556e92b2ec4 mod_pubsub_github: Abort on unknown github events
Kim Alvefur <zash@zash.se>
parents: 3514
diff changeset
    89
	elseif github_event then
9556e92b2ec4 mod_pubsub_github: Abort on unknown github events
Kim Alvefur <zash@zash.se>
parents: 3514
diff changeset
    90
		module:log("debug", "Unsupported Github event %q", github_event);
9556e92b2ec4 mod_pubsub_github: Abort on unknown github events
Kim Alvefur <zash@zash.se>
parents: 3514
diff changeset
    91
		return 501;
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    92
	end
1343
7dbde05b48a9 all the things: Remove trailing whitespace
Florian Zeitz <florob@babelmonkeys.de>
parents: 860
diff changeset
    93
3512
a98a3922bc01 mod_pubsub_github: Send sensible status codes
Kim Alvefur <zash@zash.se>
parents: 3269
diff changeset
    94
	response.status_code = 202;
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    95
	return "Thank you Github!";
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    96
end
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    97
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    98
module:provides("http", {
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    99
	route = {
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   100
		POST = handle_POST;
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   101
	};
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   102
});
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   103
3521
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   104
if not node_mapping then
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   105
	function module.load()
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   106
		if not pubsub_service.nodes[default_node] then
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   107
			local ok, err = pubsub_service:create(default_node, true);
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   108
			if not ok then
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   109
				module:log("error", "Error creating node: %s", err);
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   110
			else
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   111
				module:log("debug", "Node %q created", default_node);
ea1edd7cfb01 mod_pubsub_github: Add support for publishing to multiple node based on repository
Kim Alvefur <zash@zash.se>
parents: 3520
diff changeset
   112
			end
860
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   113
		end
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   114
	end
1c886affb375 mod_pubsub_github: Receive Github web hooks (generated on pushes to a repository) and forward to a local pubsub node
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   115
end