APP-Backend / src /services /auth-service.js
Luca448's picture
Savestate: Fix sync settings overwrite bug and persist crypto key in sessionStorage
dfd686a
Raw History Blame Contribute Delete
3.23 kB
import { supabase } from './supabase-client.js';
import { cryptoService } from './crypto-service.js';
import { db } from '../db/database.js';
class AuthService {
constructor() {
this.user = null;
this.session = null;
this.onAuthStateChangeCallbacks = [];
// Auto-setup auth listener
supabase.auth.onAuthStateChange((event, session) => {
this.session = session;
this.user = session?.user || null;
// If we log out, clear the crypto key
if (event === 'SIGNED_OUT') {
cryptoService.clearKey();
}
this.notifyListeners(event, session);
});
}
async initialize() {
const { data, error } = await supabase.auth.getSession();
if (data.session) {
this.session = data.session;
this.user = data.session.user;
// We have a session, but we don't have the crypto key!
// If the crypto key is null, the UI should prompt the user to "Unlock" their data
// by entering their password again, OR we can try to store the derived key in sessionStorage
// (not localStorage!) so it survives page reloads but dies when the tab closes.
const restored = await cryptoService.restoreKey();
if (!restored) {
// App will need to ask for password to unlock
console.warn('Session active, but crypto key missing. Needs unlock.');
}
}
return { user: this.user, session: this.session };
}
onAuthStateChange(callback) {
this.onAuthStateChangeCallbacks.push(callback);
}
notifyListeners(event, session) {
this.onAuthStateChangeCallbacks.forEach(cb => cb(event, session));
}
async signUp(email, password) {
// 1. Derive encryption key from password BEFORE signing up
await cryptoService.deriveKey(password, email);
sessionStorage.setItem('schoolmind_temp_key_marker', 'true');
// 2. Sign up with Supabase
const { data, error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
cryptoService.clearKey();
sessionStorage.removeItem('schoolmind_temp_key_marker');
throw error;
}
return data;
}
async signIn(email, password) {
// 1. Derive encryption key from password
await cryptoService.deriveKey(password, email);
sessionStorage.setItem('schoolmind_temp_key_marker', 'true');
// 2. Sign in with Supabase
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
cryptoService.clearKey();
sessionStorage.removeItem('schoolmind_temp_key_marker');
throw error;
}
return data;
}
async unlockCrypto(email, password) {
// Used when returning to an already active session, to just derive the key
await cryptoService.deriveKey(password, email);
sessionStorage.setItem('schoolmind_temp_key_marker', 'true');
return true;
}
async signOut() {
const { error } = await supabase.auth.signOut();
cryptoService.clearKey();
sessionStorage.removeItem('schoolmind_temp_key_marker');
if (error) throw error;
}
isCryptoUnlocked() {
return cryptoService.key !== null;
}
}
export const authService = new AuthService();