Enable default emergency account
Some checks are pending
ci / test (push) Waiting to run
ci / test-postgresql (push) Waiting to run

This commit is contained in:
oliver 2026-10-12 10:46:39 +08:00
parent 70bde46eff
commit 07cfbefb6c
9 changed files with 43 additions and 31 deletions

View file

@ -33,7 +33,7 @@ window.__ModuleLoader__.load({
"ui.settingsTitle": "UAC 认证",
"ui.settingsIntro": "工号+token 双校验;UAC 挂死时用应急账号 administrator 密码登录。",
"ui.loginRequiredPage": "请先登录后查看此页",
"ui.roleHint": "当前角色:{role}。超管只是身份标签,与管理员权限相同;显式配置的初始管理员在首次登录时获得超管身份,也可在「用户管理」设为管理员。应急账号 administrator 需先设密码,再在登录面板用账密登录。",
"ui.roleHint": "当前角色:{role}。超管只是身份标签,与管理员权限相同;显式配置的初始管理员在首次登录时获得超管身份,也可在「用户管理」设为管理员。应急账号默认账号 administrator、密码 Admin@123,首次登录后请修改。",
"ui.deployConfig": "部署配置",
"ui.userSearchUrl": "用户搜索 URL(token 校验)",
"ui.workspaceRoot": "工作区根目录(空=$DSH_HOME/user-workspaces)",
@ -78,8 +78,8 @@ window.__ModuleLoader__.load({
"ui.refreshQr": "刷新二维码",
"ui.fallbackLink": "UAC 不可用?应急账号登录",
"ui.fallbackDisabledLink": "应急登录(未启用)",
"ui.fallbackDisabledHint": "应急密码未配置或已停用。请用已登录的管理员在「账户 / 权限」中设置新的独立强密码后重试。旧共享默认密码不可用。",
"ui.fallbackDisabledDetail": "当前未启用应急密码。用已授权管理员登录后,在设置中配置新密码即可恢复此入口。",
"ui.fallbackDisabledHint": "应急账号已关闭。请用已登录的管理员在「账户 / 权限」中重新设置并启用。",
"ui.fallbackDisabledDetail": "当前未启用应急账号。用已授权管理员登录后,在设置中重新设置密码即可恢复此入口。",
"ui.fallbackLogin": "应急登录",
"ui.fallbackDetail": "UAC / 扫码不可用时使用",
"ui.localKeyLink": "本机密钥解锁",
@ -180,7 +180,7 @@ window.__ModuleLoader__.load({
"ui.settingsTitle": "UAC Auth",
"ui.settingsIntro": "EmpNo + token verification; when UAC is down, sign in with emergency account administrator.",
"ui.loginRequiredPage": "Sign in to view this page",
"ui.roleHint": "Current role: {role}. Super admin is only an identity label with the same permissions as admin; the explicitly configured initial administrator receives that identity on first login, or grant admin in User management. Set the emergency password before using administrator on the login panel.",
"ui.roleHint": "Current role: {role}. Super admin is only an identity label with the same permissions as admin; the explicitly configured initial administrator receives that identity on first login, or grant admin in User management. The emergency account defaults to administrator / Admin@123; change it after first sign-in.",
"ui.deployConfig": "Deploy config",
"ui.userSearchUrl": "User search URL (token verify)",
"ui.workspaceRoot": "Workspace root (empty=$DSH_HOME/user-workspaces)",
@ -225,8 +225,8 @@ window.__ModuleLoader__.load({
"ui.refreshQr": "Refresh QR",
"ui.fallbackLink": "UAC down? Emergency account",
"ui.fallbackDisabledLink": "Emergency login (disabled)",
"ui.fallbackDisabledHint": "Emergency password is not configured or was disabled. Ask a signed-in admin to set a new strong password under Account / Permissions. The old shared default password cannot be used.",
"ui.fallbackDisabledDetail": "Emergency password is off. After an authorized admin sets a new password in settings, this entry works again.",
"ui.fallbackDisabledHint": "The emergency account is disabled. Ask a signed-in admin to set a new password and enable it under Account / Permissions.",
"ui.fallbackDisabledDetail": "The emergency account is off. An authorized admin can set its password again in settings to restore this entry.",
"ui.fallbackLogin": "Emergency login",
"ui.fallbackDetail": "Use when UAC / QR is unavailable",
"ui.localKeyLink": "Unlock with local key",

View file

@ -26,7 +26,7 @@ export const MESSAGES = {
'ui.settingsTitle': 'UAC 认证',
'ui.settingsIntro': '工号+token 双校验;UAC 挂死时用应急账号 administrator 密码登录。',
'ui.loginRequiredPage': '请先登录后查看此页',
'ui.roleHint': '当前角色:{role}。超管只是身份标签,与管理员权限相同;显式配置的初始管理员在首次登录时获得超管身份,也可在「用户管理」设为管理员。应急账号 administrator 需先设密码,再在登录面板用账密登录。',
'ui.roleHint': '当前角色:{role}。超管只是身份标签,与管理员权限相同;显式配置的初始管理员在首次登录时获得超管身份,也可在「用户管理」设为管理员。应急账号默认账号 administrator、密码 Admin@123,首次登录后请修改。',
'ui.deployConfig': '部署配置',
'ui.userSearchUrl': '用户搜索 URL(token 校验)',
'ui.workspaceRoot': '工作区根目录(空=$DSH_HOME/user-workspaces)',
@ -213,7 +213,7 @@ export const MESSAGES = {
'ui.settingsTitle': 'UAC Auth',
'ui.settingsIntro': 'EmpNo + token verification; when UAC is down, sign in with emergency account administrator.',
'ui.loginRequiredPage': 'Sign in to view this page',
'ui.roleHint': 'Current role: {role}. Super admin is only an identity label with the same permissions as admin; the explicitly configured initial administrator receives that identity on first login, or grant admin in User management. Set the emergency password before using administrator on the login panel.',
'ui.roleHint': 'Current role: {role}. Super admin is only an identity label with the same permissions as admin; the explicitly configured initial administrator receives that identity on first login, or grant admin in User management. The emergency account defaults to administrator / Admin@123; change it after first sign-in.',
'ui.deployConfig': 'Deploy config',
'ui.userSearchUrl': 'User search URL (token verify)',
'ui.workspaceRoot': 'Workspace root (empty=$DSH_HOME/user-workspaces)',

View file

@ -29,7 +29,7 @@ const ACCOUNT_STATUS = {
DISABLED: 'disabled',
}
/** Known shared default from pre-0.3 installs — must never remain usable (R10). */
/** Shared emergency default requested for first boot and legacy migrations. */
const LEGACY_DEFAULT_SHA256 = createHash('sha256').update('Admin@123').digest('hex')
/**
@ -141,7 +141,7 @@ export function canToggleViewAllSessions(role) {
return isAdminClass(role)
}
/** Historical default — never enable automatically (R10). */
/** Default emergency credentials. Rotate the password after first sign-in. */
export const DEFAULT_FALLBACK_PASSWORD = 'Admin@123'
export const DEFAULT_FALLBACK_USERNAME = 'administrator'
@ -149,7 +149,7 @@ export const DEFAULT_FALLBACK_USERNAME = 'administrator'
* RolesStore — 角色存储
* 内存 Map + 可选 JSON 文件持久化
*
* fallback admin: 默认关闭;须在设置中显式设置 scrypt 口令(≥10,禁 Admin@123)。
* fallback admin: first boot uses the shared Admin@123 password; admins can rotate or disable it.
* 登录路径: POST /uds-auth/api/fallback/login { username, password }
*/
export class RolesStore {
@ -170,18 +170,21 @@ export class RolesStore {
this._saveTimer = null
}
/**
* New installs do NOT enable a shared default password (SEC-08).
* Admins must set a password explicitly via settings / setFallbackPassword.
*/
/** Seed the requested default emergency password on first initialization. */
_ensureDefaultFallback() {
// no-op — kept for call-site compatibility
if (this._fallbackPasswordHash !== null) return false
this._fallbackPasswordHash = hashPasswordScrypt(DEFAULT_FALLBACK_PASSWORD)
this._fallbackNeedsRehash = false
this._fallbackCredVersion = Math.max(1, this._fallbackCredVersion + 1)
this._dirty = true
return true
}
// === 持久化 ===
async init() {
let loadedOk = false
let seedDefaultFallback = !this._rolesFile
if (this._rolesFile) {
try {
const raw = await readFile(this._rolesFile, 'utf-8')
@ -196,6 +199,9 @@ export class RolesStore {
}
if (Object.prototype.hasOwnProperty.call(data, 'fallbackPasswordHash')) {
this._fallbackPasswordHash = data.fallbackPasswordHash || null
} else {
// Upgrade older roles files that predate explicit fallback state.
seedDefaultFallback = true
}
this._fallbackCredVersion = Number.isSafeInteger(data.fallbackCredVersion)
&& data.fallbackCredVersion >= 0 ? data.fallbackCredVersion : 0
@ -207,9 +213,10 @@ export class RolesStore {
loadedOk = true
} catch (err) {
if (err.code === 'ENOENT') {
// First boot — empty roles, fallback disabled until explicitly configured.
// First boot — seed and persist the requested default credentials.
seedDefaultFallback = true
console.info(
'[uds-auth] roles file missing; fallback password disabled until configured'
'[uds-auth] roles file missing; enabling default emergency account administrator'
+ ` (set initialAdmin via UDS_AUTH_INITIAL_ADMIN)`,
)
} else {
@ -219,11 +226,12 @@ export class RolesStore {
}
}
}
// R10: known shared default hash cannot remain enabled after upgrade.
// Upgrade the historical SHA-256 default to a salted scrypt hash.
if (loadedOk && this._fallbackPasswordHash
&& String(this._fallbackPasswordHash).toLowerCase() === LEGACY_DEFAULT_SHA256) {
console.warn('[uds-auth] refusing legacy shared default fallback password — disabled until reset')
this._fallbackPasswordHash = null
console.warn('[uds-auth] migrating legacy default fallback password to scrypt')
this._fallbackPasswordHash = hashPasswordScrypt(DEFAULT_FALLBACK_PASSWORD)
this._fallbackCredVersion = Math.max(1, this._fallbackCredVersion + 1)
this._dirty = true
await this._save()
} else if (loadedOk && this._fallbackPasswordHash
@ -231,6 +239,10 @@ export class RolesStore {
this._fallbackNeedsRehash = true
console.warn('[uds-auth] legacy SHA-256 fallback hash loaded — will upgrade on next successful login')
}
if (seedDefaultFallback && !this._loadFailed) {
this._ensureDefaultFallback()
await this.flush()
}
if (loadedOk && this._fallbackPasswordHash) {
console.info('[uds-auth] fallback_admin password loaded from roles file')
}