hash email address

This commit is contained in:
2026-01-31 17:36:04 +01:00
parent fd89040c4a
commit aa8f7c5dab

View File

@@ -3,6 +3,7 @@
*
* No email addresses, no personal data
* User remembers only their UUID
* Email stored in Directus is hash(uuid)@domain - UUID cannot be recovered
*/
import { directus } from './directus.js'
@@ -13,6 +14,7 @@ class AuthService {
constructor() {
this.currentUser = null
this.listeners = new Set()
this.hashCache = new Map()
}
/**
@@ -20,12 +22,10 @@ class AuthService {
* @returns {string} UUID v4
*/
generateUuid() {
// Use native if available (secure contexts)
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID()
}
// Fallback for non-secure contexts
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)
@@ -34,12 +34,34 @@ class AuthService {
}
/**
* Converts UUID to fake email for Directus
* @param {string} uuid - User UUID
* @returns {string} Fake email address
* Hashes a string using SHA-256
* @param {string} str - String to hash
* @returns {Promise<string>} Hex-encoded hash
*/
uuidToEmail(uuid) {
return `${uuid}@${AUTH_DOMAIN}`
async hashString(str) {
if (this.hashCache.has(str)) {
return this.hashCache.get(str)
}
const encoder = new TextEncoder()
const data = encoder.encode(str)
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
const hashArray = Array.from(new Uint8Array(hashBuffer))
const hash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
this.hashCache.set(str, hash)
return hash
}
/**
* Converts UUID to hashed email for Directus
* The UUID cannot be recovered from the hash
* @param {string} uuid - User UUID
* @returns {Promise<string>} Hashed email address
*/
async uuidToEmail(uuid) {
const hash = await this.hashString(uuid)
return `${hash.substring(0, 32)}@${AUTH_DOMAIN}`
}
/**
@@ -48,16 +70,14 @@ class AuthService {
*/
async createAccount() {
const uuid = this.generateUuid()
const email = this.uuidToEmail(uuid)
const email = await this.uuidToEmail(uuid)
try {
await directus.register(email, uuid)
// Try auto-login (may fail if verification required)
const loginResult = await this.login(uuid)
if (!loginResult.success) {
// Registration worked but login failed (verification pending)
return {
uuid,
success: true,
@@ -83,7 +103,7 @@ class AuthService {
* @returns {Promise<{success: boolean, error?: string}>}
*/
async login(uuid) {
const email = this.uuidToEmail(uuid)
const email = await this.uuidToEmail(uuid)
try {
await directus.login(email, uuid)