fix: security hardening + code quality improvements (401 retry limit, UUID crypto, debounce this-bug, deduplicate CSS/helpers, optimize SW precache)

This commit is contained in:
2026-02-08 13:53:23 +01:00
parent c66c80adcc
commit 9f48e073b8
11 changed files with 41 additions and 152 deletions

View File

@@ -27,11 +27,13 @@ class AuthService {
return crypto.randomUUID()
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0
const v = c === 'x' ? r : (r & 0x3 | 0x8)
return v.toString(16)
})
const bytes = new Uint8Array(16)
crypto.getRandomValues(bytes)
bytes[6] = (bytes[6] & 0x0f) | 0x40
bytes[8] = (bytes[8] & 0x3f) | 0x80
return [...bytes].map((b, i) =>
([4, 6, 8, 10].includes(i) ? '-' : '') + b.toString(16).padStart(2, '0')
).join('')
}
/**

View File

@@ -18,14 +18,13 @@ class ConversationsService {
return this.hashPublicKey(publicKey)
}
hashPublicKey(publicKey) {
async hashPublicKey(publicKey) {
const encoder = new TextEncoder()
const data = encoder.encode(publicKey)
return crypto.subtle.digest('SHA-256', data).then(hash => {
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('')
})
const hash = await crypto.subtle.digest('SHA-256', data)
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('')
}
async getMyConversations() {

View File

@@ -45,6 +45,7 @@ class DirectusService {
this.refreshToken = null
this.tokenExpiry = null
this.refreshTimeout = null
this._refreshPromise = null
this.loadTokens()
this.setupVisibilityRefresh()
@@ -153,15 +154,17 @@ class DirectusService {
headers
})
// Token expired - try refresh (but not for auth endpoints)
if (response.status === 401 && this.refreshToken && !endpoint.startsWith('/auth/')) {
const refreshed = await this.refreshSession()
if (refreshed) {
return this.request(endpoint, options)
} else {
this.clearTokens()
return this.request(endpoint, options)
if (response.status === 401 && this.refreshToken && !endpoint.startsWith('/auth/') && _retryCount < 1) {
if (!this._refreshPromise) {
this._refreshPromise = this.refreshSession().finally(() => {
this._refreshPromise = null
})
}
const refreshed = await this._refreshPromise
if (!refreshed) {
this.clearTokens()
}
return this.request(endpoint, options, _retryCount + 1)
}
if (response.status === 429 && _retryCount < 3) {