fix un-awaited cookie setting
[squeep-authentication-module] / lib / session-manager.js
index a97a0e0fd3f0edf2ed897e89c9f565e41843525c..43990cc376e4ee8b16a35092c2bf81620b3a1b9a 100644 (file)
@@ -6,6 +6,7 @@
 
 const { Communication: IndieAuthCommunication } = require('@squeep/indieauth-helper');
 const { MysteryBox } = require('@squeep/mystery-box');
+const { randomUUID } = require('crypto');
 const common = require('./common');
 const Enum = require('./enum');
 const Template = require('./template');
@@ -22,15 +23,16 @@ class SessionManager {
    * @param {Number=} options.authenticator.inactiveSessionLifespanSeconds
    * @param {Boolean} options.authenticator.secureAuthOnly
    * @param {Object} options.dingus
-   * @param {Object} options.dingus.proxyPrefix
-   * @param {Object} options.dingus.selfBaseUrl
+   * @param {String} options.dingus.proxyPrefix
+   * @param {String} options.dingus.selfBaseUrl
    */
   constructor(logger, authenticator, options) {
     this.logger = logger;
     this.authenticator = authenticator;
     this.options = options;
     this.indieAuthCommunication = new IndieAuthCommunication(logger, options);
-    this.mysteryBox = new MysteryBox(logger, options);
+    this.mysteryBox = new MysteryBox(options);
+    this.mysteryBox.on('statistics', common.mysteryBoxLogger(logger, _fileScope(this.constructor.name)));
 
     this.cookieLifespan = options.authenticator.inactiveSessionLifespanSeconds || 60 * 60 * 24 * 32;
   }
@@ -51,6 +53,7 @@ class SessionManager {
     const cookieParts = [
       `${cookieName}=${secureSession}`,
       'HttpOnly',
+      'SameSite=Lax',
     ];
     if (this.options.authenticator.secureAuthOnly) {
       cookieParts.push('Secure');
@@ -123,9 +126,11 @@ class SessionManager {
     }
 
     // Otherwise, carry on with IndieAuth handshake.
-    let me, session, authorizationEndpoint;
+    let me, meAutoScheme, session, authorizationEndpoint;
     try {
       me = new URL(ctx.parsedBody['me']);
+      meAutoScheme = !!ctx.parsedBody['me_auto_scheme'];
+
     } catch (e) {
       this.logger.debug(_scope, 'failed to parse supplied profile url', { ctx });
       ctx.errors.push(`Unable to understand '${ctx.parsedBody['me']}' as a profile URL.`);
@@ -133,8 +138,15 @@ class SessionManager {
 
     if (this.options.authenticator.authnEnabled.includes('indieAuth')
     &&  me) {
-      const profile = await this.indieAuthCommunication.fetchProfile(me);
-      if (!profile || !profile.metadata) {
+      let profile;
+      profile = await this.indieAuthCommunication.fetchProfile(me);
+      if ((!profile?.metadata)
+      &&  meAutoScheme) {
+        this.logger.debug(_scope, 'trying http fallback', { ctx });
+        me.protocol = 'http';
+        profile = await this.indieAuthCommunication.fetchProfile(me);
+      }
+      if (!profile?.metadata) {
         this.logger.debug(_scope, 'failed to find any profile information at url', { ctx });
         ctx.errors.push(`No profile information was found at '${me}'.`);
       } else {
@@ -169,9 +181,10 @@ class SessionManager {
       if (authorizationEndpoint) {
         const pkce = await IndieAuthCommunication.generatePKCE();
 
+        const state = randomUUID();
         session = {
           authorizationEndpoint: authorizationEndpoint.href,
-          state: ctx.requestId,
+          state,
           codeVerifier: pkce.codeVerifier,
           me,
           redirect,
@@ -214,7 +227,7 @@ class SessionManager {
     const _scope = _fileScope('getAdminLogout');
     this.logger.debug(_scope, 'called', { ctx });
 
-    this._sessionCookieSet(res, '', 0);
+    await this._sessionCookieSet(res, '', 0);
 
     const redirect = ctx.queryParams['r'] || './';
 
@@ -345,4 +358,4 @@ class SessionManager {
 
 }
 
-module.exports = SessionManager;
\ No newline at end of file
+module.exports = SessionManager;