Mercurial > prosody-hg
comparison plugins/mod_invites.lua @ 13738:26a0f653793e 13.0
mod_invites: Deprecate 'mod_invites generate' in favour of new shell commands
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Mon, 17 Feb 2025 19:12:40 +0000 |
| parents | c51140dfbc4e |
| children | 4cf2caa63277 |
comparison
equal
deleted
inserted
replaced
| 13737:46e7cc4de5e6 | 13738:26a0f653793e |
|---|---|
| 242 module:add_item("shell-command", { | 242 module:add_item("shell-command", { |
| 243 section = "invite"; | 243 section = "invite"; |
| 244 section_desc = "Create and manage invitations"; | 244 section_desc = "Create and manage invitations"; |
| 245 name = "create_account"; | 245 name = "create_account"; |
| 246 desc = "Create an invitation to make an account on this server with the specified JID (supply only a hostname to allow any username)"; | 246 desc = "Create an invitation to make an account on this server with the specified JID (supply only a hostname to allow any username)"; |
| 247 args = { | |
| 248 { name = "user_jid", type = "string" }; | |
| 249 }; | |
| 250 host_selector = "user_jid"; | |
| 251 flags = { | |
| 252 array_params = { role = true, group = true }; | |
| 253 value_params = { expires_after = true }; | |
| 254 }; | |
| 255 | |
| 256 handler = function (self, user_jid, opts) --luacheck: ignore 212/self | |
| 257 local username = jid_split(user_jid); | |
| 258 local roles = opts.role or {}; | |
| 259 local groups = opts.group or {}; | |
| 260 | |
| 261 if opts.admin then | |
| 262 -- Insert it first since we don't get order out of argparse | |
| 263 table.insert(roles, 1, "prosody:admin"); | |
| 264 end | |
| 265 | |
| 266 local ttl; | |
| 267 if opts.expires_after then | |
| 268 ttl = human_io.parse_duration(opts.expires_after); | |
| 269 if not ttl then | |
| 270 return false, "Unable to parse duration: "..opts.expires_after; | |
| 271 end | |
| 272 end | |
| 273 | |
| 274 local invite = assert(create_account(username, { | |
| 275 roles = roles; | |
| 276 groups = groups; | |
| 277 }, ttl)); | |
| 278 | |
| 279 return true, invite.landing_page or invite.uri; | |
| 280 end; | |
| 281 }); | |
| 282 | |
| 283 module:add_item("shell-command", { | |
| 284 section = "invite"; | |
| 285 section_desc = "Create and manage invitations"; | |
| 286 name = "create_reset"; | |
| 287 desc = "Create a password reset link for the specified user"; | |
| 247 args = { { name = "user_jid", type = "string" } }; | 288 args = { { name = "user_jid", type = "string" } }; |
| 248 host_selector = "user_jid"; | 289 host_selector = "user_jid"; |
| 249 | 290 flags = { |
| 250 handler = function (self, user_jid) --luacheck: ignore 212/self | 291 value_params = { expires_after = true }; |
| 292 }; | |
| 293 | |
| 294 handler = function (self, user_jid, opts) --luacheck: ignore 212/self | |
| 251 local username = jid_split(user_jid); | 295 local username = jid_split(user_jid); |
| 252 local invite, err = create_account(username); | 296 if not username then |
| 253 if not invite then return nil, err; end | 297 return nil, "Supply the JID of the account you want to generate a password reset for"; |
| 254 return true, invite.landing_page or invite.uri; | 298 end |
| 255 end; | 299 local duration_sec = require "prosody.util.human.io".parse_duration(opts and opts.expires_after or "1d"); |
| 256 }); | 300 if not duration_sec then |
| 257 | 301 return nil, "Unable to parse duration: "..opts.expires_after; |
| 258 module:add_item("shell-command", { | 302 end |
| 259 section = "invite"; | |
| 260 section_desc = "Create and manage invitations"; | |
| 261 name = "create_reset"; | |
| 262 desc = "Create a password reset link for the specified user"; | |
| 263 args = { { name = "user_jid", type = "string" }, { name = "duration", type = "string" } }; | |
| 264 host_selector = "user_jid"; | |
| 265 | |
| 266 handler = function (self, user_jid, duration) --luacheck: ignore 212/self | |
| 267 local username = jid_split(user_jid); | |
| 268 local duration_sec = require "prosody.util.human.io".parse_duration(duration or "1d"); | |
| 269 local invite, err = create_account_reset(username, duration_sec); | 303 local invite, err = create_account_reset(username, duration_sec); |
| 270 if not invite then return nil, err; end | 304 if not invite then return nil, err; end |
| 271 self.session.print(invite.landing_page or invite.uri); | 305 self.session.print(invite.landing_page or invite.uri); |
| 272 return true, ("Password reset link for %s valid until %s"):format(user_jid, os.date("%Y-%m-%d %T", invite.expires)); | 306 return true, ("Password reset link for %s valid until %s"):format(user_jid, os.date("%Y-%m-%d %T", invite.expires)); |
| 273 end; | 307 end; |
| 276 module:add_item("shell-command", { | 310 module:add_item("shell-command", { |
| 277 section = "invite"; | 311 section = "invite"; |
| 278 section_desc = "Create and manage invitations"; | 312 section_desc = "Create and manage invitations"; |
| 279 name = "create_contact"; | 313 name = "create_contact"; |
| 280 desc = "Create an invitation to become contacts with the specified user"; | 314 desc = "Create an invitation to become contacts with the specified user"; |
| 281 args = { { name = "user_jid", type = "string" }, { name = "allow_registration" } }; | 315 args = { { name = "user_jid", type = "string" } }; |
| 282 host_selector = "user_jid"; | 316 host_selector = "user_jid"; |
| 283 | 317 flags = { |
| 284 handler = function (self, user_jid, allow_registration) --luacheck: ignore 212/self | 318 value_params = { expires_after = true }; |
| 319 kv_params = { allow_registration = true }; | |
| 320 }; | |
| 321 | |
| 322 handler = function (self, user_jid, opts) --luacheck: ignore 212/self | |
| 285 local username = jid_split(user_jid); | 323 local username = jid_split(user_jid); |
| 286 local invite, err = create_contact(username, allow_registration); | 324 if not username then |
| 325 return nil, "Supply the JID of the account you want the recipient to become a contact of"; | |
| 326 end | |
| 327 local ttl; | |
| 328 if opts.expires_after then | |
| 329 ttl = require "prosody.util.human.io".parse_duration(opts.expires_after); | |
| 330 if not ttl then | |
| 331 return nil, "Unable to parse duration: "..opts.expires_after; | |
| 332 end | |
| 333 end | |
| 334 local invite, err = create_contact(username, opts.allow_registration, nil, ttl); | |
| 287 if not invite then return nil, err; end | 335 if not invite then return nil, err; end |
| 288 return true, invite.landing_page or invite.uri; | 336 return true, invite.landing_page or invite.uri; |
| 289 end; | 337 end; |
| 290 }); | 338 }); |
| 291 | 339 |
| 440 return 2; | 488 return 2; |
| 441 end | 489 end |
| 442 return subcommands[cmd](arg); | 490 return subcommands[cmd](arg); |
| 443 end | 491 end |
| 444 | 492 |
| 445 function subcommands.generate(arg) | 493 function subcommands.generate() |
| 446 local function help(short) | 494 print("This command is deprecated. Please see 'prosodyctl shell help invite' for available commands."); |
| 447 print("usage: prosodyctl mod_" .. module.name .. " generate DOMAIN --reset USERNAME") | 495 return 1; |
| 448 print("usage: prosodyctl mod_" .. module.name .. " generate DOMAIN [--admin] [--role ROLE] [--group GROUPID]...") | 496 end |
| 449 if short then return 2 end | |
| 450 print() | |
| 451 print("This command has two modes: password reset and new account.") | |
| 452 print("If --reset is given, the command operates in password reset mode and in new account mode otherwise.") | |
| 453 print() | |
| 454 print("required arguments in password reset mode:") | |
| 455 print() | |
| 456 print(" --reset USERNAME Generate a password reset link for the given USERNAME.") | |
| 457 print() | |
| 458 print("optional arguments in new account mode:") | |
| 459 print() | |
| 460 print(" --admin Make the new user privileged") | |
| 461 print(" Equivalent to --role prosody:admin") | |
| 462 print(" --role ROLE Grant the given ROLE to the new user") | |
| 463 print(" --group GROUPID Add the user to the group with the given ID") | |
| 464 print(" Can be specified multiple times") | |
| 465 print(" --expires-after T Time until the invite expires (e.g. '1 week')") | |
| 466 print() | |
| 467 print("--group can be specified multiple times; the user will be added to all groups.") | |
| 468 print() | |
| 469 print("--reset and the other options cannot be mixed.") | |
| 470 return 2 | |
| 471 end | |
| 472 | |
| 473 local earlyopts = argparse.parse(arg, { short_params = { h = "help"; ["?"] = "help" } }); | |
| 474 if earlyopts.help or not earlyopts[1] then | |
| 475 return help(); | |
| 476 end | |
| 477 | |
| 478 local sm = require "prosody.core.storagemanager"; | |
| 479 local mm = require "prosody.core.modulemanager"; | |
| 480 | |
| 481 local host = table.remove(arg, 1); -- pop host | |
| 482 if not host then return help(true) end | |
| 483 sm.initialize_host(host); | |
| 484 module.host = host; --luacheck: ignore 122/module | |
| 485 token_storage = module:open_store("invite_token", "map"); | |
| 486 | |
| 487 local opts = argparse.parse(arg, { | |
| 488 short_params = { h = "help"; ["?"] = "help"; g = "group" }; | |
| 489 value_params = { group = true; reset = true; role = true }; | |
| 490 array_params = { group = true; role = true }; | |
| 491 }); | |
| 492 | |
| 493 if opts.help then | |
| 494 return help(); | |
| 495 end | |
| 496 | |
| 497 -- Load mod_invites | |
| 498 local invites = module:depends("invites"); | |
| 499 -- Optional community module that if used, needs to be loaded here | |
| 500 local invites_page_module = module:get_option_string("invites_page_module", "invites_page"); | |
| 501 if mm.get_modules_for_host(host):contains(invites_page_module) then | |
| 502 module:depends(invites_page_module); | |
| 503 end | |
| 504 | |
| 505 local allow_reset; | |
| 506 | |
| 507 if opts.reset then | |
| 508 local nodeprep = require "prosody.util.encodings".stringprep.nodeprep; | |
| 509 local username = nodeprep(opts.reset) | |
| 510 if not username then | |
| 511 print("Please supply a valid username to generate a reset link for"); | |
| 512 return 2; | |
| 513 end | |
| 514 allow_reset = username; | |
| 515 end | |
| 516 | |
| 517 local roles = opts.role or {}; | |
| 518 local groups = opts.group or {}; | |
| 519 | |
| 520 if opts.admin then | |
| 521 -- Insert it first since we don't get order out of argparse | |
| 522 table.insert(roles, 1, "prosody:admin"); | |
| 523 end | |
| 524 | |
| 525 local invite; | |
| 526 if allow_reset then | |
| 527 if roles[1] then | |
| 528 print("--role/--admin and --reset are mutually exclusive") | |
| 529 return 2; | |
| 530 end | |
| 531 if #groups > 0 then | |
| 532 print("--group and --reset are mutually exclusive") | |
| 533 end | |
| 534 invite = assert(invites.create_account_reset(allow_reset)); | |
| 535 else | |
| 536 invite = assert(invites.create_account(nil, { | |
| 537 roles = roles, | |
| 538 groups = groups | |
| 539 }, opts.expires_after and human_io.parse_duration(opts.expires_after))); | |
| 540 end | |
| 541 | |
| 542 print(invite.landing_page or invite.uri); | |
| 543 end |
