2 /* eslint-disable capitalized-comments, sonarjs/no-duplicate-string, sonarjs/no-identical-functions */
6 const assert
= require('assert');
7 const sinon
= require('sinon'); // eslint-disable-line node/no-unpublished-require
9 const SessionManager
= require('../../src/session-manager');
10 const Config
= require('../../config');
11 const stubLogger
= require('../stub-logger');
13 describe('SessionManager', function () {
14 let manager
, options
, stubAuthenticator
;
17 beforeEach(function () {
18 options
= new Config('test');
21 setHeader: sinon
.stub(),
30 isValidIdentifierCredential: sinon
.stub(),
32 manager
= new SessionManager(stubLogger
, stubAuthenticator
, options
);
33 sinon
.stub(manager
.indieAuthCommunication
);
36 afterEach(function () {
40 describe('_sessionCookieSet', function () {
42 beforeEach(function () {
46 it('covers', async
function () {
47 await manager
._sessionCookieSet(res
, session
, maxAge
);
48 assert(res
.setHeader
.called
);
50 it('covers reset', async
function () {
53 await manager
._sessionCookieSet(res
, session
, maxAge
);
54 assert(res
.setHeader
.called
);
56 }); // _sessionCookieSet
58 describe('getAdminLogin', function () {
59 it('covers', async
function () {
60 await manager
.getAdminLogin(res
, ctx
);
64 describe('postAdminLogin', function () {
65 it('covers valid local', async
function () {
66 ctx
.parsedBody
.identifier
= 'user';
67 ctx
.parsedBody
.credential
= 'password';
68 manager
.authenticator
.isValidIdentifierCredential
.resolves(true);
69 await manager
.postAdminLogin(res
, ctx
);
70 assert
.strictEqual(res
.statusCode
, 302);
72 it('covers invalid local', async
function () {
73 ctx
.parsedBody
.identifier
= 'user';
74 ctx
.parsedBody
.credential
= 'password';
75 manager
.authenticator
.isValidIdentifierCredential
.resolves(false);
76 await manager
.postAdminLogin(res
, ctx
);
77 assert(!res
.setHeader
.called
);
79 it('covers valid profile', async
function () {
80 ctx
.parsedBody
.me
= 'https://example.com/profile';
81 manager
.indieAuthCommunication
.fetchProfile
.resolves({
82 authorizationEndpoint: 'https://example.com/auth',
84 await manager
.postAdminLogin(res
, ctx
);
85 assert
.strictEqual(res
.statusCode
, 302);
87 it('covers invalid profile', async
function () {
88 ctx
.parsedBody
.me
= 'not a profile';
89 manager
.indieAuthCommunication
.fetchProfile
.resolves();
90 await manager
.postAdminLogin(res
, ctx
);
91 assert(!res
.setHeader
.called
);
93 it('covers invalid profile response', async
function () {
94 ctx
.parsedBody
.me
= 'https://example.com/profile';
95 manager
.indieAuthCommunication
.fetchProfile
.resolves();
96 await manager
.postAdminLogin(res
, ctx
);
97 assert(!res
.setHeader
.called
);
99 it('covers invalid profile response endpoint', async
function () {
100 ctx
.parsedBody
.me
= 'https://example.com/profile';
101 manager
.indieAuthCommunication
.fetchProfile
.resolves({
102 authorizationEndpoint: 'not an auth endpoint',
104 await manager
.postAdminLogin(res
, ctx
);
105 assert(!res
.setHeader
.called
);
107 }); // postAdminLogin
109 describe('getAdminLogout', function () {
110 it('covers', async
function () {
111 await manager
.getAdminLogout(res
, ctx
);
113 }); // getAdminLogout
115 describe('getAdminIA', function () {
116 let state
, me
, authorizationEndpoint
;
117 beforeEach(function () {
118 state
= '4ea7e936-3427-11ec-9f4b-0025905f714a';
119 me
= 'https://example.com/profile';
120 authorizationEndpoint
= 'https://example.com/auth'
121 ctx
.cookie
= 'WSHas=sessionCookie';
122 manager
.indieAuthCommunication
.redeemProfileCode
.resolves({
125 manager
.indieAuthCommunication
.fetchProfile
.resolves({
126 authorizationEndpoint
,
128 sinon
.stub(manager
.mysteryBox
, 'unpack').resolves({
129 authorizationEndpoint
,
134 it('covers valid', async
function () {
135 ctx
.queryParams
['state'] = state
;
136 ctx
.queryParams
['code'] = 'codeCodeCode';
138 await manager
.getAdminIA(res
, ctx
);
140 assert
.strictEqual(res
.statusCode
, 302);
142 it('covers missing cookie', async
function () {
145 await manager
.getAdminIA(res
, ctx
);
147 assert(ctx
.errors
.length
);
149 it('covers invalid cookie', async
function () {
150 manager
.mysteryBox
.unpack
.restore();
151 sinon
.stub(manager
.mysteryBox
, 'unpack').rejects();
153 await manager
.getAdminIA(res
, ctx
);
155 assert(ctx
.errors
.length
);
157 it('covers mis-matched state', async
function () {
158 ctx
.queryParams
['state'] = 'incorrect-state';
159 ctx
.queryParams
['code'] = 'codeCodeCode';
161 await manager
.getAdminIA(res
, ctx
);
163 assert(ctx
.errors
.length
);
165 it('relays auth endpoint errors', async
function () {
166 ctx
.queryParams
['state'] = state
;
167 ctx
.queryParams
['code'] = 'codeCodeCode';
168 ctx
.queryParams
['error'] = 'error_code';
169 ctx
.queryParams
['error_description'] = 'something went wrong';
171 await manager
.getAdminIA(res
, ctx
);
173 assert(ctx
.errors
.length
);
175 it('covers invalid restored session', async
function () {
176 manager
.mysteryBox
.unpack
.restore();
177 sinon
.stub(manager
.mysteryBox
, 'unpack').resolves({
178 authorizationEndpoint: 'not a url',
182 ctx
.queryParams
['state'] = state
;
183 ctx
.queryParams
['code'] = 'codeCodeCode';
185 await manager
.getAdminIA(res
, ctx
);
187 assert(ctx
.errors
.length
);
189 it('covers empty profile redemption response', async
function () {
190 ctx
.queryParams
['state'] = state
;
191 ctx
.queryParams
['code'] = 'codeCodeCode';
192 manager
.indieAuthCommunication
.redeemProfileCode
.restore();
193 sinon
.stub(manager
.indieAuthCommunication
, 'redeemProfileCode').resolves();
195 await manager
.getAdminIA(res
, ctx
);
197 assert(ctx
.errors
.length
);
199 it('covers missing profile in redemption response', async
function () {
200 ctx
.queryParams
['state'] = state
;
201 ctx
.queryParams
['code'] = 'codeCodeCode';
202 manager
.indieAuthCommunication
.redeemProfileCode
.restore();
203 sinon
.stub(manager
.indieAuthCommunication
, 'redeemProfileCode').resolves({
206 await manager
.getAdminIA(res
, ctx
);
208 assert(ctx
.errors
.length
);
210 it('covers different canonical profile response', async
function () {
211 ctx
.queryParams
['state'] = state
;
212 ctx
.queryParams
['code'] = 'codeCodeCode';
213 manager
.indieAuthCommunication
.redeemProfileCode
.restore();
214 sinon
.stub(manager
.indieAuthCommunication
, 'redeemProfileCode').resolves({
215 me: 'https://different.example.com/profile',
218 await manager
.getAdminIA(res
, ctx
);
220 assert
.strictEqual(res
.statusCode
, 302);
222 it('covers different canonical profile response mis-matched endpoint', async
function () {
223 ctx
.queryParams
['state'] = state
;
224 ctx
.queryParams
['code'] = 'codeCodeCode';
225 manager
.indieAuthCommunication
.redeemProfileCode
.restore();
226 sinon
.stub(manager
.indieAuthCommunication
, 'redeemProfileCode').resolves({
227 me: 'https://different.example.com/profile',
229 manager
.indieAuthCommunication
.fetchProfile
.restore();
230 sinon
.stub(manager
.indieAuthCommunication
, 'fetchProfile').resolves({
231 authorizationEndpoint: 'https://elsewhere.example.com/auth',
234 await manager
.getAdminIA(res
, ctx
);
236 assert(ctx
.errors
.length
);
240 }); // SessionManager