// ── Shared trusted-device establishment ──────────────────────────────────── // // One place that mints + persists a trusted device, enforces the per-user cap // (no silent pruning), and audit-logs it. Reused by every path that can create a // trust: web /auth/login/totp, mobile /auth/mobile/login, and the authenticated // self-service POST /auth/me/trusted-devices (the "revoke one, then retry" path // after a cap-reached prompt). // // The caller decides how the returned trust token reaches the client: the web // paths set the httpOnly rg_trust cookie (setTrustCookie); native paths return the // token in the JSON body for EncryptedSharedPreferences. This helper never touches // res, so it stays surface-agnostic. const trustedDevices = require('../../../model/trustedDevices/trustedDevices.model') const activity = require('../../../model/activity/activity.model') const sessionService = require('../../../auth/session.service') const log = require('../../../utils/logger')('trusted-device') // Attempt to trust the current device for `user`. Returns: // { ok: true, trustToken } — trusted; caller delivers the token // { ok: false, capReached: true, devices } — at the cap; caller prompts to revoke // `platform` is 'web' | 'mobile'; `deviceName` is the optional friendly label. async function establishTrust(req, user, { platform = 'web', deviceName = null } = {}) { if (await sessionService.trustDeviceCapReached(user.id)) { const devices = await trustedDevices.listActiveForUser(user.id) log.info('trust refused — device cap reached', { userId: user.id, platform }) return { ok: false, capReached: true, devices } } const meta = sessionService.sessionMeta(req) const out = sessionService.mintTrustToken(meta) await trustedDevices.store({ userId: user.id, tokenHash: out.trustHash, platform, deviceName, deviceHash: out.deviceHash, userAgent: out.userAgent, expiresAt: out.expiresAt, }) await activity.log({ req, userId: user.id, action: 'account.trusted_device.add', detail: { platform } }) log.info('device trusted', { userId: user.id, platform }) return { ok: true, trustToken: out.trustToken } } module.exports = { establishTrust }