4 const assert
= require('assert');
5 const sinon
= require('sinon'); // eslint-disable-line node/no-unpublished-require
6 const { ResourceAuthenticator
, ResourceAuthenticatorError
} = require('../../lib/resource-authenticator');
7 const Enum
= require('../../lib/enum');
8 const { ResponseError
} = require('../../lib/errors');
9 const StubLogger
= require('../stub-logger');
10 const StubDb
= require('../stub-db');
12 const noExpectedException
= 'did not receive expected exception';
14 describe('Resource Authenticator', function () {
15 let stubLogger
, stubDb
;
18 beforeEach(function () {
19 stubLogger
= new StubLogger();
21 stubDb
= new StubDb();
24 ra
= new ResourceAuthenticator(stubLogger
, stubDb
, options
);
26 getHeader: sinon
.stub(),
29 setHeader: sinon
.stub(),
38 afterEach(function () {
42 it('covers no options', function () {
43 ra
= new ResourceAuthenticator(stubLogger
, stubDb
);
46 describe('required', function () {
48 const validBearerHeader
= 'Bearer bq7ZSLHkEeyakQAlkF9xSg:1648836029:xxxxx:fdUYC8Gqe0nAyX_-SWvRsPsx0UjY-vV-Ff0A52j6Zfw';
49 beforeEach(function () {
54 it('requires auth header', async
function () {
56 await ra
.required(req
, res
, ctx
);
57 assert
.fail(noExpectedException
);
59 assert(e
instanceof ResponseError
, noExpectedException
);
60 assert
.strictEqual(e
.statusCode
, 401);
63 it('requires bearer token', async
function () {
64 req
.getHeader
.returns('Basic Zm9vcABiYXJr');
66 await ra
.required(req
, res
, ctx
);
67 assert
.fail(noExpectedException
);
69 assert(e
instanceof ResponseError
, noExpectedException
);
70 assert
.strictEqual(e
.statusCode
, 401);
73 it('requires proper bearer token', async
function () {
74 req
.getHeader
.returns('Bearer Zm9vcABiYXJr');
76 await ra
.required(req
, res
, ctx
);
77 assert
.fail(noExpectedException
);
79 assert(e
instanceof ResponseError
, noExpectedException
);
80 assert
.strictEqual(e
.statusCode
, 401);
83 it('requires identifier to exist', async
function () {
84 req
.getHeader
.returns(validBearerHeader
);
86 await ra
.required(req
, res
, ctx
);
87 assert
.fail(noExpectedException
);
89 assert(e
instanceof ResponseError
, noExpectedException
);
90 assert
.strictEqual(e
.statusCode
, 401);
93 it('covers db failure', async
function () {
94 const expected
= new Error('oh no');
95 ra
.db
.resourceGet
.rejects(expected
);
96 req
.getHeader
.returns(validBearerHeader
);
98 await ra
.required(req
, res
, ctx
);
99 assert
.fail(noExpectedException
);
101 assert
.deepStrictEqual(e
, expected
, noExpectedException
);
104 it('requires timestamp within grace', async
function () {
105 sinon
.stub(ResourceAuthenticator
, 'currentEpoch').get(() => 1648838184);
106 ra
.db
.resourceGet
.resolves(resource
);
107 req
.getHeader
.returns(validBearerHeader
);
109 await ra
.required(req
, res
, ctx
);
110 assert
.fail(noExpectedException
);
112 assert(e
instanceof ResponseError
, noExpectedException
);
113 assert
.strictEqual(e
.statusCode
, 401);
116 it('requires digest to match', async
function () {
117 sinon
.stub(ResourceAuthenticator
, 'currentEpoch').get(() => 1648836031);
118 ra
.db
.resourceGet
.resolves(resource
);
119 req
.getHeader
.returns('Bearer bq7ZSLHkEeyakQAlkF9xSg:1648836029:xxxxx:invalid1M2j9wtoerc3Pqe6kRzqFrkrkwqdeYXG331Q');
121 await ra
.required(req
, res
, ctx
);
122 assert
.fail(noExpectedException
);
124 assert(e
instanceof ResponseError
, noExpectedException
);
125 assert
.strictEqual(e
.statusCode
, 401);
128 it('succeeds', async
function () {
129 sinon
.stub(ResourceAuthenticator
, 'currentEpoch').get(() => 1648836031);
130 ra
.db
.resourceGet
.resolves(resource
);
131 req
.getHeader
.returns(validBearerHeader
);
132 await ra
.required(req
, res
, ctx
);
133 assert
.strictEqual(ra
.logger
.debug
.args
[1][1], 'success');
137 describe('currentEpoch', function () {
138 it('covers', function () {
139 const now
= 1648836413503;
140 const expected
= Math
.ceil(now
/ 1000);
141 sinon
.stub(Date
, 'now').returns(now
);
142 const result
= ResourceAuthenticator
.currentEpoch
;
143 assert
.strictEqual(result
, expected
);
147 describe('getSalt', function () {
148 it('covers', async
function () {
149 const result
= await ra
.getSalt();
151 assert
.strictEqual(result
.length
, 28);
155 describe('authenticate', function () {
156 it('covers', async
function () {
157 const identifier
= '6eaed948-b1e4-11ec-9a91-0025905f714a';
158 const secret
= 'secrety';
159 sinon
.stub(ResourceAuthenticator
, 'currentEpoch').get(() => 1648836029);
160 sinon
.stub(ra
, 'getSalt').resolves('xxxxx');
161 const expected
= 'bq7ZSLHkEeyakQAlkF9xSg:1648836029:xxxxx:fdUYC8Gqe0nAyX_-SWvRsPsx0UjY-vV-Ff0A52j6Zfw';
162 const result
= await ra
.authenticate(identifier
, secret
);
163 assert
.strictEqual(result
, expected
);
167 describe('Identifier Compaction', function () {
168 it('reciprocates', function () {
169 const identifier
= '6eaed948-b1e4-11ec-9a91-0025905f714a';
170 const smaller
= ResourceAuthenticator
.ensmallenIdentifier(identifier
);
171 const bigger
= ResourceAuthenticator
.embiggenIdentifier(smaller
);
172 assert
.strictEqual(bigger
, identifier
);
174 }); // Identifier Compaction
176 describe('createDigest', function () {
178 beforeEach(function () {
181 it('creates empty digest', function () {
182 const result
= ra
.createDigest(secret
);
183 const expected
= '-eZuF5tnR65UEI-C-K3os8Jddv0wr95sOVgixTAZYWk';
184 assert
.strictEqual(result
, expected
);
186 it('creates digest', function () {
187 const result
= ra
.createDigest(secret
, 'data');
188 const expected
= 'GywWt1vSqHDBFBU8zaW8_KYzFLxyL6Fg1pDeEzzLuds';
189 assert
.strictEqual(result
, expected
);
193 describe('requestBearer', function () {
194 it('covers default response', function () {
196 ResourceAuthenticator
.requestBearer(res
);
197 assert
.fail(noExpectedException
);
199 assert(res
.setHeader
.called
);
200 assert
.strictEqual(res
.setHeader
.args
[0][0], 'WWW-Authenticate');
201 assert
.strictEqual(res
.setHeader
.args
[0][1], 'Bearer');
202 assert(e
instanceof ResponseError
, noExpectedException
);
203 assert
.strictEqual(e
.statusCode
, 401);
206 it('covers other response', function () {
208 ResourceAuthenticator
.requestBearer(res
, Enum
.ErrorResponse
.Forbidden
);
209 assert
.fail(noExpectedException
);
211 assert(res
.setHeader
.called
);
212 assert
.strictEqual(res
.setHeader
.args
[0][0], 'WWW-Authenticate');
213 assert
.strictEqual(res
.setHeader
.args
[0][1], 'Bearer');
214 assert(e
instanceof ResponseError
);
215 assert
.strictEqual(e
.statusCode
, 403);
220 describe('ResourceAuthenticatorError', function () {
221 it('covers', function () {
222 const e
= new ResourceAuthenticatorError();
223 const result
= e
.name
;
224 assert
.strictEqual(result
, 'ResourceAuthenticatorError');
228 }); // ResourceAuthenticator