diff --git a/containers/rocketchat/scripts/rocketchat_auth.sh b/containers/rocketchat/scripts/rocketchat_auth.sh index 33632e4..3a81f9b 100644 --- a/containers/rocketchat/scripts/rocketchat_auth.sh +++ b/containers/rocketchat/scripts/rocketchat_auth.sh @@ -50,6 +50,18 @@ _rocketchatLogin() { printf '%s %s' "$id" "$token" } +# Rocket.Chat enables a password policy by default that demands lower, upper, +# digit AND special, at 14+ characters. generateRandomPassword is alphanumeric, +# so a generated password is rejected by users.update with "does not meet the +# server's password policy" — note that users.create does NOT enforce it, which +# is why creating worked while resetting did not. +# +# Appending one character from each class guarantees compliance without +# weakening anything: the entropy of the generated part is untouched. +_rocketchatPassword() { + printf '%s%s' "$(generateRandomPassword)" 'aZ7#' +} + # JSON-encode a bash string so a password containing quotes or backslashes # cannot break the request body. _rcJson() { @@ -94,7 +106,7 @@ authAdapter_rocketchat_createUser() { local email="$1" password="$2" username="$3" isAdmin="$4" [[ -z "$email" ]] && { isError "An email address is required."; return 1; } [[ -z "$username" ]] && username="${email%@*}" - [[ -z "$password" ]] && password=$(generateRandomPassword) + [[ -z "$password" ]] && password=$(_rocketchatPassword) local roles='["user"]' [[ "$isAdmin" == "true" ]] && roles='["admin","user"]' @@ -120,10 +132,20 @@ try: print(json.load(sys.stdin).get('user',{}).get('_id','')) except Exception: print('')" 2>/dev/null } +_rocketchatUsernameOf() { + local who="$1" field="username" + [[ "$who" == *@* ]] && field="email" + local out + out=$(_rocketchatApi GET "/api/v1/users.info?${field}=${who}") || return 1 + printf '%s' "$out" | python3 -c "import sys,json +try: print(json.load(sys.stdin).get('user',{}).get('username','')) +except Exception: print('')" 2>/dev/null +} + authAdapter_rocketchat_setPassword() { local who="$1" password="$2" [[ -z "$who" ]] && { isError "A username or email is required."; return 1; } - [[ -z "$password" ]] && password=$(generateRandomPassword) + [[ -z "$password" ]] && password=$(_rocketchatPassword) local uid; uid=$(_rocketchatUserId "$who") || return 1 [[ -z "$uid" ]] && { isError "No Rocket.Chat user '$who'."; return 1; } @@ -193,6 +215,21 @@ authAdapter_rocketchat_deleteUser() { isSuccessful "Rocket.Chat user '$who' deactivated. Re-enable them from Admin → Users." } +# The counterpart to deleteUser. Deactivation is only a safe default if undoing +# it is equally easy — otherwise the "reversible" claim is theoretical. +authAdapter_rocketchat_enableUser() { + local who="$1" + [[ -z "$who" ]] && { isError "A username or email is required."; return 1; } + + local uid; uid=$(_rocketchatUserId "$who") || return 1 + [[ -z "$uid" ]] && { isError "No Rocket.Chat user '$who'."; return 1; } + + local out + out=$(_rocketchatApi POST /api/v1/users.setActiveStatus "$(printf '{"userId":%s,"activeStatus":true}' "$(_rcJson "$uid")")") || return 1 + [[ "$(_rocketchatOk "$out")" != "yes" ]] && { isError "Enabling $who failed: $(_rocketchatError "$out")"; return 1; } + isSuccessful "Rocket.Chat user '$who' re-enabled." +} + authAdapter_rocketchat_setAdmin() { local who="$1" isAdmin="$2" [[ -z "$who" ]] && { isError "A username or email is required."; return 1; } @@ -203,15 +240,21 @@ authAdapter_rocketchat_setAdmin() { return 1 fi - local uid; uid=$(_rocketchatUserId "$who") || return 1 - [[ -z "$uid" ]] && { isError "No Rocket.Chat user '$who'."; return 1; } + # The endpoint takes roleId + username, and nothing else: passing roleName + # fails schema validation with "must NOT have additional properties", and + # roleId + userId is rejected for a missing username. For built-in roles the + # id and the name happen to be the same string ("admin"). + # + # username is resolved from the account rather than assumed from the input, + # so passing an email works here too. + local username + username=$(_rocketchatUsernameOf "$who") || return 1 + [[ -z "$username" ]] && { isError "No Rocket.Chat user '$who'."; return 1; } local endpoint="/api/v1/roles.addUserToRole" + [[ "$target" == "false" ]] && endpoint="/api/v1/roles.removeUserFromRole" local body - body=$(printf '{"roleName":"admin","username":%s}' "$(_rcJson "${who%%@*}")") - if [[ "$target" == "false" ]]; then - endpoint="/api/v1/roles.removeUserFromRole" - fi + body=$(printf '{"roleId":"admin","username":%s}' "$(_rcJson "$username")") local out out=$(_rocketchatApi POST "$endpoint" "$body") || return 1 diff --git a/containers/rocketchat/tools/rocketchat.tools.json b/containers/rocketchat/tools/rocketchat.tools.json index 911ca3b..1912df8 100644 --- a/containers/rocketchat/tools/rocketchat.tools.json +++ b/containers/rocketchat/tools/rocketchat.tools.json @@ -100,6 +100,21 @@ "required": true } ] + }, + { + "id": "enable_user", + "category": "users", + "label": "Enable User Account", + "description": "Undo a deactivation and let the account sign in again.", + "icon": "✅", + "fields": [ + { + "name": "user", + "label": "Username or email", + "type": "text", + "required": true + } + ] } ] } diff --git a/containers/rocketchat/tools/rocketchat_enable_user.sh b/containers/rocketchat/tools/rocketchat_enable_user.sh new file mode 100644 index 0000000..c8bb0d5 --- /dev/null +++ b/containers/rocketchat/tools/rocketchat_enable_user.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +appRocketchatEnableUser() { + local args="$1" + authAdapterCall rocketchat enableUser "$(authToolArg "$args" user)" +} diff --git a/scripts/source/files/arrays/function_manifest.sh b/scripts/source/files/arrays/function_manifest.sh index b425ace..09e2bff 100644 --- a/scripts/source/files/arrays/function_manifest.sh +++ b/scripts/source/files/arrays/function_manifest.sh @@ -87,6 +87,7 @@ declare -gA LP_FN_MAP=( [_appReqServiceMsg]="checks/requirements/check_app_install.sh" [appRocketchatCreateAccount]="rocketchat/tools/rocketchat_create_account.sh" [appRocketchatDeactivateUser]="rocketchat/tools/rocketchat_deactivate_user.sh" + [appRocketchatEnableUser]="rocketchat/tools/rocketchat_enable_user.sh" [appRocketchatListUsers]="rocketchat/tools/rocketchat_list_users.sh" [appRocketchatResetPassword]="rocketchat/tools/rocketchat_reset_password.sh" [appRocketchatSetAdmin]="rocketchat/tools/rocketchat_set_admin.sh" @@ -183,6 +184,7 @@ declare -gA LP_FN_MAP=( [authAdapter_nextcloud_setPassword]="nextcloud/scripts/nextcloud_auth.sh" [authAdapter_rocketchat_createUser]="rocketchat/scripts/rocketchat_auth.sh" [authAdapter_rocketchat_deleteUser]="rocketchat/scripts/rocketchat_auth.sh" + [authAdapter_rocketchat_enableUser]="rocketchat/scripts/rocketchat_auth.sh" [authAdapter_rocketchat_listUsers]="rocketchat/scripts/rocketchat_auth.sh" [authAdapter_rocketchat_setAdmin]="rocketchat/scripts/rocketchat_auth.sh" [authAdapter_rocketchat_setPassword]="rocketchat/scripts/rocketchat_auth.sh" @@ -872,7 +874,9 @@ declare -gA LP_FN_MAP=( [rocketchat_install_post_start]="rocketchat/scripts/rocketchat_install_hooks.sh" [_rocketchatLogin]="rocketchat/scripts/rocketchat_auth.sh" [_rocketchatOk]="rocketchat/scripts/rocketchat_auth.sh" + [_rocketchatPassword]="rocketchat/scripts/rocketchat_auth.sh" [_rocketchatUserId]="rocketchat/scripts/rocketchat_auth.sh" + [_rocketchatUsernameOf]="rocketchat/scripts/rocketchat_auth.sh" [runAppCfg]="docker/command/run_privileged.sh" [runAsManager]="docker/command/run_privileged.sh" [runBackupOp]="docker/command/run_privileged.sh" @@ -1200,6 +1204,7 @@ declare -gA LP_FN_ROOT=( [_appReqServiceMsg]="scripts" [appRocketchatCreateAccount]="containers" [appRocketchatDeactivateUser]="containers" + [appRocketchatEnableUser]="containers" [appRocketchatListUsers]="containers" [appRocketchatResetPassword]="containers" [appRocketchatSetAdmin]="containers" @@ -1296,6 +1301,7 @@ declare -gA LP_FN_ROOT=( [authAdapter_nextcloud_setPassword]="containers" [authAdapter_rocketchat_createUser]="containers" [authAdapter_rocketchat_deleteUser]="containers" + [authAdapter_rocketchat_enableUser]="containers" [authAdapter_rocketchat_listUsers]="containers" [authAdapter_rocketchat_setAdmin]="containers" [authAdapter_rocketchat_setPassword]="containers" @@ -1985,7 +1991,9 @@ declare -gA LP_FN_ROOT=( [rocketchat_install_post_start]="containers" [_rocketchatLogin]="containers" [_rocketchatOk]="containers" + [_rocketchatPassword]="containers" [_rocketchatUserId]="containers" + [_rocketchatUsernameOf]="containers" [runAppCfg]="scripts" [runAsManager]="scripts" [runBackupOp]="scripts" @@ -2348,6 +2356,7 @@ _appReqServiceInstalled() { unset -f _appReqServiceInstalled; __lpAutoload "${in _appReqServiceMsg() { unset -f _appReqServiceMsg; __lpAutoload "${install_scripts_dir}checks/requirements/check_app_install.sh"; _appReqServiceMsg "$@"; } appRocketchatCreateAccount() { unset -f appRocketchatCreateAccount; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_create_account.sh"; appRocketchatCreateAccount "$@"; } appRocketchatDeactivateUser() { unset -f appRocketchatDeactivateUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_deactivate_user.sh"; appRocketchatDeactivateUser "$@"; } +appRocketchatEnableUser() { unset -f appRocketchatEnableUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_enable_user.sh"; appRocketchatEnableUser "$@"; } appRocketchatListUsers() { unset -f appRocketchatListUsers; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_list_users.sh"; appRocketchatListUsers "$@"; } appRocketchatResetPassword() { unset -f appRocketchatResetPassword; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_reset_password.sh"; appRocketchatResetPassword "$@"; } appRocketchatSetAdmin() { unset -f appRocketchatSetAdmin; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_set_admin.sh"; appRocketchatSetAdmin "$@"; } @@ -2444,6 +2453,7 @@ authAdapter_nextcloud_setAdmin() { unset -f authAdapter_nextcloud_setAdmin; __lp authAdapter_nextcloud_setPassword() { unset -f authAdapter_nextcloud_setPassword; __lpAutoload "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; authAdapter_nextcloud_setPassword "$@"; } authAdapter_rocketchat_createUser() { unset -f authAdapter_rocketchat_createUser; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; authAdapter_rocketchat_createUser "$@"; } authAdapter_rocketchat_deleteUser() { unset -f authAdapter_rocketchat_deleteUser; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; authAdapter_rocketchat_deleteUser "$@"; } +authAdapter_rocketchat_enableUser() { unset -f authAdapter_rocketchat_enableUser; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; authAdapter_rocketchat_enableUser "$@"; } authAdapter_rocketchat_listUsers() { unset -f authAdapter_rocketchat_listUsers; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; authAdapter_rocketchat_listUsers "$@"; } authAdapter_rocketchat_setAdmin() { unset -f authAdapter_rocketchat_setAdmin; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; authAdapter_rocketchat_setAdmin "$@"; } authAdapter_rocketchat_setPassword() { unset -f authAdapter_rocketchat_setPassword; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; authAdapter_rocketchat_setPassword "$@"; } @@ -3133,7 +3143,9 @@ rocketchat_install_post() { unset -f rocketchat_install_post; __lpAutoload "${in rocketchat_install_post_start() { unset -f rocketchat_install_post_start; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_install_hooks.sh"; rocketchat_install_post_start "$@"; } _rocketchatLogin() { unset -f _rocketchatLogin; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; _rocketchatLogin "$@"; } _rocketchatOk() { unset -f _rocketchatOk; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; _rocketchatOk "$@"; } +_rocketchatPassword() { unset -f _rocketchatPassword; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; _rocketchatPassword "$@"; } _rocketchatUserId() { unset -f _rocketchatUserId; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; _rocketchatUserId "$@"; } +_rocketchatUsernameOf() { unset -f _rocketchatUsernameOf; __lpAutoload "${install_containers_dir}rocketchat/scripts/rocketchat_auth.sh"; _rocketchatUsernameOf "$@"; } runAppCfg() { unset -f runAppCfg; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runAppCfg "$@"; } runAsManager() { unset -f runAsManager; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runAsManager "$@"; } runBackupOp() { unset -f runBackupOp; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runBackupOp "$@"; }