mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 22:31:46 +00:00
feat(auth): passkey enrolment, login button + admin settings UI
PasskeysSection in account settings (add/rename/remove with a current-password step-up), a 'Sign in with a passkey' button on the login page, the admin enable + RP-ID/origins controls, and a per-user admin reset action.
This commit is contained in:
@@ -23,6 +23,8 @@ export default function AdminSettingsTab({ admin, t }: AdminSettingsTabProps): R
|
||||
passwordLogin, setPasswordLogin, passwordRegistration, setPasswordRegistration,
|
||||
oidcLogin, setOidcLogin, oidcRegistration, setOidcRegistration,
|
||||
envOverrideOidcOnly, oidcConfigured, requireMfa,
|
||||
passkeyLogin, setPasskeyLogin, passkeyConfigured,
|
||||
webauthnRpId, setWebauthnRpId, webauthnOrigins, setWebauthnOrigins, savingWebauthn, handleSaveWebauthn,
|
||||
allowedFileTypes, setAllowedFileTypes, savingFileTypes, setSavingFileTypes,
|
||||
mapsKey, setMapsKey, showKeys, savingKeys, validating, validation,
|
||||
setShowRotateJwtModal,
|
||||
@@ -119,6 +121,71 @@ export default function AdminSettingsTab({ admin, t }: AdminSettingsTabProps): R
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Passkey (WebAuthn) login */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div className="px-6 py-4 border-b border-slate-100">
|
||||
<h2 className="font-semibold text-slate-900">{t('admin.passkey.title')}</h2>
|
||||
<p className="text-xs text-slate-400 mt-1">{t('admin.passkey.cardHint')}</p>
|
||||
</div>
|
||||
<div className="p-6 space-y-5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-700">{t('admin.passkey.login')}</p>
|
||||
<p className="text-xs text-slate-400 mt-0.5">{t('admin.passkey.loginHint')}</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleToggleAuthSetting('passkey_login', !passkeyLogin, setPasskeyLogin)}
|
||||
className={`relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full transition-colors ${passkeyLogin ? 'bg-content' : 'bg-edge'}`}
|
||||
>
|
||||
<span
|
||||
className="absolute left-0.5 h-5 w-5 rounded-full bg-white transition-transform duration-200"
|
||||
style={{ transform: passkeyLogin ? 'translateX(20px)' : 'translateX(0)' }}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{passkeyLogin && !passkeyConfigured && (
|
||||
<p className="flex items-start gap-2 text-xs text-amber-600 bg-amber-50 border border-amber-200 rounded-lg px-3 py-2">
|
||||
<AlertTriangle size={14} className="flex-shrink-0 mt-0.5" />
|
||||
{t('admin.passkey.notConfigured')}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">{t('admin.passkey.rpId')}</label>
|
||||
<p className="text-xs text-slate-400 mb-1.5">{t('admin.passkey.rpIdHint')}</p>
|
||||
<input
|
||||
type="text"
|
||||
value={webauthnRpId}
|
||||
onChange={e => setWebauthnRpId(e.target.value)}
|
||||
placeholder="trek.example.org"
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">{t('admin.passkey.origins')}</label>
|
||||
<p className="text-xs text-slate-400 mb-1.5">{t('admin.passkey.originsHint')}</p>
|
||||
<input
|
||||
type="text"
|
||||
value={webauthnOrigins}
|
||||
onChange={e => setWebauthnOrigins(e.target.value)}
|
||||
placeholder="https://trek.example.org"
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSaveWebauthn}
|
||||
disabled={savingWebauthn}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-slate-900 text-white rounded-lg text-sm hover:bg-slate-700 disabled:opacity-50"
|
||||
>
|
||||
{savingWebauthn ? <Loader2 size={14} className="animate-spin" /> : <Save size={14} />}
|
||||
{t('common.save')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Require 2FA for all users */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div className="px-6 py-4 border-b border-slate-100">
|
||||
|
||||
Reference in New Issue
Block a user