'use strict'; const { canonicalizeAltaOrigin } = require('./url-policy'); const MAX_COOKIE_LENGTH = 4096; function sessionError(code, message) { const error = new Error(message); error.code = code; return error; } function validateCookie(cookie) { if ( typeof cookie !== 'string' || cookie.length === 0 || cookie.length > MAX_COOKIE_LENGTH || /[;\r\n\0]/.test(cookie) ) { throw sessionError('INVALID_SESSION_COOKIE', 'Invalid Alta session cookie'); } return cookie; } class SessionStore { #origin = null; #cookie = null; #disposed = false; establish(deploymentOrigin, cookie) { if (this.#disposed) { throw sessionError('SESSION_STORE_DISPOSED', 'Alta session store is disposed'); } // Validate the complete replacement before dropping the current session. const nextOrigin = canonicalizeAltaOrigin(deploymentOrigin); const nextCookie = validateCookie(cookie); this.#origin = nextOrigin; this.#cookie = nextCookie; return this.describe(); } setSession(deploymentOrigin, cookie) { return this.establish(deploymentOrigin, cookie); } requireSession() { if (this.#disposed || this.#origin === null || this.#cookie === null) { throw sessionError('NO_ALTA_SESSION', 'No active Alta session'); } return Object.freeze({ origin: this.#origin, cookie: this.#cookie }); } describe() { return Object.freeze({ connected: !this.#disposed && this.#origin !== null && this.#cookie !== null, origin: !this.#disposed ? this.#origin : null, }); } clear() { this.#cookie = null; this.#origin = null; } dispose() { this.clear(); this.#disposed = true; } } function createSessionStore() { return new SessionStore(); } module.exports = { MAX_COOKIE_LENGTH, SessionStore, createSessionStore, validateCookie, };