From 4008155abdc1cb610c8732caec14b9a0d51f58b7 Mon Sep 17 00:00:00 2001 From: treamz Date: Sat, 21 Mar 2026 23:56:42 +0300 Subject: [PATCH] Admin: password confirmation field + validation - Added password_confirm field in user edit/new forms - Validation: passwords must match, min 6 chars - New user: password required - Edit user: password optional (leave empty to keep) --- lib/admin.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/admin.js b/lib/admin.js index 0949368..1437ca0 100644 --- a/lib/admin.js +++ b/lib/admin.js @@ -101,7 +101,7 @@ async function setupAdmin(app) { options: { navigation: { name: 'Пользователи', icon: 'User' }, listProperties: ['id', 'email', 'display_name', 'role', 'is_blocked', 'last_login'], - editProperties: ['email', 'display_name', 'role', 'is_blocked', 'password'], + editProperties: ['email', 'display_name', 'role', 'is_blocked', 'password', 'password_confirm'], showProperties: ['id', 'email', 'display_name', 'role', 'is_blocked', 'created_at', 'last_login'], properties: { password_hash: { isVisible: false }, @@ -110,26 +110,40 @@ async function setupAdmin(app) { isVisible: { list: false, show: false, edit: true, filter: false }, description: 'Оставьте пустым чтобы не менять', }, + password_confirm: { + type: 'password', + isVisible: { list: false, show: false, edit: true, filter: false }, + description: 'Повторите пароль', + }, role: { availableValues: [{ value: 'user', label: 'User' }, { value: 'admin', label: 'Admin' }] }, }, actions: { edit: { before: async (request) => { - if (request.payload && request.payload.password && request.payload.password.trim()) { + const pw = request.payload?.password?.trim(); + const pw2 = request.payload?.password_confirm?.trim(); + if (pw) { + if (pw !== pw2) throw new Error('Пароли не совпадают'); + if (pw.length < 6) throw new Error('Пароль минимум 6 символов'); const bcrypt = require('bcrypt'); - request.payload.password_hash = await bcrypt.hash(request.payload.password, 10); + request.payload.password_hash = await bcrypt.hash(pw, 10); } delete request.payload.password; + delete request.payload.password_confirm; return request; }, }, new: { before: async (request) => { - if (request.payload && request.payload.password && request.payload.password.trim()) { - const bcrypt = require('bcrypt'); - request.payload.password_hash = await bcrypt.hash(request.payload.password, 10); - } + const pw = request.payload?.password?.trim(); + const pw2 = request.payload?.password_confirm?.trim(); + if (!pw) throw new Error('Пароль обязателен'); + if (pw !== pw2) throw new Error('Пароли не совпадают'); + if (pw.length < 6) throw new Error('Пароль минимум 6 символов'); + const bcrypt = require('bcrypt'); + request.payload.password_hash = await bcrypt.hash(pw, 10); delete request.payload.password; + delete request.payload.password_confirm; return request; }, },