diff --git a/CHANGELOG.md b/CHANGELOG.md index 32873c18f3343d5f230c2e9e73966f9aac7feb4c..3186bebed5b192a8fa51dbae282d13ef7312502b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,17 @@ TBD ### Bug fixes - Fix MFA login failure when the totp `dict`'s attempted codes list changes size while being processed ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/899)) - Resolve additional json being appended to downloaded files ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/902)) +- Fix certain users not showing up following a change made in `4.5.0` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/901)) +- Fix password dialogue closing with no indicator the password did not change when the passwords did not match ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/901)) ### Tweaks +- Remove triple option for validation and use sole robust error ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/901)) +- Allow numeric passwords ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/901)) +- Enable use of `` key for password form submission ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/901)) - Add extended debug logging to help troubleshoot MFA issues ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/898)) - Change upload progress bar to monitor chunk processing ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/896)) ### Lang -TBD +Consolidate "passLength" & "numbericPassword" to single "passProp" translation for validators ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/901)) +

## --- [4.5.4] - 2025/09/15 diff --git a/app/classes/controllers/users_controller.py b/app/classes/controllers/users_controller.py index 64522c97c3865be1a65f2447ddcc3e607edb63b2..77aa25004b98195428e730c21372e6e344711d26 100644 --- a/app/classes/controllers/users_controller.py +++ b/app/classes/controllers/users_controller.py @@ -62,14 +62,10 @@ class UsersController: "password": { "type": "string", "minLength": self.helper.minimum_password_length, - "pattern": "(?=.*[^0-9])", + "pattern": "^.{8,}$", "examples": ["crafty"], "title": "Password", - "error": { - "minLength": "passLength", - "type": "numbericPassword", - "pattern": "numbericPassword", - }, + "error": "passProp", }, "email": { "type": "string", diff --git a/app/classes/web/routes/api/users/index.py b/app/classes/web/routes/api/users/index.py index fc9fcc4fbb00204e685cd392e919b8c56d66e86b..de21cf10f1c29bb9c40c057f9249b4c8499a9f48 100644 --- a/app/classes/web/routes/api/users/index.py +++ b/app/classes/web/routes/api/users/index.py @@ -101,9 +101,14 @@ class ApiUsersIndexHandler(BaseApiHandler): offending_key = "" if why.schema.get("fill", None): offending_key = why.path[0] if why.path else None + schema_error = why.schema.get("error", "additionalProperties") + # We need to get the type of this for additional password property errors + translate_key = schema_error + if isinstance(schema_error, dict): + translate_key = schema_error[why.validator] err = f"""{offending_key} {self.translator.translate( "validators", - why.schema.get("error", "additionalProperties")[why.validator], + translate_key, self.controller.users.get_user_lang_by_id(auth_data[4]["user_id"]), )} {why.schema.get("enum", "")}""" return self.finish_json( diff --git a/app/frontend/static/assets/js/shared/userSettings.js b/app/frontend/static/assets/js/shared/userSettings.js index 841754e91f79c4bbb34355847ea34ae80ba618eb..f4f892cc453d6d3679f15b1e8cce93452c4af417 100644 --- a/app/frontend/static/assets/js/shared/userSettings.js +++ b/app/frontend/static/assets/js/shared/userSettings.js @@ -24,40 +24,58 @@ $(document).on("submit", ".bootbox form", function (e) { $(".edit_password").on("click", async function () { const token = getCookie("_xsrf"); let user_id = $(this).data('id'); - bootbox.confirm(`
\ + bootbox.dialog({ + message: ` +
- -
\ + +
- - \ + +
-
`, async function (result) { - if (result) { - let password = validateForm(); - if (!password) { - return; - } - let res = await fetch(`/api/v2/users/${user_id}`, { - method: 'PATCH', - headers: { - 'X-XSRFToken': token - }, - body: JSON.stringify({ "password": password }), - }); - let responseData = await res.json(); - if (responseData.status === "ok") { - console.log(responseData.data) - } else { + + `, + buttons: { + cancel: { + label: "Cancel", + className: "btn-secondary" + }, + confirm: { + label: "OK", + className: "btn-primary", + callback: function () { + let password = validateForm(); + if (!password) { + return false; + } - bootbox.alert({ - title: responseData.status, - message: responseData.error_data - }); + (async () => { + password = password.toString(); + let res = await fetch(`/api/v2/users/${user_id}`, { + method: 'PATCH', + headers: { 'X-XSRFToken': token }, + body: JSON.stringify({ "password": password }), + }); + let responseData = await res.json(); + + if (responseData.status === "ok") { + console.log(responseData.data); + bootbox.hideAll(); + } else { + bootbox.hideAll(); + bootbox.alert({ + title: responseData.status, + message: responseData.error_data + }); + } + })(); + } } } }); + }); $(".edit_user").on("click", function () { diff --git a/app/frontend/templates/panel/panel_edit_user.html b/app/frontend/templates/panel/panel_edit_user.html index 79feb54ef5e2fe84ee77e2cd28dd98a45befcef0..c8fd09a689eada841f6a93fc4ff537c6a49dd4f2 100644 --- a/app/frontend/templates/panel/panel_edit_user.html +++ b/app/frontend/templates/panel/panel_edit_user.html @@ -410,10 +410,14 @@ data['lang']) }}{% end %} } } function replacer(key, value) { - if (typeof value == "boolean" || key === "email" || key === "permissions" || key === "roles" || key === "password") { + if (typeof value == "boolean" || key === "email" || key === "permissions" || key === "roles") { console.log(key) return value - } else { + } else if (key === "password"){ + value = value.toString() + return value + } + else { console.log(key, value) return (isNaN(value) ? value : +value); } diff --git a/app/frontend/templates/public/login.html b/app/frontend/templates/public/login.html index e11ffb5807614edbc2ed10828b97c023fd61a1aa..ea0f46c27d039806095b202cc81bb7d60d216218 100644 --- a/app/frontend/templates/public/login.html +++ b/app/frontend/templates/public/login.html @@ -182,13 +182,13 @@ let formDataObject = Object.fromEntries(formData.entries()); let body = { "username": formDataObject.username, - "password": formDataObject.password, + "password": (formDataObject.password).toString(), } if (formDataObject.totp != "") { let key = $("#2fa-type").val(); body = { "username": formDataObject.username, - "password": formDataObject.password, + "password": (formDataObject.password).toString(), [key]: formDataObject.totp, } } diff --git a/app/translations/en_EN.json b/app/translations/en_EN.json index b05e457ef1054a2ae786b5ec7b5305ab0739bfeb..3e65cc6029170b839f6daa952e131223ac2feee5 100644 --- a/app/translations/en_EN.json +++ b/app/translations/en_EN.json @@ -763,8 +763,7 @@ "filesPageLen": "length must be greater than 1 for property", "insufficientPerms": "Permission Error: Missing permissions for this resource", "mfaName": "Input must be of type string and a minimum of 3 characters for property", - "passLength": "Password Too Short. Minimum Length: 8", - "numbericPassword": "Numeric Password. Needs at least 1 alphabetic character", + "passProp": "Password must be a string with a min length of 8 characters.", "roleManager": "Role manager must be of type integer (manager ID) or None", "roleName": "Role name must be a string that is greater than 1 character. It must not include any of the following symbols: [ ] , ", "roleServerId": "Server ID property must be a string with a minimum length of 1",