diff --git a/js/components/auth-modal.js b/js/components/auth-modal.js
index 1cad60c..9697f46 100644
--- a/js/components/auth-modal.js
+++ b/js/components/auth-modal.js
@@ -110,6 +110,14 @@ class AuthModal extends HTMLElement {
` : ''}
+
+
@@ -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)
diff --git a/js/services/auth.js b/js/services/auth.js
index 4132dcd..b351e1e 100644
--- a/js/services/auth.js
+++ b/js/services/auth.js
@@ -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
diff --git a/js/services/directus/client.js b/js/services/directus/client.js
index 0fbd568..df20f09 100644
--- a/js/services/directus/client.js
+++ b/js/services/directus/client.js
@@ -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) {
diff --git a/locales/de.json b/locales/de.json
index 2e7dd25..2d076d2 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -198,7 +198,9 @@
"downloadBackup": "Backup herunterladen",
"confirmSaved": "Ich habe meine UUID gespeichert",
"registrationFailed": "Registrierung fehlgeschlagen",
- "loginRequired": "Bitte melde dich an, um fortzufahren"
+ "loginRequired": "Bitte melde dich an, um fortzufahren",
+ "rememberMe": "Auf diesem Gerät merken",
+ "rememberMeHint": "Deine UUID wird lokal gespeichert. Nur aktivieren auf vertrauenswürdigen Geräten."
},
"favorites": {
"title": "Favoriten",
diff --git a/locales/en.json b/locales/en.json
index a22c774..1a91a88 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -198,7 +198,9 @@
"downloadBackup": "Download Backup",
"confirmSaved": "I have saved my UUID",
"registrationFailed": "Registration failed",
- "loginRequired": "Please log in to continue"
+ "loginRequired": "Please log in to continue",
+ "rememberMe": "Remember me on this device",
+ "rememberMeHint": "Your UUID will be stored locally. Only enable on trusted devices."
},
"favorites": {
"title": "Favorites",
diff --git a/locales/es.json b/locales/es.json
index de4f31c..861117e 100644
--- a/locales/es.json
+++ b/locales/es.json
@@ -198,7 +198,9 @@
"downloadBackup": "Descargar copia de seguridad",
"confirmSaved": "He guardado mi UUID",
"registrationFailed": "Error en el registro",
- "loginRequired": "Inicia sesión para continuar"
+ "loginRequired": "Inicia sesión para continuar",
+ "rememberMe": "Recordarme en este dispositivo",
+ "rememberMeHint": "Tu UUID se guardará localmente. Actívalo solo en dispositivos de confianza."
},
"favorites": {
"title": "Favoritos",
diff --git a/locales/fr.json b/locales/fr.json
index 46bf54d..c0bf23b 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -198,7 +198,9 @@
"downloadBackup": "Télécharger la sauvegarde",
"confirmSaved": "J'ai sauvegardé mon UUID",
"registrationFailed": "Échec de l'inscription",
- "loginRequired": "Veuillez vous connecter pour continuer"
+ "loginRequired": "Veuillez vous connecter pour continuer",
+ "rememberMe": "Se souvenir de moi",
+ "rememberMeHint": "Votre UUID sera stocké localement. N'activez que sur des appareils de confiance."
},
"favorites": {
"title": "Favoris",
diff --git a/locales/it.json b/locales/it.json
index 07bb6a3..4bb9006 100644
--- a/locales/it.json
+++ b/locales/it.json
@@ -198,7 +198,9 @@
"downloadBackup": "Scarica backup",
"confirmSaved": "Ho salvato il mio UUID",
"registrationFailed": "Registrazione fallita",
- "loginRequired": "Accedi per continuare"
+ "loginRequired": "Accedi per continuare",
+ "rememberMe": "Ricordami su questo dispositivo",
+ "rememberMeHint": "Il tuo UUID verrà salvato localmente. Attiva solo su dispositivi affidabili."
},
"favorites": {
"title": "Preferiti",
diff --git a/locales/pt.json b/locales/pt.json
index 0cc0c45..6110bd0 100644
--- a/locales/pt.json
+++ b/locales/pt.json
@@ -198,7 +198,9 @@
"downloadBackup": "Baixar Backup",
"confirmSaved": "Eu salvei meu UUID",
"registrationFailed": "Falha no cadastro",
- "loginRequired": "Por favor, faça login para continuar"
+ "loginRequired": "Por favor, faça login para continuar",
+ "rememberMe": "Lembrar neste dispositivo",
+ "rememberMeHint": "Seu UUID será armazenado localmente. Ative apenas em dispositivos confiáveis."
},
"favorites": {
"title": "Favoritos",
diff --git a/locales/ru.json b/locales/ru.json
index 927dd4a..a80810e 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -198,7 +198,9 @@
"downloadBackup": "Скачать резервную копию",
"confirmSaved": "Я сохранил свой UUID",
"registrationFailed": "Регистрация не удалась",
- "loginRequired": "Войдите, чтобы продолжить"
+ "loginRequired": "Войдите, чтобы продолжить",
+ "rememberMe": "Запомнить на этом устройстве",
+ "rememberMeHint": "Ваш UUID будет сохранён локально. Включайте только на доверенных устройствах."
},
"favorites": {
"title": "Избранное",