// Per-request user context. // // The web UI authenticates a user via a signed session cookie (see the // /login flow + auth middleware in server.js). The middleware stores the // resolved user object in an AsyncLocalStorage, so any code running during the // request — including the libs (config, mailer, caldav, chat) called deep in // the stack — can read the *current user* without threading it through every // function signature. Background jobs (IMAP poll, CalDAV sync) set the same // context per user while iterating, so each user's config/data is used in turn. // // This is the keystone of the multi-tenant split: config.get() reads the current // user's cfg rows, and the per-user query helpers below filter every SELECT/INSERT // by the current user, guaranteeing isolation between users. const { AsyncLocalStorage } = require('async_hooks'); const userContext = new AsyncLocalStorage(); // The current user object ({ id, username, is_admin }) or null outside a request // (e.g. during boot). Anything that needs the user id must call this and decide // how to behave when it is absent. function currentUser() { return userContext.getStore() || null; } // Convenience: the current user's id, or null when no user is set. function currentUserId() { const u = currentUser(); return u ? u.id : null; } module.exports = { userContext, currentUser, currentUserId };