mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-18 03:30:48 +08:00
fix(uds-auth): emergency login workspaces, Desktop key prompts, persistent sessions
Emergency (fallback / sealed-box) admins lost the workspace sidebar and saw "sign-in failed / add API key" on DSH Desktop because the remote.mux opens anonymously at boot and every early call was rejected terminally. - gateway: anonymous workspace/follow reaches dsh-acl's empty baseline; anonymous streams are parked until the carrier aborts instead of failing; anonymous workspace/initializeDefault answers "nothing created" - request-auth: a dead UDS_SESSION cookie no longer shadows a valid WS ticket or bridge (sync + async variants used by all callers) - dsh-acl: /api/* waits (bounded 15s) for the gateway ACL during Host startup instead of 403, so the Desktop welcome read no longer fails - desktop-bootstrap: key/account projection is best-effort per reference - client: emit connection/reset after login so boot-time caches (settings describe mirror -> Settings > Models) re-read under the real principal - sessions: absolute lifetime fixed at 7 days (was min(ttl, 7d) = 30 min); bridge expiry slides with its session; MemoryStore persisted to sessions.json (bearer hash only, userData AES-256-GCM sealed) - README: session lifetime/persistence and DSH compatibility notes Also includes previously uncommitted uds-auth 0.3.x work in this tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fa4d5d6d97
commit
df97c5e042
72 changed files with 8436 additions and 1192 deletions
|
|
@ -26,7 +26,7 @@ export const MESSAGES = {
|
|||
'ui.settingsTitle': 'UAC 认证',
|
||||
'ui.settingsIntro': '工号+token 双校验;UAC 挂死时用应急账号 administrator 密码登录。',
|
||||
'ui.loginRequiredPage': '请先登录后查看此页',
|
||||
'ui.roleHint': '当前角色:{role}。超管只是身份标签,与管理员权限相同;首位扫码登录且 roles.json 为空时自动获得超管身份,也可在「用户管理」设为管理员。应急账号 administrator 需先设密码,再在登录面板用账密登录。',
|
||||
'ui.roleHint': '当前角色:{role}。超管只是身份标签,与管理员权限相同;显式配置的初始管理员在首次登录时获得超管身份,也可在「用户管理」设为管理员。应急账号 administrator 需先设密码,再在登录面板用账密登录。',
|
||||
'ui.deployConfig': '部署配置',
|
||||
'ui.userSearchUrl': '用户搜索 URL(token 校验)',
|
||||
'ui.workspaceRoot': '工作区根目录(空=$DSH_HOME/user-workspaces)',
|
||||
|
|
@ -38,7 +38,7 @@ export const MESSAGES = {
|
|||
'ui.fallbackStatus': '状态:{status}。可在此改密或关闭。仅在扫码不可用时从登录面板切换。',
|
||||
'ui.enabled': '已启用',
|
||||
'ui.disabled': '未启用',
|
||||
'ui.fallbackPassword': '应急密码(至少 6 位)',
|
||||
'ui.fallbackPassword': '应急密码(至少 10 位)',
|
||||
'ui.saveFallbackPassword': '保存应急密码',
|
||||
'ui.fallbackPasswordSet': '应急密码已设置',
|
||||
'ui.confirmClearFallback': '确认清除应急密码?',
|
||||
|
|
@ -121,20 +121,50 @@ export const MESSAGES = {
|
|||
'err.invalid_credentials': '用户名或密码错误',
|
||||
'err.last_super_admin_demote': '系统至少需要 1 个超级管理员,不能降级最后一个',
|
||||
'err.last_super_admin_delete': '系统至少需要 1 个超级管理员,不能删除最后一个',
|
||||
'err.password_too_short': '密码至少 6 位',
|
||||
'err.password_too_short': '密码至少 10 位',
|
||||
'err.password_too_common': '不能使用已知默认口令',
|
||||
'err.account_disabled': '账号已停用',
|
||||
'err.qr_unknown': '二维码无效或已过期',
|
||||
'err.qr_replay': '二维码已使用',
|
||||
'err.qr_expired': '二维码已过期',
|
||||
'err.qr_mismatch': '二维码校验失败',
|
||||
'err.upstream_too_large': '上游响应过大',
|
||||
'err.config_not_ready': '配置未初始化',
|
||||
'err.request_failed': '请求失败',
|
||||
'err.method_not_allowed': '方法不允许',
|
||||
'err.missing_qr_params': '缺少 qrCodeKey 或 qrCodeValue',
|
||||
'err.missing_emp_token': '缺少 empNo 或 token',
|
||||
'err.token_in_query_forbidden': '禁止在 URL 传递 token,请改用 POST body 或请求头',
|
||||
'err.user_search_failed': '用户搜索失败',
|
||||
'err.not_found': '未找到',
|
||||
'err.internal': '内部错误',
|
||||
'err.login_required_cron': '登录后才能使用定时任务',
|
||||
'err.login_required_session': '登录后才能访问会话',
|
||||
'err.login_required_create_session': '登录后才能创建会话',
|
||||
'err.login_required_create_workspace': '登录后才能创建工作区',
|
||||
'err.login_required_workspace': '登录后才能使用工作区',
|
||||
'err.workspace_provision_failed': '个人工作区初始化失败,请重试',
|
||||
'err.plugin_unready': '认证插件未就绪',
|
||||
'err.origin_forbidden': '请求来源不被允许',
|
||||
'err.content_type': 'Content-Type 必须为 application/json',
|
||||
'err.https_required': '出站代理仅允许 HTTPS',
|
||||
'err.invalid_config': '配置无效',
|
||||
'err.unknown_config_field': '未知配置字段',
|
||||
'err.invalid_uac_url': 'uacBaseUrl 必须是 https URL',
|
||||
'err.invalid_user_search_url': 'userSearchUrl 必须是 https URL',
|
||||
'err.invalid_workspace_root': 'workspaceRoot 必须是绝对路径',
|
||||
'err.invalid_ttl': 'TTL 超出允许范围',
|
||||
'err.invalid_outbound_host': 'outbound 白名单 host 格式无效',
|
||||
'err.bootstrap_required': '系统尚未初始化管理员,请配置 UDS_AUTH_INITIAL_ADMIN',
|
||||
'err.registration_closed': '未开放自动注册,请联系管理员',
|
||||
'err.raw_token_disabled': '原始凭证接口已关闭,请使用 outbound 代理',
|
||||
'err.caller_unauthenticated': '调用方未通过本地会话认证',
|
||||
'err.session_id_required': '需要 DSH sessionId',
|
||||
'err.session_owner_mismatch': '会话归属与调用方不一致',
|
||||
'err.session_forbidden': '无权访问该会话',
|
||||
'err.session_revoked': '会话已失效,请重新登录',
|
||||
'err.fallback_disabled': '应急账号已关闭',
|
||||
'err.file_forbidden': '无权访问该文件',
|
||||
'err.session_workspace_only': '只能在自己的工作区创建会话',
|
||||
'err.workspace_path_only': '只能打开自己的工作区路径',
|
||||
'err.workspace_create_forbidden': '只有管理员可以创建工作区',
|
||||
|
|
@ -152,6 +182,8 @@ export const MESSAGES = {
|
|||
'err.key_required': '请输入解密密钥',
|
||||
'err.decrypt_failed': '密钥无法解密,登录失败',
|
||||
'err.rate_limited': '尝试过多,请稍后再试',
|
||||
'err.payload_too_large': '请求体过大',
|
||||
'err.invalid_json': 'JSON 无效',
|
||||
|
||||
// API success
|
||||
'ok.logged_out': '已退出登录',
|
||||
|
|
@ -179,7 +211,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 first QR login with an empty roles.json gets that identity, 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. Set the emergency password before using administrator on the login panel.',
|
||||
'ui.deployConfig': 'Deploy config',
|
||||
'ui.userSearchUrl': 'User search URL (token verify)',
|
||||
'ui.workspaceRoot': 'Workspace root (empty=$DSH_HOME/user-workspaces)',
|
||||
|
|
@ -191,7 +223,7 @@ export const MESSAGES = {
|
|||
'ui.fallbackStatus': 'Status: {status}. Change or disable here. Switch from the login panel only when QR is unavailable.',
|
||||
'ui.enabled': 'Enabled',
|
||||
'ui.disabled': 'Disabled',
|
||||
'ui.fallbackPassword': 'Emergency password (min 6 chars)',
|
||||
'ui.fallbackPassword': 'Emergency password (min 10 chars)',
|
||||
'ui.saveFallbackPassword': 'Save emergency password',
|
||||
'ui.fallbackPasswordSet': 'Emergency password set',
|
||||
'ui.confirmClearFallback': 'Clear emergency password?',
|
||||
|
|
@ -269,20 +301,50 @@ export const MESSAGES = {
|
|||
'err.invalid_credentials': 'Invalid username or password',
|
||||
'err.last_super_admin_demote': 'At least one super admin is required; cannot demote the last one',
|
||||
'err.last_super_admin_delete': 'At least one super admin is required; cannot delete the last one',
|
||||
'err.password_too_short': 'Password must be at least 6 characters',
|
||||
'err.password_too_short': 'Password must be at least 10 characters',
|
||||
'err.password_too_common': 'Cannot use the known default password',
|
||||
'err.account_disabled': 'Account is disabled',
|
||||
'err.qr_unknown': 'QR challenge unknown or expired',
|
||||
'err.qr_replay': 'QR challenge already used',
|
||||
'err.qr_expired': 'QR challenge expired',
|
||||
'err.qr_mismatch': 'QR challenge mismatch',
|
||||
'err.upstream_too_large': 'Upstream response too large',
|
||||
'err.config_not_ready': 'Config not initialized',
|
||||
'err.request_failed': 'Request failed',
|
||||
'err.method_not_allowed': 'Method not allowed',
|
||||
'err.missing_qr_params': 'Missing qrCodeKey or qrCodeValue',
|
||||
'err.missing_emp_token': 'Missing empNo or token',
|
||||
'err.token_in_query_forbidden': 'Do not put token in the URL; use POST body or headers',
|
||||
'err.user_search_failed': 'User search failed',
|
||||
'err.not_found': 'Not found',
|
||||
'err.internal': 'Internal error',
|
||||
'err.login_required_cron': 'Sign in to use scheduled tasks',
|
||||
'err.login_required_session': 'Sign in to access sessions',
|
||||
'err.login_required_create_session': 'Sign in to create a session',
|
||||
'err.login_required_create_workspace': 'Sign in to create a workspace',
|
||||
'err.login_required_workspace': 'Sign in to use workspaces',
|
||||
'err.workspace_provision_failed': 'Personal workspace provisioning failed; retry',
|
||||
'err.plugin_unready': 'Auth plugin not ready',
|
||||
'err.origin_forbidden': 'Request origin not allowed',
|
||||
'err.content_type': 'Content-Type must be application/json',
|
||||
'err.https_required': 'Outbound proxy requires HTTPS',
|
||||
'err.invalid_config': 'Invalid config',
|
||||
'err.unknown_config_field': 'Unknown config field',
|
||||
'err.invalid_uac_url': 'uacBaseUrl must be an https URL',
|
||||
'err.invalid_user_search_url': 'userSearchUrl must be an https URL',
|
||||
'err.invalid_workspace_root': 'workspaceRoot must be an absolute path',
|
||||
'err.invalid_ttl': 'TTL out of allowed range',
|
||||
'err.invalid_outbound_host': 'Invalid outbound host entry',
|
||||
'err.bootstrap_required': 'Admin not initialized; set UDS_AUTH_INITIAL_ADMIN',
|
||||
'err.registration_closed': 'Open registration is disabled; contact an admin',
|
||||
'err.raw_token_disabled': 'Raw credential API disabled; use outbound proxy',
|
||||
'err.caller_unauthenticated': 'Caller lacks a verified local session',
|
||||
'err.session_id_required': 'DSH sessionId required',
|
||||
'err.session_owner_mismatch': 'Session owner does not match caller',
|
||||
'err.session_forbidden': 'No access to this session',
|
||||
'err.session_revoked': 'Session expired; please sign in again',
|
||||
'err.fallback_disabled': 'Emergency account is disabled',
|
||||
'err.file_forbidden': 'No access to this file',
|
||||
'err.session_workspace_only': 'Sessions can only be created in your own workspace',
|
||||
'err.workspace_path_only': 'You can only open your own workspace path',
|
||||
'err.workspace_create_forbidden': 'Only admins can create workspaces',
|
||||
|
|
@ -300,6 +362,8 @@ export const MESSAGES = {
|
|||
'err.key_required': 'Decryption key required',
|
||||
'err.decrypt_failed': 'Key could not decrypt — sign-in failed',
|
||||
'err.rate_limited': 'Too many attempts, try later',
|
||||
'err.payload_too_large': 'Payload too large',
|
||||
'err.invalid_json': 'Invalid JSON',
|
||||
|
||||
'ok.logged_out': 'Signed out',
|
||||
'ok.config_saved': 'Config saved',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue