From ec9be40d6c6e01e26fb140b30e7b516d921b4ca6 Mon Sep 17 00:00:00 2001 From: shuaiplus <2327005759@qq.com> Date: Thu, 26 Feb 2026 05:04:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E7=BD=91=E9=A1=B5?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=A0=B7=E5=BC=8F=E5=92=8C=E5=B8=83?= =?UTF-8?q?=E5=B1=80=EF=BC=8C=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7=E4=BD=93?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handlers/web.ts | 380 +++++++++++++++++++++++++++----------------- 1 file changed, 237 insertions(+), 143 deletions(-) diff --git a/src/handlers/web.ts b/src/handlers/web.ts index f07fc03..c4d618a 100644 --- a/src/handlers/web.ts +++ b/src/handlers/web.ts @@ -13,213 +13,298 @@ function renderWebClientHTML(): string { NodeWarden Web @@ -403,12 +488,12 @@ function renderWebClientHTML(): string { + '
' + '
' + '
' - + '
' + + '
' + '
' + (state.pendingLogin ? '' + '

Two-step verification

Password is already verified.
' + (state.loginTotpError?'
'+esc(state.loginTotpError)+'
':'') - + '
' + + '
' + '
' : '') + ' ' @@ -426,7 +511,7 @@ function renderWebClientHTML(): string { + '
' + '
' + '
' - + '
' + + '
' + ' ' + ' ' + ''; @@ -438,12 +523,12 @@ function renderWebClientHTML(): string { for(var i=0;i
'+esc(nameText)+'
'+esc(c.id)+'
'; + rows += '
'+esc(nameText)+'
'+esc(c.id)+'
'; } - if(!rows) rows='
No items in this folder.
'; + if(!rows) rows='
No items in this folder.
'; var c0=selectedCipher(); - var detail='
Select an item to view details.
'; + var detail='
Select an item to view details.
'; if(c0){ var login = c0.login||{}; var fields=Array.isArray(c0.fields)?c0.fields:[]; @@ -463,10 +548,11 @@ function renderWebClientHTML(): string { return '' + renderMsg() - + '

Vault

' - + '
' - + '
'+rows+'
'+detail+'
' - + '
'; + + '
' + + '

Vault

' + + '
' + + '
' + + '
'+rows+'
'+detail+'
'; } function renderSettingsTab(){ @@ -475,52 +561,58 @@ function renderWebClientHTML(): string { var qr='https://api.qrserver.com/v1/create-qr-code/?size=180x180&data='+encodeURIComponent(buildTotpUri(secret)); return '' + renderMsg() + + '

Settings

' + '

Profile

' + '

Master Password

After success, current sessions are revoked and you must log in again.
' - + '

TOTP Setup

TOTP QR
Disable action prompts for master password.
'; + + '

TOTP Setup

TOTP QR
Disable action prompts for master password.
'; } function renderTotpDisableModal(){ if(!state.totpDisableOpen) return ''; return '' - + '

Disable TOTP

Enter master password to disable two-step verification.
' - + (state.totpDisableError?'
'+esc(state.totpDisableError)+'
':'') - + '
' + + '

Disable TOTP

Enter master password to disable two-step verification.
' + + (state.totpDisableError?'
'+esc(state.totpDisableError)+'
':'') + + '
' + '
'; } function renderHelpTab(){ return '' - + '

Upstream Sync

  • Track upstream with a fork and scheduled sync workflow (recommended).
  • Before merge: compare API routes, migration files, and auth logic changes.
  • After merge: run local dev migration tests, then deploy Worker after validation.
' - + '

Common Errors

  • 401 Unauthorized: token expired or revoked, login again.
  • 403 Account disabled: admin must unban user in User Management.
  • 403 Invite invalid: invite expired/used/revoked, create a new invite.
  • 429 Too many requests: wait retry seconds and avoid burst writes.
' - + '

Troubleshooting

  • Login OK but encrypted values shown: verify profile key and KDF settings are consistent.
  • TOTP fails repeatedly: sync device time and re-scan QR using latest secret.
  • Password change failed: ensure current password is correct and new password has at least 12 chars.
  • Sync conflicts: refresh vault and retry one operation at a time.
'; + + '

Help & Support

' + + '

Upstream Sync

  • Track upstream with a fork and scheduled sync workflow (recommended).
  • Before merge: compare API routes, migration files, and auth logic changes.
  • After merge: run local dev migration tests, then deploy Worker after validation.
' + + '

Common Errors

  • 401 Unauthorized: token expired or revoked, login again.
  • 403 Account disabled: admin must unban user in User Management.
  • 403 Invite invalid: invite expired/used/revoked, create a new invite.
  • 429 Too many requests: wait retry seconds and avoid burst writes.
' + + '

Troubleshooting

  • Login OK but encrypted values shown: verify profile key and KDF settings are consistent.
  • TOTP fails repeatedly: sync device time and re-scan QR using latest secret.
  • Password change failed: ensure current password is correct and new password has at least 12 chars.
  • Sync conflicts: refresh vault and retry one operation at a time.
'; } function renderAdminTab(){ var usersRows=''; for(var i=0;i'+esc(u.name||'')+''+esc(u.role)+''+esc(u.status)+'' - + (canAct?'':'') + usersRows += ''+esc(u.email)+''+esc(u.name||'')+''+esc(u.role)+''+esc(u.status)+'' + + (canAct?'':'') + (canAct?' ':'') + ''; } - if(!usersRows) usersRows='No users.'; + if(!usersRows) usersRows='No users found.'; var inviteRows=''; for(var j=0;j'+esc(inv.status)+''+esc(inv.expiresAt)+'' - + '' + inviteRows += ''+esc(inv.code)+''+esc(inv.status)+''+esc(inv.expiresAt)+'' + + '' + (inv.status==='active'?' ':'') + ''; } - if(!inviteRows) inviteRows='No invites.'; + if(!inviteRows) inviteRows='No invites found.'; return '' + renderMsg() - + '

Create Invite

' - + '

Users

'+usersRows+'
EmailNameRoleStatusAction
' - + '

Invites

'+inviteRows+'
CodeStatusExpires AtAction
'; + + '
' + + '

User Management

' + + '' + + '
' + + '

Create Invite

' + + '

Users

'+usersRows+'
EmailNameRoleStatusAction
' + + '

Invites

'+inviteRows+'
CodeStatusExpires AtAction
'; } function renderApp(){ @@ -534,18 +626,20 @@ function renderWebClientHTML(): string { return '' + '
' + ' ' - + (showFolders?(' '):'') + + ' ' + + '
' + + ' ' + + (showFolders?(' '):'') + '
'+content+'
' + '
'+renderTotpDisableModal()+'
'; } function render(){ - if(state.phase==='loading'){ app.innerHTML='

Loading...

'; return; } + if(state.phase==='loading'){ app.innerHTML='
NW
Loading NodeWarden...
'; return; } if(state.phase==='register'){ app.innerHTML=renderRegisterScreen(); return; } if(state.phase==='login'){ app.innerHTML=renderLoginScreen(); return; } app.innerHTML=renderApp();