hash email address
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user