diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index cb4d2f8..457d9b3 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -95,6 +95,7 @@ modules_enabled = { "invites_register_api"; "invites_tracking"; "invites_default_group"; + "invites_boostrap"; "firewall"; @@ -133,6 +134,9 @@ allow_contact_invites = false invites_page = ENV_SNIKKET_INVITE_URL or ("https://"..DOMAIN.."/invite/{invite.token}/"); invites_page_external = true +invites_boostrap_index = tonumber(ENV_TWEAK_SNIKKET_BOOTSTRAP_INDEX) +invites_bootstrap_secret = ENV_TWEAK_SNIKKET_BOOTSTRAP_SECRET + c2s_require_encryption = true s2s_require_encryption = true s2s_secure_auth = true diff --git a/ansible/tasks/prosody.yml b/ansible/tasks/prosody.yml index 13aa54e..636bf1a 100644 --- a/ansible/tasks/prosody.yml +++ b/ansible/tasks/prosody.yml @@ -122,6 +122,7 @@ - mod_update_check - mod_update_notify - mod_invites_default_group + - mod_invites_bootstrap - name: "Install lua-ossl for encrypted push notifications" apt: diff --git a/snikket-modules/mod_invites_bootstrap/mod_invites_bootstrap.lua b/snikket-modules/mod_invites_bootstrap/mod_invites_bootstrap.lua new file mode 100644 index 0000000..9fbaadc --- /dev/null +++ b/snikket-modules/mod_invites_bootstrap/mod_invites_bootstrap.lua @@ -0,0 +1,50 @@ +--luacheck: ignore 143/module + +local http_formdecode = require "net.http".formdecode; + +local secret = module:get_option_string("invites_bootstrap_secret"); +if not secret then return; end + +local invites_bootstrap_store = module:open_store("invites_bootstrap"); +local bootstrap_records = invites_bootstrap_store:get() or {}; + +local index = module:get_option_number("invites_bootstrap_index"); +if #bootstrap_records > 0 and (index or -1) <= bootstrap_records[#bootstrap_records].index then + module:log("debug", "Already bootstrapped for index %d", index or 0); + return; +end + +local invites = module:depends("invites"); +module:depends("http"); + +local function handle_request(event) + local query_params = http_formdecode(event.request.url.query); + + if not query_params.token or query_params.token ~= secret then + return 403; + end + + local invite, err = invites.create_account(nil, { + roles = { ["prosody:admin"] = true }; + source = "api/token/bootstrap"; + }); + if not invite then + module:log("error", "Failed to create bootstrap invite! %s", err); + return 500; + end + + table.insert(bootstrap_records, { + index = index; + timestamp = os.time(); + }); + + event.response.headers.Location = invite.landing_page or invite.uri; + + return 201; +end + +module:provides("http", { + route = { + GET = handle_request; + }; +});