security(seeders): 初始管理员 seeder 支持 ADMIN_INIT_PASSWORD 覆盖(R110-B5①b)

- 002-seed-admin.js:口令改为「内置 bcrypt 哈希默认 + ADMIN_INIT_PASSWORD 环境变量覆盖」;
  提供环境变量时以 bcrypt.hashSync(值,10) 重算哈希、salt 取哈希前 29 字符(bcrypt 盐前缀)。
- 默认分支保持原哈希不变 ⇒ 既有开发/演示链路(admin123)零回归。
- 本文件⛔不落盘任何明文口令(铁律 25);凭据扫描 CAND 计数 2 → 2(零新增,可见性无损)。
This commit is contained in:
2026-10-14 10:22:53 +08:00
parent 706ff2507e
commit 6d3fbd62b4

View File

@@ -1,31 +1,41 @@
'use strict'; 'use strict';
// 初始管理员账号。
// 口令:下方内置 bcrypt 哈希仅为**开发/演示**默认值(对应公开弱口令,仅供本机初始化)。
// 正式初始化(生产等)时应通过环境变量 ADMIN_INIT_PASSWORD 注入真实口令 ——
// 本文件⛔不落盘任何明文口令(铁律 25)。
module.exports = { module.exports = {
up: async (queryInterface, Sequelize) => { up: async (queryInterface, Sequelize) => {
const now = new Date(); const now = new Date();
await queryInterface.bulkInsert('accounts', [ const row = {
{ role: 'admin',
role: 'admin', name_cn: '系统管理员',
name_cn: '系统管理员', name_en: 'Administrator',
name_en: 'Administrator', gender: null,
gender: null, phone: null,
phone: null, email: 'admin@competition.com',
email: 'admin@competition.com', id_number: '000000000000000000',
id_number: '000000000000000000', password: '$2b$10$Nc6PCJItIwuOzpM22dTiAezB.jZMI8mzkCbg3oRZkAWx.QaI4co9.',
password: '$2b$10$Nc6PCJItIwuOzpM22dTiAezB.jZMI8mzkCbg3oRZkAWx.QaI4co9.', salt: '$2b$10$Nc6PCJItIwuOzpM22dTiAe',
salt: '$2b$10$Nc6PCJItIwuOzpM22dTiAe', position: '系统管理员',
position: '系统管理员', major: null,
major: null, country: '中国',
country: '中国', region: null,
region: null, organization_cn: '赛事组委会',
organization_cn: '赛事组委会', organization_en: 'Competition Committee',
organization_en: 'Competition Committee', activated: 1,
activated: 1, score: null,
score: null, created_at: now,
created_at: now, updated_at: now,
updated_at: now, };
}, // 若提供 ADMIN_INIT_PASSWORD,则以之为准重算 bcrypt 哈希(salt 取哈希前 29 字符的 bcrypt 盐前缀)。
], {}); const initPwd = process.env.ADMIN_INIT_PASSWORD;
if (initPwd) {
const hash = require('bcrypt').hashSync(String(initPwd), 10);
row.password = hash;
row.salt = hash.slice(0, 29);
}
await queryInterface.bulkInsert('accounts', [row], {});
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface, Sequelize) => {