From 328932bc7484022cb9b2de808cbf18ecd5d7f206 Mon Sep 17 00:00:00 2001 From: Justin Wind Date: Thu, 23 Feb 2023 13:49:19 -0800 Subject: [PATCH] default indieauth profile entry to https if scheme not specified --- lib/authenticator.js | 2 +- lib/session-manager.js | 13 ++++++++++-- lib/template/login-html.js | 40 +++++++++++++++++++++++++++++++++++++ test/lib/session-manager.js | 15 ++++++++++++++ 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/lib/authenticator.js b/lib/authenticator.js index c69ada9..5a4cd7d 100644 --- a/lib/authenticator.js +++ b/lib/authenticator.js @@ -86,7 +86,7 @@ class Authenticator { && this.authnEnabled.includes('pam')) { isValid = this._isValidPAMIdentifier(identifier, credential); } else { - this.logger.error(_scope, 'failed, unknown type of stored credential', { identifier, ctx }); + this.logger.error(_scope, 'failed, unknown or unsupported type of stored credential', { identifier, ctx }); } } diff --git a/lib/session-manager.js b/lib/session-manager.js index bd08eef..a0bea6a 100644 --- a/lib/session-manager.js +++ b/lib/session-manager.js @@ -124,9 +124,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.`); @@ -134,7 +136,14 @@ class SessionManager { if (this.options.authenticator.authnEnabled.includes('indieAuth') && me) { - const profile = await this.indieAuthCommunication.fetchProfile(me); + let profile; + profile = await this.indieAuthCommunication.fetchProfile(me); + if ((!profile || !profile.metadata) + && meAutoScheme) { + this.logger.debug(_scope, 'trying http fallback', { ctx }); + me.protocol = 'http'; + profile = await this.indieAuthCommunication.fetchProfile(me); + } if (!profile || !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}'.`); diff --git a/lib/template/login-html.js b/lib/template/login-html.js index 7d059e0..d6a45f5 100644 --- a/lib/template/login-html.js +++ b/lib/template/login-html.js @@ -15,6 +15,7 @@ function indieAuthSection(ctx, options) { \t\t\t\t\t\tIndieAuth \t\t\t\t\t\t \t\t\t\t\t\t +\t\t\t\t\t\t \t\t\t\t\t\t ${indieAuthBlurb} \t\t\t\t\t @@ -24,6 +25,44 @@ ${indieAuthBlurb} } +/** + * Default all URL inputs to https if scheme not specified, + * and set a flag if that happened. + * From https://aaronparecki.com/2019/05/13/2/https + */ +function indieAuthURLTrySecureFirstScript(ctx, options) { + const showIndieAuthForm = options.authnEnabled.includes('indieAuth'); + return showIndieAuthForm ? ` +` : ''; +} + const userAuthn = ['argon2', 'pam', 'DEBUG_ANY']; function userSection(ctx, options) { const userBlurb = (options.userBlurb || []).map((x) => '\t'.repeat(6) + x).join('\n'); @@ -78,6 +117,7 @@ module.exports = (ctx, options) => { }; const mainContent = [ ...(options.authenticator.loginBlurb || []), + indieAuthURLTrySecureFirstScript(ctx, htmlOptions), indieAuthSection(ctx, htmlOptions), userSection(ctx, htmlOptions), ]; diff --git a/test/lib/session-manager.js b/test/lib/session-manager.js index bf8df03..a3efeaf 100644 --- a/test/lib/session-manager.js +++ b/test/lib/session-manager.js @@ -113,6 +113,21 @@ describe('SessionManager', function () { await manager.postAdminLogin(res, ctx); assert(!res.setHeader.called); }); + it('covers profile scheme fallback', async function () { + ctx.parsedBody.me = 'https://example.com/profile'; + ctx.parsedBody.me_auto_scheme = '1'; + manager.indieAuthCommunication.fetchProfile + .onCall(0).resolves() + .onCall(1).resolves({ + metadata: { + issuer: 'https://example.com/', + authorizationEndpoint: 'https://example.com/auth', + }, + }); + await manager.postAdminLogin(res, ctx); + assert.strictEqual(res.statusCode, 302); + + }); describe('living-standard-20220212', function () { it('covers valid profile', async function () { ctx.parsedBody.me = 'https://example.com/profile'; -- 2.43.2