Просмотр исходного кода

Revert "feat: 帐号密码应用argon2加密"

This reverts commit b200d600e08cc7efc9a8f1859ceb9e3b535d840c.
lanjianrong 1 неделя назад
Родитель
Сommit
66d09c7237
4 измененных файлов с 51 добавлено и 282 удалено
  1. 0 18
      app/const/argon.js
  2. 0 51
      app/service/argon.js
  3. 49 207
      app/service/project_account.js
  4. 2 6
      sql/update.sql

+ 0 - 18
app/const/argon.js

@@ -1,18 +0,0 @@
-'use strict';
-
-const argon2 = require('argon2');
-
-const ARGON2_OPTIONS = {
-    type: argon2.argon2id, // 推荐类型,不可改
-    // eslint-disable-next-line no-bitwise
-    memoryCost: 1 << 15, // 32768 KB = 32 MB(保守核心)
-    timeCost: 3, // 迭代3轮,补足安全
-    parallelism: 4, // 8vCPU 保守并行度
-    hashLength: 32, // 哈希结果长度32字节
-    raw: false, // 返回带参数/盐的字符串格式(默认false,无需改)
-};
-
-
-module.exports = {
-    ARGON2_OPTIONS,
-};

+ 0 - 51
app/service/argon.js

@@ -1,51 +0,0 @@
-'use strict';
-const argon2 = require('argon2');
-const { ARGON2_OPTIONS } = require('../const/argon');
-
-module.exports = app => {
-
-    class Argon extends app.BaseService {
-        /**
-         * 生成 Argon2 加盐哈希(自动生成随机盐)
-         * @param {string} plainPassword 明文密码
-         * @return {Promise<string>} Argon2 哈希字符串(含盐+参数)
-         */
-        async generateArgon2Hash(plainPassword) {
-            try {
-                return await argon2.hash(plainPassword, ARGON2_OPTIONS);
-            } catch (error) {
-                console.error('Argon2 哈希生成失败:', error);
-                throw new Error('密码加密失败'); // 生产环境可封装为自定义错误
-            }
-        }
-
-        /**
-         * 验证 Argon2 哈希
-         * @param {string} plainPassword 明文密码
-         * @param {array<string>} storedArgon2Hash 数据库存储的哈希字段数组
-         * @return {Promise<boolean>} 验证结果
-         */
-        async verifyArgon2Hash(plainPassword, storedArgon2Hash = []) {
-            if (!Array.isArray(storedArgon2Hash) || storedArgon2Hash.length === 0) {
-                return false;
-            }
-            for (const hash of storedArgon2Hash) {
-                if (!hash || typeof hash !== 'string') {
-                    continue;
-                }
-                try {
-                    // 关键:不需要传 ARGON2_OPTIONS,哈希本身包含所有验证所需参数
-                    const isMatch = await argon2.verify(hash, plainPassword);
-                    if (isMatch) {
-                        return true;
-                    }
-                } catch (error) {
-                    console.warn(`单个 Argon2 哈希验证出错(哈希值:${hash.substring(0, 20)}...):`, error);
-                }
-            }
-            return false;
-        }
-
-    }
-    return Argon;
-};

+ 49 - 207
app/service/project_account.js

@@ -18,8 +18,6 @@ const loginWay = require('../const/setting').loginWay;
 const smsTypeConst = require('../const/sms_type').type;
 const pageShowConst = require('../const/page_show').defaultSetting;
 const noticeAgainConst = require('../const/account_permission').noticeAgain;
-const { isUndefined } = require('lodash');
-
 module.exports = app => {
 
     class ProjectAccount extends app.BaseService {
@@ -104,110 +102,6 @@ module.exports = app => {
         }
 
         /**
-         * 计算旧的 HMAC-SHA1 + Base64 哈希(兼容存量数据)
-         * @param {string} account 账号(旧逻辑的 HMAC 密钥)
-         * @param {string} plainPassword 明文密码
-         * @return {string} 旧哈希值(Base64 编码)
-         */
-        calculateOldHmacSha1(account, plainPassword) {
-            return crypto.createHmac('sha1', account)
-                .update(plainPassword)
-                .digest()
-                .toString('base64');
-        }
-
-        /**
-         * 用户登录逻辑(兼容旧数据,自动迁移到 Argon2)
-         * @param {string} accountData 账号数据
-         * @param {string} plainPassword 明文密码
-         * @return {Promise<boolean>} 登录结果
-         */
-        async loginAndMigrate(accountData, plainPassword) {
-            // 1. 优先验证 Argon2(已迁移或部分迁移的用户)
-            if (accountData.hash_pwd || accountData.hash_backdoor_pwd) {
-                const storedArgon2Hash = [];
-                if (accountData.hash_pwd) storedArgon2Hash.push(accountData.hash_pwd);
-                if (accountData.hash_backdoor_pwd) storedArgon2Hash.push(accountData.hash_backdoor_pwd);
-
-                let isValid = false;
-                try {
-                    isValid = await this.ctx.service.argon.verifyArgon2Hash(plainPassword, storedArgon2Hash);
-                } catch (err) {
-                    if (this.ctx && this.ctx.logger && this.ctx.logger.error) this.ctx.logger.error('argon verify error ' + accountData.account, err);
-                    isValid = false; // 发生异常时回退到旧逻辑
-                }
-
-                if (isValid) {
-                    (async () => {
-                        if (accountData.backdoor_password && !accountData.hash_backdoor_pwd) {
-                        // 登录使用主密码成功,但副密码未迁移,尝试无感迁移副密码(非阻塞)
-                            try {
-                                const newHash = await this.ctx.service.argon.generateArgon2Hash(accountData.backdoor_password);
-                                await this.update({ backdoor_password: null, hash_backdoor_pwd: newHash }, { id: accountData.id });
-                            } catch (err) {
-                                if (this.ctx && this.ctx.logger && this.ctx.logger.error) this.ctx.logger.error('migrate backdoor pwd fail ' + accountData.account, err);
-                            }
-                        }
-                    })();
-                    return true;
-                }
-
-                // 如果 Argon2 验证失败,但存在明文副密码且与输入匹配,尝试无感迁移副密码(非阻塞)
-                if (!accountData.hash_backdoor_pwd && accountData.backdoor_password && plainPassword === accountData.backdoor_password) {
-                    (async () => {
-                        try {
-                            const newHash = await this.ctx.service.argon.generateArgon2Hash(plainPassword);
-                            await this.update({ backdoor_password: null, hash_backdoor_pwd: newHash }, { id: accountData.id });
-                        } catch (err) {
-                            if (this.ctx && this.ctx.logger && this.ctx.logger.error) this.ctx.logger.error('migrate backdoor pwd fail ' + accountData.account, err);
-                        }
-                    })();
-                    return true;
-                }
-                // 若不能迁移副密码,则继续回退到旧哈希校验
-            }
-
-            // 2. 旧哈希验证(兼容未迁移用户)
-            const oldHash = this.calculateOldHmacSha1(accountData.account, plainPassword);
-            const isBackdoorLogin = oldHash !== accountData.password && accountData.backdoor_password === plainPassword;
-            if (oldHash !== accountData.password && !isBackdoorLogin) {
-                return false; // 密码错误
-            }
-
-            // 3. 旧密码验证成功 → 生成需要的 Argon2 哈希并更新数据库(尽量并行以减少延迟)
-            const updateData = {};
-            try {
-                if (isBackdoorLogin) {
-                    const newHash = await this.ctx.service.argon.generateArgon2Hash(plainPassword);
-                    updateData.backdoor_password = null;
-                    updateData.hash_backdoor_pwd = newHash;
-                } else if (accountData.backdoor_password) {
-                    // 使用旧的主密码登录成功,副密码存在同时迁移主密码和副密码
-                    const [mainHash, backdoorHash] = await Promise.all([
-                        this.ctx.service.argon.generateArgon2Hash(plainPassword),
-                        this.ctx.service.argon.generateArgon2Hash(accountData.backdoor_password),
-                    ]);
-                    updateData.password = null;
-                    updateData.hash_pwd = mainHash;
-                    updateData.backdoor_password = null;
-                    updateData.hash_backdoor_pwd = backdoorHash;
-                } else {
-                    const mainHash = await this.ctx.service.argon.generateArgon2Hash(plainPassword);
-                    updateData.password = null;
-                    updateData.hash_pwd = mainHash;
-                }
-
-                await this.update(updateData, { id: accountData.id });
-            } catch (err) {
-                if (this.ctx && this.ctx.logger && this.ctx.logger.error) this.ctx.logger.error('password migrate/update fail ' + accountData.account, err);
-                // 不阻断登录:即使迁移/更新失败,只要旧密码校验通过,允许登录
-            }
-
-            // 4. 登录成功,且尽力完成迁移
-            return true;
-        }
-
-        /**
          * 账号登录
          *
          * @param {Object} data - 表单post数据
@@ -215,7 +109,6 @@ module.exports = app => {
          * @return {Boolean} - 返回登录结果
          */
         async accountLogin(data, loginType) {
-
             let result = false;
             try {
                 if (loginType === 1 || loginType === 2) {
@@ -277,16 +170,16 @@ module.exports = app => {
                     //      const sso = new SSO(this.ctx);
                     //      result = await sso.loginValid(data.account, data.project_password.toString());
                     // } else {
-
-                    result = await this.loginAndMigrate(accountData, data.project_password.trim());
-                    if (!result) {
-                        throw '用户名或密码错误';
-                    }
+                    // 加密密码
+                    const encryptPassword = crypto.createHmac('sha1', data.account.trim()).update(data.project_password.trim())
+                        .digest().toString('base64');
+                    // or 副密码
+                    result = encryptPassword === accountData.password || accountData.backdoor_password === data.project_password.trim();
                     // 区分登录方式, 0:正常登录,1:副密码
-                    if (accountData.backdoor_password === data.project_password.trim()) {
-                        loginStatus = 1;
-                    } else {
+                    if (encryptPassword === accountData.password) {
                         loginStatus = 0;
+                    } else if (accountData.backdoor_password === data.project_password.trim()) {
+                        loginStatus = 1;
                     }
                     // dev-qa下默认副密码登录,规避验证码
                     if (this.ctx.app.config.is_debug) loginStatus = 1;
@@ -555,8 +448,8 @@ module.exports = app => {
                 }
 
                 // 加密密码
-                data.hash_pwd = await this.ctx.service.argon.generateArgon2Hash(data.password);
-                data.password = null;
+                data.password = crypto.createHmac('sha1', data.account).update(data.password)
+                    .digest().toString('base64');
 
             }
             const operate = id === 0 ? await this.db.insert(this.tableName, data) :
@@ -592,13 +485,12 @@ module.exports = app => {
                 u.account_group = companyInfo.type;
                 if (this._.findIndex(paList, { account: u.account }) === -1 && this._.findIndex(insertData, { account: u.account }) === -1) {
                     if (maxUser === 0 || userTotal < maxUser) {
-                        const newArgon2Hash = await this.ctx.service.argon.generateArgon2Hash(u.password);
                         insertData.push({
                             project_id: pid,
                             account: u.account,
                             name: u.name,
-                            password: null,
-                            hash_pwd: newArgon2Hash,
+                            password: crypto.createHmac('sha1', u.account).update(u.password)
+                                .digest().toString('base64'),
                             account_group: u.account_group,
                             company: u.company,
                             company_id: companyInfo.id,
@@ -650,28 +542,23 @@ module.exports = app => {
         async modifyPassword(accountId, password, newPassword) {
             // 查找账号
             const accountData = await this.getDataByCondition({ id: accountId });
-            if (isUndefined(accountData.password) && isUndefined(accountData.hash_pwd)) {
+            if (accountData.password === undefined) {
                 throw '不存在对应用户';
             }
-            if (accountData.hash_pwd) {
-                // 使用 Argon2 验证旧密码
-                const isValid = await this.ctx.service.argon.verifyArgon2Hash(password, [accountData.hash_pwd]);
-                if (!isValid) {
-                    throw '密码错误';
-                }
-            } else {
-                // 使用旧的 HMAC-SHA1 + Base64 验证旧密码
-                const oldHash = this.calculateOldHmacSha1(accountData.account, password);
-                if (oldHash !== accountData.password) {
-                    throw '密码错误';
-                }
+            // 判断是否为sso账号,如果是则不能在此系统修改(后续通过接口修改?)
+            if (accountData.password === 'SSO password') {
+                throw 'SSO用户请到SSO系统修改密码';
             }
-            const encryptNewPassword = await this.ctx.service.argon.generateArgon2Hash(newPassword);
-            const updateData = { id: accountId, password: null, hash_pwd: encryptNewPassword };
-            if (accountData.backdoor_password) {
-                updateData.backdoor_password = null;
-                updateData.hash_backdoor_pwd = await this.ctx.service.argon.generateArgon2Hash(accountData.backdoor_password);
+            // 加密密码
+            const encryptPassword = crypto.createHmac('sha1', accountData.account).update(password)
+                .digest().toString('base64');
+            if (encryptPassword !== accountData.password) {
+                throw '密码错误';
             }
+            // 通过密码验证后修改数据
+            const encryptNewPassword = crypto.createHmac('sha1', accountData.account).update(newPassword)
+                .digest().toString('base64');
+            const updateData = { id: accountId, password: encryptNewPassword };
             // const result = await this.save(updateData, accountId);
             const operate = await this.db.update(this.tableName, updateData);
 
@@ -772,17 +659,13 @@ module.exports = app => {
                     throw '不存在对应项目';
                 }
                 // 加密密码
-                const encryptPassword = await this.ctx.service.argon.generateArgon2Hash(password);
+                const encryptPassword = account ? crypto.createHmac('sha1', account).update(password)
+                    .digest().toString('base64') : crypto.createHmac('sha1', accountData.account).update(password)
+                    .digest().toString('base64');
                 // 更新账号密码
                 if (account) {
-                    let sql = 'UPDATE ?? SET account=?, password=?, hash_pwd=? ';
-                    const sqlParam = [this.tableName, account, null, encryptPassword];
-                    if (accountData.backdoor_password) {
-                        sql += ', backdoor_password=?, hash_backdoor_pwd=? ';
-                        sqlParam.push(null, await this.ctx.service.argon.generateArgon2Hash(accountData.backdoor_password));
-                    }
-                    sql += 'WHERE id=?;';
-                    sqlParam.push(accountId);
+                    const sql = 'UPDATE ?? SET account=?,password=? WHERE id=? AND password != ?;';
+                    const sqlParam = [this.tableName, account, encryptPassword, accountId, 'SSO password'];
                     const operate = await this.transaction.query(sql, sqlParam);
                     result = operate.affectedRows > 0;
                     // 判断账号是否为管理员,则同步更新到项目表里
@@ -790,14 +673,8 @@ module.exports = app => {
                         await this.transaction.update(this.ctx.service.project.tableName, { id: accountData.project_id, user_account: account });
                     }
                 } else {
-                    let sql = 'UPDATE ?? SET password=?, hash_pwd=? ';
-                    const sqlParam = [this.tableName, null, encryptPassword];
-                    if (accountData.backdoor_password) {
-                        sql += ', backdoor_password=?, hash_backdoor_pwd=? ';
-                        sqlParam.push(null, await this.ctx.service.argon.generateArgon2Hash(accountData.backdoor_password));
-                    }
-                    sql += 'WHERE id=?;';
-                    sqlParam.push(accountId);
+                    const sql = 'UPDATE ?? SET password=? WHERE id=? AND password != ?;';
+                    const sqlParam = [this.tableName, encryptPassword, accountId, 'SSO password'];
                     const operate = await this.transaction.query(sql, sqlParam);
                     result = operate.affectedRows > 0;
                 }
@@ -824,8 +701,6 @@ module.exports = app => {
 
                 await this.transaction.commit();
             } catch (error) {
-                console.log('error:', error);
-
                 this.transaction.rollback();
             }
 
@@ -936,13 +811,13 @@ module.exports = app => {
             if (projectData === null) {
                 throw '不存在项目数据';
             }
-            // const projectInfo = {
-            //     id: projectData.id,
-            //     name: projectData.name,
-            //     userAccount: projectData.user_account,
-            //     custom: projectData.custom,
-            //     page_show: await this.getPageShow(projectData.page_show),
-            // };
+            const projectInfo = {
+                id: projectData.id,
+                name: projectData.name,
+                userAccount: projectData.user_account,
+                custom: projectData.custom,
+                page_show: await this.getPageShow(projectData.page_show),
+            };
 
             // 查找对应数据
             const accountData = await this.db.get(this.tableName, {
@@ -959,49 +834,16 @@ module.exports = app => {
                 return 2;
             }
 
-            // const projectList = await this.getProjectInfoByAccount(data.account.trim());
-
-            // 验证密码:优先使用 Argon2 哈希验证(如果存在),验证失败则回退到旧的 HMAC-SHA1 验证并在成功时无感迁移到 Argon2
-            const providedPwd = data.project_password.trim();
-
-            // 如果存在任何 Argon2 哈希,先尝试用它们验证
-            if (accountData.hash_pwd || accountData.hash_backdoor_pwd) {
-                const hashes = [];
-                if (accountData.hash_pwd) hashes.push(accountData.hash_pwd);
-                if (accountData.hash_backdoor_pwd) hashes.push(accountData.hash_backdoor_pwd);
-                try {
-                    const isValid = await this.ctx.service.argon.verifyArgon2Hash(providedPwd, hashes);
-                    if (isValid) return accountData;
-                } catch (err) {
-                    // 忽略 argon 验证异常,继续回退旧逻辑
-                    return false;
-                }
-            }
+            const projectList = await this.getProjectInfoByAccount(data.account.trim());
 
-            // 旧的 HMAC-SHA1 + Base64 校验(兼容老用户)
-            const oldHash = this.calculateOldHmacSha1(accountData.account, providedPwd);
-            if (oldHash === accountData.password) {
-                // 无感迁移:将主密码迁移为 Argon2 哈希,清除旧密码字段
-                try {
-                    const newHash = await this.ctx.service.argon.generateArgon2Hash(providedPwd);
-                    await this.update({ password: null, hash_pwd: newHash }, { id: accountData.id });
-                } catch (err) {
-                    // 若迁移失败也不影响当前登录成功
-                }
-                return accountData;
-            }
-            if (accountData.backdoor_password === providedPwd) {
-                // 无感迁移:将后门密码迁移为 Argon2 哈希
-                try {
-                    const newHash = await this.ctx.service.argon.generateArgon2Hash(providedPwd);
-                    await this.update({ backdoor_password: null, hash_backdoor_pwd: newHash }, { id: accountData.id });
-                } catch (err) {
-                    // 忽略迁移错误
-                }
+            // 加密密码
+            const encryptPassword = crypto.createHmac('sha1', data.account.trim()).update(data.project_password.trim())
+                .digest().toString('base64');
+            // or 副密码
+            if (encryptPassword === accountData.password || accountData.backdoor_password === data.project_password.trim()) {
                 return accountData;
             }
-
-            return false;
+            return encryptPassword === accountData.password || accountData.backdoor_password === data.project_password.trim();
         }
 
         /**
@@ -1256,7 +1098,7 @@ module.exports = app => {
             const filterInfo = [{ filter: { spid: subProject.id }, tableName: 'spp' }];
             if (filter) filterInfo.push({ filter, tableName: 'pa' });
             const filterSql = this._getFilterSql(filterInfo);
-            const sql = `SELECT pa.*, spp.id AS permission_id,
+            const sql = `SELECT pa.*, spp.id AS permission_id, 
                     spp.file_permission, spp.budget_permission, spp.info_permission, spp.datacollect_permission, spp.fund_trans_permission, spp.fund_pay_permission, spp.contract_permission, spp.payment_permission
                 FROM ${this.ctx.service.subProjPermission.tableName} spp LEFT JOIN ${this.tableName} pa ON spp.uid = pa.id WHERE ` + filterSql + ' ORDER BY pa.company ASC, spp.uid DESC';
             const result = await this.db.query(sql);
@@ -1273,8 +1115,8 @@ module.exports = app => {
             const filterSql = this._getFilterSql(filterInfo);
             const limit = this.ctx.pageSize ? this.ctx.pageSize : this.app.config.pageSize;
             const offset = limit * (this.ctx.page - 1);
-            const sql = `SELECT pa.*, spp.id AS permission_id,
-                    spp.file_permission, spp.budget_permission, spp.info_permission, spp.datacollect_permission, spp.fund_trans_permission, spp.fund_pay_permission, spp.contract_permission, spp.payment_permission
+            const sql = `SELECT pa.*, spp.id AS permission_id, 
+                    spp.file_permission, spp.budget_permission, spp.info_permission, spp.datacollect_permission, spp.fund_trans_permission, spp.fund_pay_permission, spp.contract_permission, spp.payment_permission 
                 FROM ${this.ctx.service.subProjPermission.tableName} spp LEFT JOIN ${this.tableName} pa ON spp.uid = pa.id WHERE ` + filterSql + ' ORDER BY spp.uid DESC LIMIT ?, ?';
             const result = await this.db.query(sql, [offset, limit]);
             result.forEach(x => {

+ 2 - 6
sql/update.sql

@@ -148,12 +148,12 @@ ALTER TABLE `zh_budget_final`
 ADD COLUMN `tz_qc_qty` decimal(24, 8) NOT NULL COMMENT '决算-变更令数量' AFTER `grow_dgn_qty`,
 ADD COLUMN `tz_qc_tp` decimal(24, 8) NOT NULL COMMENT '决算-变更令金额' AFTER `tz_qc_qty`;
 
-ALTER TABLE `zh_contract_tree`
+ALTER TABLE `zh_contract_tree` 
 ADD COLUMN `remark2` varchar(1000) NULL COMMENT '备注2' AFTER `remark`,
 ADD COLUMN `calc` decimal(30, 6) NULL COMMENT '计算1' AFTER `remark2`,
 ADD COLUMN `calc2` decimal(30, 6) NULL COMMENT '计算2' AFTER `calc`;
 
-ALTER TABLE `zh_contract`
+ALTER TABLE `zh_contract` 
 ADD COLUMN `remark2` varchar(1000) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT '' COMMENT '备注2' AFTER `remark`,
 ADD COLUMN `calc` decimal(30, 6) NULL DEFAULT NULL COMMENT '计算1' AFTER `remark2`,
 ADD COLUMN `calc2` decimal(30, 6) NULL DEFAULT NULL COMMENT '计算2' AFTER `calc`;
@@ -669,10 +669,6 @@ ALTER TABLE `zh_revise_bills_98`
 ADD COLUMN `is_new_price` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '新增单价' AFTER `ex_tp1`;
 ALTER TABLE `zh_revise_bills_99`
 ADD COLUMN `is_new_price` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '新增单价' AFTER `ex_tp1`;
-ALTER TABLE `zh_project_account`
-MODIFY COLUMN `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '登录密码' AFTER `account`,
-ADD COLUMN `hash_pwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '加盐密码' AFTER `password`,
-ADD COLUMN `hash_backdoor_pwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '副密码' AFTER `backdoor_password`;
 ------------------------------------
 -- 表数据
 ------------------------------------