feat: use sessionStorage by default for UUID/tokens, add opt-in remember-me with warning
This commit is contained in:
@@ -110,6 +110,14 @@ class AuthModal extends HTMLElement {
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="remember-me" ${auth.getRememberMe() ? 'checked' : ''}>
|
||||
<span>${t('auth.rememberMe')}</span>
|
||||
</label>
|
||||
<p class="field-hint">${t('auth.rememberMeHint')}</p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-lg btn-block" ${this.loading ? 'disabled' : ''}>
|
||||
${this.loading ? t('auth.loggingIn') : t('auth.login')}
|
||||
</button>
|
||||
@@ -247,6 +255,9 @@ class AuthModal extends HTMLElement {
|
||||
this.error = null
|
||||
this.render()
|
||||
|
||||
const rememberMe = this.querySelector('#remember-me')?.checked || false
|
||||
auth.setRememberMe(rememberMe)
|
||||
|
||||
const result = await auth.login(uuid)
|
||||
|
||||
this.loading = false
|
||||
@@ -469,6 +480,26 @@ style.textContent = /* css */`
|
||||
auth-modal .link-btn:hover {
|
||||
color: var(--color-accent-hover);
|
||||
}
|
||||
|
||||
auth-modal .checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
auth-modal .checkbox-label input {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
accent-color: var(--color-accent);
|
||||
}
|
||||
|
||||
auth-modal .field-hint {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-text-muted);
|
||||
margin-top: var(--space-xs);
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import { directus } from './directus.js'
|
||||
import { setPersist, getPersist } from './directus/client.js'
|
||||
import { i18n } from '../i18n.js'
|
||||
|
||||
const AUTH_DOMAIN = 'dgray.io'
|
||||
@@ -16,6 +17,9 @@ class AuthService {
|
||||
this.currentUser = null
|
||||
this.listeners = new Set()
|
||||
this.hashCache = new Map()
|
||||
if (localStorage.getItem('dgray_remember') === '1') {
|
||||
setPersist(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,6 +140,8 @@ class AuthService {
|
||||
|
||||
this.currentUser = null
|
||||
this.clearStoredUuid()
|
||||
localStorage.removeItem('dgray_remember')
|
||||
setPersist(false)
|
||||
this.resetPreferencesToDefaults()
|
||||
this.notifyListeners()
|
||||
}
|
||||
@@ -227,7 +233,8 @@ class AuthService {
|
||||
* @param {string} uuid
|
||||
*/
|
||||
storeUuid(uuid) {
|
||||
localStorage.setItem('dgray_uuid', uuid)
|
||||
const storage = getPersist() ? localStorage : sessionStorage
|
||||
storage.setItem('dgray_uuid', uuid)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,16 +242,30 @@ class AuthService {
|
||||
* @returns {string|null}
|
||||
*/
|
||||
getStoredUuid() {
|
||||
return localStorage.getItem('dgray_uuid')
|
||||
return sessionStorage.getItem('dgray_uuid') || localStorage.getItem('dgray_uuid')
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears stored UUID
|
||||
*/
|
||||
clearStoredUuid() {
|
||||
sessionStorage.removeItem('dgray_uuid')
|
||||
localStorage.removeItem('dgray_uuid')
|
||||
}
|
||||
|
||||
setRememberMe(value) {
|
||||
setPersist(value)
|
||||
if (value) {
|
||||
localStorage.setItem('dgray_remember', '1')
|
||||
} else {
|
||||
localStorage.removeItem('dgray_remember')
|
||||
}
|
||||
}
|
||||
|
||||
getRememberMe() {
|
||||
return localStorage.getItem('dgray_remember') === '1'
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to auth state changes
|
||||
* @param {Function} callback
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
const DIRECTUS_URL = 'https://api.dgray.io'
|
||||
|
||||
let _persist = false
|
||||
|
||||
export function setPersist(value) {
|
||||
_persist = value
|
||||
}
|
||||
|
||||
export function getPersist() {
|
||||
return _persist
|
||||
}
|
||||
|
||||
function _storage() {
|
||||
return _persist ? localStorage : sessionStorage
|
||||
}
|
||||
|
||||
class DirectusError extends Error {
|
||||
constructor(status, message, data = {}) {
|
||||
super(message)
|
||||
@@ -37,13 +51,16 @@ class DirectusClient {
|
||||
// ── Token Management ──
|
||||
|
||||
loadTokens() {
|
||||
const stored = localStorage.getItem('dgray_auth')
|
||||
const stored = sessionStorage.getItem('dgray_auth') || localStorage.getItem('dgray_auth')
|
||||
if (stored) {
|
||||
try {
|
||||
const { accessToken, refreshToken, expiry } = JSON.parse(stored)
|
||||
this.accessToken = accessToken
|
||||
this.refreshToken = refreshToken
|
||||
this.tokenExpiry = expiry
|
||||
if (localStorage.getItem('dgray_auth')) {
|
||||
_persist = true
|
||||
}
|
||||
this.scheduleTokenRefresh()
|
||||
} catch (e) {
|
||||
this.clearTokens()
|
||||
@@ -56,7 +73,7 @@ class DirectusClient {
|
||||
this.refreshToken = refreshToken
|
||||
this.tokenExpiry = Date.now() + (expiresIn * 1000)
|
||||
|
||||
localStorage.setItem('dgray_auth', JSON.stringify({
|
||||
_storage().setItem('dgray_auth', JSON.stringify({
|
||||
accessToken: this.accessToken,
|
||||
refreshToken: this.refreshToken,
|
||||
expiry: this.tokenExpiry
|
||||
@@ -69,6 +86,7 @@ class DirectusClient {
|
||||
this.accessToken = null
|
||||
this.refreshToken = null
|
||||
this.tokenExpiry = null
|
||||
sessionStorage.removeItem('dgray_auth')
|
||||
localStorage.removeItem('dgray_auth')
|
||||
|
||||
if (this.refreshTimeout) {
|
||||
|
||||
Reference in New Issue
Block a user