@ambushsoftworks/nestjs-auth-graphql 0.17.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -0
- package/README.md +363 -1
- package/dist/auth.module.d.ts +16 -0
- package/dist/auth.module.d.ts.map +1 -1
- package/dist/auth.module.js +71 -3
- package/dist/auth.module.js.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/decorators/allow-guest-session.decorator.d.ts +3 -0
- package/dist/decorators/allow-guest-session.decorator.d.ts.map +1 -0
- package/dist/decorators/allow-guest-session.decorator.js +8 -0
- package/dist/decorators/allow-guest-session.decorator.js.map +1 -0
- package/dist/decorators/current-guest.decorator.d.ts +2 -0
- package/dist/decorators/current-guest.decorator.d.ts.map +1 -0
- package/dist/decorators/current-guest.decorator.js +7 -0
- package/dist/decorators/current-guest.decorator.js.map +1 -0
- package/dist/exceptions/email-challenge.exceptions.d.ts +8 -0
- package/dist/exceptions/email-challenge.exceptions.d.ts.map +1 -0
- package/dist/exceptions/email-challenge.exceptions.js +21 -0
- package/dist/exceptions/email-challenge.exceptions.js.map +1 -0
- package/dist/exceptions/guest-session.exceptions.d.ts +9 -0
- package/dist/exceptions/guest-session.exceptions.d.ts.map +1 -0
- package/dist/exceptions/guest-session.exceptions.js +20 -0
- package/dist/exceptions/guest-session.exceptions.js.map +1 -0
- package/dist/guards/create-auth-guard.d.ts.map +1 -1
- package/dist/guards/create-auth-guard.js +29 -1
- package/dist/guards/create-auth-guard.js.map +1 -1
- package/dist/guards/guest-session.guard.d.ts +14 -0
- package/dist/guards/guest-session.guard.d.ts.map +1 -0
- package/dist/guards/guest-session.guard.js +63 -0
- package/dist/guards/guest-session.guard.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/auth-logger.interface.d.ts +10 -1
- package/dist/interfaces/auth-logger.interface.d.ts.map +1 -1
- package/dist/interfaces/auth-logger.interface.js +9 -0
- package/dist/interfaces/auth-logger.interface.js.map +1 -1
- package/dist/interfaces/email-challenge-repository.interface.d.ts +22 -0
- package/dist/interfaces/email-challenge-repository.interface.d.ts.map +1 -0
- package/dist/interfaces/email-challenge-repository.interface.js +3 -0
- package/dist/interfaces/email-challenge-repository.interface.js.map +1 -0
- package/dist/interfaces/email-service.interface.d.ts +5 -0
- package/dist/interfaces/email-service.interface.d.ts.map +1 -1
- package/dist/interfaces/email-template-renderer.interface.d.ts +7 -0
- package/dist/interfaces/email-template-renderer.interface.d.ts.map +1 -1
- package/dist/interfaces/guest-session-repository.interface.d.ts +37 -0
- package/dist/interfaces/guest-session-repository.interface.d.ts.map +1 -0
- package/dist/interfaces/guest-session-repository.interface.js +3 -0
- package/dist/interfaces/guest-session-repository.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +2 -0
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/index.js +2 -0
- package/dist/interfaces/index.js.map +1 -1
- package/dist/repositories/in-memory-email-challenge.repository.d.ts +14 -0
- package/dist/repositories/in-memory-email-challenge.repository.d.ts.map +1 -0
- package/dist/repositories/in-memory-email-challenge.repository.js +55 -0
- package/dist/repositories/in-memory-email-challenge.repository.js.map +1 -0
- package/dist/repositories/in-memory-guest-session.repository.d.ts +18 -0
- package/dist/repositories/in-memory-guest-session.repository.d.ts.map +1 -0
- package/dist/repositories/in-memory-guest-session.repository.js +83 -0
- package/dist/repositories/in-memory-guest-session.repository.js.map +1 -0
- package/dist/services/configurable-email.service.d.ts +2 -1
- package/dist/services/configurable-email.service.d.ts.map +1 -1
- package/dist/services/configurable-email.service.js +24 -0
- package/dist/services/configurable-email.service.js.map +1 -1
- package/dist/services/default-email-template-renderer.d.ts +7 -0
- package/dist/services/default-email-template-renderer.d.ts.map +1 -1
- package/dist/services/default-email-template-renderer.js +31 -0
- package/dist/services/default-email-template-renderer.js.map +1 -1
- package/dist/services/email-challenge.service.d.ts +74 -0
- package/dist/services/email-challenge.service.d.ts.map +1 -0
- package/dist/services/email-challenge.service.js +306 -0
- package/dist/services/email-challenge.service.js.map +1 -0
- package/dist/services/guest-session.service.d.ts +80 -0
- package/dist/services/guest-session.service.d.ts.map +1 -0
- package/dist/services/guest-session.service.js +293 -0
- package/dist/services/guest-session.service.js.map +1 -0
- package/dist/services/passkey.service.d.ts.map +1 -1
- package/dist/services/passkey.service.js +8 -20
- package/dist/services/passkey.service.js.map +1 -1
- package/dist/testing/email-challenge-repository.contract.d.ts +15 -0
- package/dist/testing/email-challenge-repository.contract.d.ts.map +1 -0
- package/dist/testing/email-challenge-repository.contract.js +287 -0
- package/dist/testing/email-challenge-repository.contract.js.map +1 -0
- package/dist/testing/guest-session-repository.contract.d.ts +18 -0
- package/dist/testing/guest-session-repository.contract.d.ts.map +1 -0
- package/dist/testing/guest-session-repository.contract.js +368 -0
- package/dist/testing/guest-session-repository.contract.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +7 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/utils/rate-limit-helpers.d.ts +4 -0
- package/dist/utils/rate-limit-helpers.d.ts.map +1 -0
- package/dist/utils/rate-limit-helpers.js +20 -0
- package/dist/utils/rate-limit-helpers.js.map +1 -0
- package/examples/email-challenge/prisma-email-challenge.repository.ts +85 -0
- package/examples/email-challenge/schema.prisma +24 -0
- package/examples/guest-sessions/prisma-guest-session.repository.ts +86 -0
- package/examples/guest-sessions/schema.prisma +33 -0
- package/package.json +1 -1
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GuestSessionRepositoryContractError = void 0;
|
|
4
|
+
exports.assertGuestSessionRepositoryContract = assertGuestSessionRepositoryContract;
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
class GuestSessionRepositoryContractError extends Error {
|
|
7
|
+
constructor(check, detail, options) {
|
|
8
|
+
super(`IGuestSessionRepository contract — ${check}: ${detail}`);
|
|
9
|
+
this.name = 'GuestSessionRepositoryContractError';
|
|
10
|
+
if (options?.cause !== undefined) {
|
|
11
|
+
this.cause = options.cause;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.GuestSessionRepositoryContractError = GuestSessionRepositoryContractError;
|
|
16
|
+
const CONCURRENCY = 8;
|
|
17
|
+
async function assertGuestSessionRepositoryContract(factory, options = {}) {
|
|
18
|
+
if (options.realms !== undefined && typeof options.realms !== 'boolean') {
|
|
19
|
+
throw new TypeError(`assertGuestSessionRepositoryContract: realms must be a boolean; received ${String(options.realms)}`);
|
|
20
|
+
}
|
|
21
|
+
if (options.cleanup !== undefined && typeof options.cleanup !== 'function') {
|
|
22
|
+
throw new TypeError('assertGuestSessionRepositoryContract: cleanup must be a function');
|
|
23
|
+
}
|
|
24
|
+
const run = new ContractRun(options.realms ?? true);
|
|
25
|
+
let failure;
|
|
26
|
+
try {
|
|
27
|
+
for (const [name, check] of CHECKS) {
|
|
28
|
+
try {
|
|
29
|
+
const repository = run.track(await factory());
|
|
30
|
+
await check(repository, run, name);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof GuestSessionRepositoryContractError)
|
|
34
|
+
throw error;
|
|
35
|
+
throw new GuestSessionRepositoryContractError(name, `threw ${error instanceof Error ? `${error.name}: ${error.message}` : String(error)}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
failure = error;
|
|
41
|
+
}
|
|
42
|
+
if (options.cleanup) {
|
|
43
|
+
try {
|
|
44
|
+
await options.cleanup(run.created());
|
|
45
|
+
}
|
|
46
|
+
catch (cleanupError) {
|
|
47
|
+
if (failure instanceof GuestSessionRepositoryContractError) {
|
|
48
|
+
throw new GuestSessionRepositoryContractError('cleanup', `${failure.message} — and cleanup then threw: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`, { cause: cleanupError });
|
|
49
|
+
}
|
|
50
|
+
if (failure === undefined)
|
|
51
|
+
throw cleanupError;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (failure !== undefined)
|
|
55
|
+
throw failure;
|
|
56
|
+
}
|
|
57
|
+
class ContractRun {
|
|
58
|
+
constructor(realms) {
|
|
59
|
+
this.realms = realms;
|
|
60
|
+
this.sessionIds = new Set();
|
|
61
|
+
this.grantIds = new Set();
|
|
62
|
+
}
|
|
63
|
+
created() {
|
|
64
|
+
return { sessionIds: [...this.sessionIds], grantIds: [...this.grantIds] };
|
|
65
|
+
}
|
|
66
|
+
track(repo) {
|
|
67
|
+
return new Proxy(repo, {
|
|
68
|
+
get: (target, property, receiver) => {
|
|
69
|
+
const value = Reflect.get(target, property, receiver);
|
|
70
|
+
if (property === 'createSession') {
|
|
71
|
+
return async (session, grant) => {
|
|
72
|
+
this.sessionIds.add(session.id);
|
|
73
|
+
this.grantIds.add(grant.id);
|
|
74
|
+
return value.call(target, session, grant);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (property === 'addGrant') {
|
|
78
|
+
return async (grant) => {
|
|
79
|
+
this.grantIds.add(grant.id);
|
|
80
|
+
return value.call(target, grant);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
realm(realm) {
|
|
88
|
+
return this.realms ? realm : null;
|
|
89
|
+
}
|
|
90
|
+
session(overrides = {}) {
|
|
91
|
+
return {
|
|
92
|
+
id: (0, crypto_1.randomUUID)(),
|
|
93
|
+
tokenHash: hash(),
|
|
94
|
+
principalId: `contract-principal-${(0, crypto_1.randomUUID)()}`,
|
|
95
|
+
email: `contract-${(0, crypto_1.randomUUID)()}@example.com`,
|
|
96
|
+
realm: this.realm('contract-realm'),
|
|
97
|
+
revokedAt: null,
|
|
98
|
+
createdAt: wholeSecond(),
|
|
99
|
+
...overrides,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
grant(session, overrides = {}) {
|
|
103
|
+
return {
|
|
104
|
+
id: (0, crypto_1.randomUUID)(),
|
|
105
|
+
sessionId: session.id,
|
|
106
|
+
kind: 'contract-kind',
|
|
107
|
+
grantId: `contract-grant-${(0, crypto_1.randomUUID)()}`,
|
|
108
|
+
realm: session.realm,
|
|
109
|
+
expiresAt: new Date(wholeSecond().getTime() + 600_000),
|
|
110
|
+
revokedAt: null,
|
|
111
|
+
createdAt: wholeSecond(),
|
|
112
|
+
...overrides,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
async stored(repo, sessionOverrides = {}, grantOverrides = {}) {
|
|
116
|
+
const session = this.session(sessionOverrides);
|
|
117
|
+
const grant = this.grant(session, grantOverrides);
|
|
118
|
+
await repo.createSession(session, grant);
|
|
119
|
+
return { session, grant };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const hash = () => (0, crypto_1.randomBytes)(32).toString('hex');
|
|
123
|
+
const wholeSecond = () => new Date(Math.floor(Date.now() / 1000) * 1000);
|
|
124
|
+
function fail(check, detail) {
|
|
125
|
+
throw new GuestSessionRepositoryContractError(check, detail);
|
|
126
|
+
}
|
|
127
|
+
const sameTime = (a, b) => a === b || (a instanceof Date && b instanceof Date && Math.abs(a.getTime() - b.getTime()) < 1000);
|
|
128
|
+
const CHECKS = [
|
|
129
|
+
[
|
|
130
|
+
'a session and its grants round-trip every field',
|
|
131
|
+
async (repo, run, check) => {
|
|
132
|
+
const { session, grant } = await run.stored(repo);
|
|
133
|
+
const second = run.grant(session, { kind: 'contract-other-kind' });
|
|
134
|
+
await repo.addGrant(second);
|
|
135
|
+
const got = await repo.findSessionByTokenHash(session.tokenHash);
|
|
136
|
+
if (!got)
|
|
137
|
+
fail(check, 'findSessionByTokenHash returned null for a session just created');
|
|
138
|
+
for (const key of ['id', 'tokenHash', 'principalId', 'email', 'realm', 'revokedAt']) {
|
|
139
|
+
if (got[key] !== session[key]) {
|
|
140
|
+
fail(check, `session ${key} came back as ${JSON.stringify(got[key])}, stored ${JSON.stringify(session[key])}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (!(got.createdAt instanceof Date) || !sameTime(got.createdAt, session.createdAt)) {
|
|
144
|
+
fail(check, 'session createdAt changed, or is not a Date');
|
|
145
|
+
}
|
|
146
|
+
if (!Array.isArray(got.grants) || got.grants.length !== 2) {
|
|
147
|
+
fail(check, `the session came back with ${JSON.stringify(got.grants?.length)} grants; it has 2`);
|
|
148
|
+
}
|
|
149
|
+
for (const stored of [grant, second]) {
|
|
150
|
+
const back = got.grants.find((g) => g.id === stored.id);
|
|
151
|
+
if (!back)
|
|
152
|
+
fail(check, `grant ${stored.kind} is missing from the session`);
|
|
153
|
+
for (const key of ['sessionId', 'kind', 'grantId', 'realm', 'revokedAt']) {
|
|
154
|
+
if (back[key] !== stored[key]) {
|
|
155
|
+
fail(check, `grant ${key} came back as ${JSON.stringify(back[key])}, stored ${JSON.stringify(stored[key])}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!(back.expiresAt instanceof Date) || !sameTime(back.expiresAt, stored.expiresAt)) {
|
|
159
|
+
fail(check, 'grant expiresAt changed, or is not a Date');
|
|
160
|
+
}
|
|
161
|
+
if (!(back.createdAt instanceof Date) || !sameTime(back.createdAt, stored.createdAt)) {
|
|
162
|
+
fail(check, 'grant createdAt changed, or is not a Date');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
[
|
|
168
|
+
'a session without a realm stores null',
|
|
169
|
+
async (repo, run, check) => {
|
|
170
|
+
const { session } = await run.stored(repo, { realm: null });
|
|
171
|
+
const got = await repo.findSessionByTokenHash(session.tokenHash);
|
|
172
|
+
if (!got)
|
|
173
|
+
fail(check, 'findSessionByTokenHash returned null');
|
|
174
|
+
if (got.realm !== null || got.grants[0]?.realm !== null) {
|
|
175
|
+
fail(check, `realm came back as ${JSON.stringify(got.realm)} on the session and ` +
|
|
176
|
+
`${JSON.stringify(got.grants[0]?.realm)} on its grant; both must be null, not undefined or ''`);
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
'an unknown token or id answers null or false',
|
|
182
|
+
async (repo, _run, check) => {
|
|
183
|
+
const unknown = `unknown-${(0, crypto_1.randomUUID)()}`;
|
|
184
|
+
if ((await repo.findSessionByTokenHash(hash())) !== null)
|
|
185
|
+
fail(check, 'findSessionByTokenHash did not return null');
|
|
186
|
+
if ((await repo.rotateToken(unknown, hash(), hash())) !== false)
|
|
187
|
+
fail(check, 'rotateToken did not return false');
|
|
188
|
+
if ((await repo.revokeSession(unknown)) !== false)
|
|
189
|
+
fail(check, 'revokeSession did not return false');
|
|
190
|
+
if ((await repo.revokeGrant(unknown)) !== false)
|
|
191
|
+
fail(check, 'revokeGrant did not return false');
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
[
|
|
195
|
+
'revoked sessions, and revoked and expired grants, are still returned',
|
|
196
|
+
async (repo, run, check) => {
|
|
197
|
+
const { session, grant } = await run.stored(repo);
|
|
198
|
+
const expired = run.grant(session, { expiresAt: new Date(Date.now() - 60_000) });
|
|
199
|
+
await repo.addGrant(expired);
|
|
200
|
+
await repo.revokeGrant(grant.id);
|
|
201
|
+
await repo.revokeSession(session.id);
|
|
202
|
+
const got = await repo.findSessionByTokenHash(session.tokenHash);
|
|
203
|
+
if (!got)
|
|
204
|
+
fail(check, 'findSessionByTokenHash hid a revoked session. Return it: the package decides.');
|
|
205
|
+
if (!(got.revokedAt instanceof Date))
|
|
206
|
+
fail(check, 'revokedAt is not a Date after revokeSession');
|
|
207
|
+
const revoked = got.grants.find((g) => g.id === grant.id);
|
|
208
|
+
if (!revoked)
|
|
209
|
+
fail(check, 'a revoked grant is missing from its session');
|
|
210
|
+
if (!(revoked.revokedAt instanceof Date))
|
|
211
|
+
fail(check, "a revoked grant's revokedAt is not a Date");
|
|
212
|
+
if (!got.grants.some((g) => g.id === expired.id))
|
|
213
|
+
fail(check, 'an expired grant is missing from its session');
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
[
|
|
217
|
+
'rotateToken replaces the hash only from the current one',
|
|
218
|
+
async (repo, run, check) => {
|
|
219
|
+
const { session } = await run.stored(repo);
|
|
220
|
+
const next = hash();
|
|
221
|
+
if ((await repo.rotateToken(session.id, hash(), next)) !== false) {
|
|
222
|
+
fail(check, 'it rotated from a hash that is not the current one');
|
|
223
|
+
}
|
|
224
|
+
if ((await repo.rotateToken(session.id, session.tokenHash, next)) !== true) {
|
|
225
|
+
fail(check, 'it refused to rotate from the current hash');
|
|
226
|
+
}
|
|
227
|
+
if ((await repo.findSessionByTokenHash(session.tokenHash)) !== null) {
|
|
228
|
+
fail(check, 'the old token hash still finds the session after a rotation');
|
|
229
|
+
}
|
|
230
|
+
if ((await repo.findSessionByTokenHash(next))?.id !== session.id) {
|
|
231
|
+
fail(check, 'the new token hash does not find the session');
|
|
232
|
+
}
|
|
233
|
+
if ((await repo.rotateToken(session.id, session.tokenHash, hash())) !== false) {
|
|
234
|
+
fail(check, 'it rotated again from the hash it had just replaced');
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
[
|
|
239
|
+
'rotateToken refuses a revoked session',
|
|
240
|
+
async (repo, run, check) => {
|
|
241
|
+
const { session } = await run.stored(repo);
|
|
242
|
+
await repo.revokeSession(session.id);
|
|
243
|
+
if ((await repo.rotateToken(session.id, session.tokenHash, hash())) !== false) {
|
|
244
|
+
fail(check, 'it rotated the token of a revoked session');
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
[
|
|
249
|
+
'rotateToken applies exactly once, under concurrency',
|
|
250
|
+
async (repo, run, check) => {
|
|
251
|
+
const { session } = await run.stored(repo);
|
|
252
|
+
const candidates = Array.from({ length: CONCURRENCY }, hash);
|
|
253
|
+
const results = await Promise.all(candidates.map((next) => repo.rotateToken(session.id, session.tokenHash, next)));
|
|
254
|
+
const applied = results.filter((r) => r === true).length;
|
|
255
|
+
if (applied !== 1) {
|
|
256
|
+
fail(check, `${applied} of ${CONCURRENCY} concurrent rotations from the same hash applied; exactly one must. ` +
|
|
257
|
+
'It must be one conditional update (UPDATE … SET tokenHash = new WHERE tokenHash = old), ' +
|
|
258
|
+
'not a read then a write.');
|
|
259
|
+
}
|
|
260
|
+
const winner = candidates[results.indexOf(true)];
|
|
261
|
+
if ((await repo.findSessionByTokenHash(winner))?.id !== session.id) {
|
|
262
|
+
fail(check, 'the rotation that reported success is not the hash the session ended up with');
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
[
|
|
267
|
+
'revoking a session or a grant happens once',
|
|
268
|
+
async (repo, run, check) => {
|
|
269
|
+
const { session, grant } = await run.stored(repo);
|
|
270
|
+
if ((await repo.revokeGrant(grant.id)) !== true)
|
|
271
|
+
fail(check, 'revokeGrant refused a standing grant');
|
|
272
|
+
const grantRevokedAt = (await repo.findSessionByTokenHash(session.tokenHash))?.grants[0]?.revokedAt;
|
|
273
|
+
if ((await repo.revokeGrant(grant.id)) !== false)
|
|
274
|
+
fail(check, 'revokeGrant revoked a grant twice');
|
|
275
|
+
if ((await repo.revokeSession(session.id)) !== true)
|
|
276
|
+
fail(check, 'revokeSession refused a standing session');
|
|
277
|
+
const sessionRevokedAt = (await repo.findSessionByTokenHash(session.tokenHash))?.revokedAt;
|
|
278
|
+
if ((await repo.revokeSession(session.id)) !== false)
|
|
279
|
+
fail(check, 'revokeSession revoked a session twice');
|
|
280
|
+
const got = await repo.findSessionByTokenHash(session.tokenHash);
|
|
281
|
+
if (!sameTime(got?.revokedAt, sessionRevokedAt) || !(got?.revokedAt instanceof Date)) {
|
|
282
|
+
fail(check, "the session's revokedAt changed on the second revoke");
|
|
283
|
+
}
|
|
284
|
+
if (!sameTime(got.grants[0]?.revokedAt, grantRevokedAt) || !(got.grants[0]?.revokedAt instanceof Date)) {
|
|
285
|
+
fail(check, "the grant's revokedAt changed on the second revoke");
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
[
|
|
290
|
+
'revokeGrants is by kind, id and realm, across sessions',
|
|
291
|
+
async (repo, run, check) => {
|
|
292
|
+
const realm = run.realm('contract-realm');
|
|
293
|
+
const grantId = `contract-job-${(0, crypto_1.randomUUID)()}`;
|
|
294
|
+
const one = await run.stored(repo, {}, { grantId });
|
|
295
|
+
const two = await run.stored(repo, {}, { grantId });
|
|
296
|
+
const otherId = await run.stored(repo);
|
|
297
|
+
const otherKind = await run.stored(repo, {}, { grantId, kind: 'contract-other-kind' });
|
|
298
|
+
const standing = async (stored) => (await repo.findSessionByTokenHash(stored.session.tokenHash))?.grants.find((g) => g.id === stored.grant.id)?.revokedAt === null;
|
|
299
|
+
const count = await repo.revokeGrants({ kind: 'contract-kind', grantId, realm });
|
|
300
|
+
if (await standing(one))
|
|
301
|
+
fail(check, 'a matching grant is still standing');
|
|
302
|
+
if (await standing(two))
|
|
303
|
+
fail(check, "a matching grant in another session is still standing");
|
|
304
|
+
if (!(await standing(otherId)))
|
|
305
|
+
fail(check, 'it revoked a grant with another id');
|
|
306
|
+
if (!(await standing(otherKind)))
|
|
307
|
+
fail(check, 'it revoked a grant of another kind with the same id');
|
|
308
|
+
if (count !== 2)
|
|
309
|
+
fail(check, `it reported ${JSON.stringify(count)} revoked; 2 matched`);
|
|
310
|
+
const again = await repo.revokeGrants({ kind: 'contract-kind', grantId, realm });
|
|
311
|
+
if (again !== 0)
|
|
312
|
+
fail(check, `a second call reported ${JSON.stringify(again)} revoked; none was standing`);
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
[
|
|
316
|
+
'revokeGrants keeps realms apart, and null means no realm',
|
|
317
|
+
async (repo, run, check) => {
|
|
318
|
+
if (!run.realms)
|
|
319
|
+
return;
|
|
320
|
+
const grantId = `contract-job-${(0, crypto_1.randomUUID)()}`;
|
|
321
|
+
const inA = await run.stored(repo, { realm: 'contract-realm-a' }, { grantId });
|
|
322
|
+
const inB = await run.stored(repo, { realm: 'contract-realm-b' }, { grantId });
|
|
323
|
+
const inNone = await run.stored(repo, { realm: null }, { grantId });
|
|
324
|
+
const standing = async (stored) => (await repo.findSessionByTokenHash(stored.session.tokenHash))?.grants[0]?.revokedAt === null;
|
|
325
|
+
const none = await repo.revokeGrants({ kind: 'contract-kind', grantId, realm: null });
|
|
326
|
+
if (!(await standing(inA)) || !(await standing(inB))) {
|
|
327
|
+
fail(check, 'realm: null revoked a grant that has a realm. null means "no realm", not "any realm": ' +
|
|
328
|
+
'do not let it become `where: { realm: undefined }`.');
|
|
329
|
+
}
|
|
330
|
+
if (await standing(inNone))
|
|
331
|
+
fail(check, 'realm: null left the grant without a realm standing');
|
|
332
|
+
if (none !== 1)
|
|
333
|
+
fail(check, `realm: null reported ${JSON.stringify(none)} revoked; 1 matched`);
|
|
334
|
+
const a = await repo.revokeGrants({ kind: 'contract-kind', grantId, realm: 'contract-realm-a' });
|
|
335
|
+
if (await standing(inA))
|
|
336
|
+
fail(check, "a realm's own grant is still standing");
|
|
337
|
+
if (!(await standing(inB)))
|
|
338
|
+
fail(check, "revoking in one realm revoked another realm's grant");
|
|
339
|
+
if (a !== 1)
|
|
340
|
+
fail(check, `one realm reported ${JSON.stringify(a)} revoked; 1 matched`);
|
|
341
|
+
},
|
|
342
|
+
],
|
|
343
|
+
[
|
|
344
|
+
'deleteExpired removes expired grants and emptied sessions, and keeps the rest',
|
|
345
|
+
async (repo, run, check) => {
|
|
346
|
+
const past = new Date(Date.now() - 60_000);
|
|
347
|
+
const dead = await run.stored(repo, {}, { expiresAt: past });
|
|
348
|
+
const mixed = await run.stored(repo);
|
|
349
|
+
const mixedExpired = run.grant(mixed.session, { expiresAt: past });
|
|
350
|
+
await repo.addGrant(mixedExpired);
|
|
351
|
+
const deleted = await repo.deleteExpired();
|
|
352
|
+
if (typeof deleted !== 'number' || deleted < 2) {
|
|
353
|
+
fail(check, `deleteExpired returned ${JSON.stringify(deleted)}; at least two grants had expired`);
|
|
354
|
+
}
|
|
355
|
+
if ((await repo.findSessionByTokenHash(dead.session.tokenHash)) !== null) {
|
|
356
|
+
fail(check, 'a session whose only grant had expired survived');
|
|
357
|
+
}
|
|
358
|
+
const kept = await repo.findSessionByTokenHash(mixed.session.tokenHash);
|
|
359
|
+
if (!kept)
|
|
360
|
+
fail(check, 'a session with a live grant was deleted');
|
|
361
|
+
if (kept.grants.some((g) => g.id === mixedExpired.id))
|
|
362
|
+
fail(check, 'an expired grant survived');
|
|
363
|
+
if (!kept.grants.some((g) => g.id === mixed.grant.id))
|
|
364
|
+
fail(check, 'a live grant was deleted');
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
];
|
|
368
|
+
//# sourceMappingURL=guest-session-repository.contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guest-session-repository.contract.js","sourceRoot":"","sources":["../../src/testing/guest-session-repository.contract.ts"],"names":[],"mappings":"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"}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { assertPasskeyRepositoryContract, PasskeyRepositoryContractError, type PasskeyRepositoryContractOptions, type PasskeyContractCreatedIds, } from './passkey-repository.contract';
|
|
2
|
+
export { assertEmailChallengeRepositoryContract, EmailChallengeRepositoryContractError, type EmailChallengeRepositoryContractOptions, } from './email-challenge-repository.contract';
|
|
3
|
+
export { assertGuestSessionRepositoryContract, GuestSessionRepositoryContractError, type GuestSessionRepositoryContractOptions, type GuestSessionContractCreatedIds, } from './guest-session-repository.contract';
|
|
2
4
|
export { SoftwareAuthenticator, type CreateOptions as SoftwareAuthenticatorCreateOptions, type GetOptions as SoftwareAuthenticatorGetOptions, type SoftwareAlgorithm, } from '../test-utils/software-authenticator';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,KAAK,gCAAgC,EACrC,KAAK,yBAAyB,GAC/B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,KAAK,aAAa,IAAI,kCAAkC,EACxD,KAAK,UAAU,IAAI,+BAA+B,EAClD,KAAK,iBAAiB,GACvB,MAAM,sCAAsC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,KAAK,gCAAgC,EACrC,KAAK,yBAAyB,GAC/B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,sCAAsC,EACtC,qCAAqC,EACrC,KAAK,uCAAuC,GAC7C,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,oCAAoC,EACpC,mCAAmC,EACnC,KAAK,qCAAqC,EAC1C,KAAK,8BAA8B,GACpC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,qBAAqB,EACrB,KAAK,aAAa,IAAI,kCAAkC,EACxD,KAAK,UAAU,IAAI,+BAA+B,EAClD,KAAK,iBAAiB,GACvB,MAAM,sCAAsC,CAAC"}
|
package/dist/testing/index.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SoftwareAuthenticator = exports.PasskeyRepositoryContractError = exports.assertPasskeyRepositoryContract = void 0;
|
|
3
|
+
exports.SoftwareAuthenticator = exports.GuestSessionRepositoryContractError = exports.assertGuestSessionRepositoryContract = exports.EmailChallengeRepositoryContractError = exports.assertEmailChallengeRepositoryContract = exports.PasskeyRepositoryContractError = exports.assertPasskeyRepositoryContract = void 0;
|
|
4
4
|
var passkey_repository_contract_1 = require("./passkey-repository.contract");
|
|
5
5
|
Object.defineProperty(exports, "assertPasskeyRepositoryContract", { enumerable: true, get: function () { return passkey_repository_contract_1.assertPasskeyRepositoryContract; } });
|
|
6
6
|
Object.defineProperty(exports, "PasskeyRepositoryContractError", { enumerable: true, get: function () { return passkey_repository_contract_1.PasskeyRepositoryContractError; } });
|
|
7
|
+
var email_challenge_repository_contract_1 = require("./email-challenge-repository.contract");
|
|
8
|
+
Object.defineProperty(exports, "assertEmailChallengeRepositoryContract", { enumerable: true, get: function () { return email_challenge_repository_contract_1.assertEmailChallengeRepositoryContract; } });
|
|
9
|
+
Object.defineProperty(exports, "EmailChallengeRepositoryContractError", { enumerable: true, get: function () { return email_challenge_repository_contract_1.EmailChallengeRepositoryContractError; } });
|
|
10
|
+
var guest_session_repository_contract_1 = require("./guest-session-repository.contract");
|
|
11
|
+
Object.defineProperty(exports, "assertGuestSessionRepositoryContract", { enumerable: true, get: function () { return guest_session_repository_contract_1.assertGuestSessionRepositoryContract; } });
|
|
12
|
+
Object.defineProperty(exports, "GuestSessionRepositoryContractError", { enumerable: true, get: function () { return guest_session_repository_contract_1.GuestSessionRepositoryContractError; } });
|
|
7
13
|
var software_authenticator_1 = require("../test-utils/software-authenticator");
|
|
8
14
|
Object.defineProperty(exports, "SoftwareAuthenticator", { enumerable: true, get: function () { return software_authenticator_1.SoftwareAuthenticator; } });
|
|
9
15
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";;;AAMA,6EAKuC;AAJrC,8IAAA,+BAA+B,OAAA;AAC/B,6IAAA,8BAA8B,OAAA;AAIhC,+EAK8C;AAJ5C,+HAAA,qBAAqB,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";;;AAMA,6EAKuC;AAJrC,8IAAA,+BAA+B,OAAA;AAC/B,6IAAA,8BAA8B,OAAA;AAIhC,6FAI+C;AAH7C,6JAAA,sCAAsC,OAAA;AACtC,4JAAA,qCAAqC,OAAA;AAGvC,yFAK6C;AAJ3C,yJAAA,oCAAoC,OAAA;AACpC,wJAAA,mCAAmC,OAAA;AAIrC,+EAK8C;AAJ5C,+HAAA,qBAAqB,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/rate-limit-helpers.ts"],"names":[],"mappings":"AAGA,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAEvD;AAGD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEhE;AAGD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMrD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.retryAfterSeconds = retryAfterSeconds;
|
|
4
|
+
exports.realmKeyPrefix = realmKeyPrefix;
|
|
5
|
+
exports.normaliseEmail = normaliseEmail;
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
function retryAfterSeconds(resetAt) {
|
|
8
|
+
return Math.max(1, Math.ceil((resetAt.getTime() - Date.now()) / 1000));
|
|
9
|
+
}
|
|
10
|
+
function realmKeyPrefix(realm) {
|
|
11
|
+
return realm ? `${realm}:` : '';
|
|
12
|
+
}
|
|
13
|
+
function normaliseEmail(email) {
|
|
14
|
+
const normalised = typeof email === 'string' ? email.trim().toLowerCase() : '';
|
|
15
|
+
if (!/^[^\s@]+@[^\s@]+$/.test(normalised)) {
|
|
16
|
+
throw new common_1.BadRequestException('A valid email address is required');
|
|
17
|
+
}
|
|
18
|
+
return normalised;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=rate-limit-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit-helpers.js","sourceRoot":"","sources":["../../src/utils/rate-limit-helpers.ts"],"names":[],"mappings":";;AAGA,8CAEC;AAGD,wCAEC;AAGD,wCAMC;AAnBD,2CAAqD;AAGrD,SAAgB,iBAAiB,CAAC,OAAa;IAC7C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AACzE,CAAC;AAGD,SAAgB,cAAc,CAAC,KAAyB;IACtD,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAClC,CAAC;AAGD,SAAgB,cAAc,CAAC,KAAc;IAC3C,MAAM,UAAU,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,4BAAmB,CAAC,mCAAmC,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import {
|
|
4
|
+
EmailChallengeRecord,
|
|
5
|
+
IEmailChallengeRepository,
|
|
6
|
+
} from '@ambushsoftworks/nestjs-auth-graphql';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* IEmailChallengeRepository on Prisma, for the model in ./schema.prisma.
|
|
10
|
+
*
|
|
11
|
+
* Verified against PostgreSQL 16 with `assertEmailChallengeRepositoryContract`
|
|
12
|
+
* from `@ambushsoftworks/nestjs-auth-graphql/testing`. Run that contract
|
|
13
|
+
* against your copy, too, on your real database:
|
|
14
|
+
*
|
|
15
|
+
* await assertEmailChallengeRepositoryContract(() => new PrismaEmailChallengeRepository(prisma), {
|
|
16
|
+
* cleanup: async ({ challengeIds }) => {
|
|
17
|
+
* await prisma.emailChallenge.deleteMany({ where: { id: { in: challengeIds } } });
|
|
18
|
+
* },
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* Inject your own PrismaService in place of PrismaClient if you have one.
|
|
22
|
+
*/
|
|
23
|
+
@Injectable()
|
|
24
|
+
export class PrismaEmailChallengeRepository implements IEmailChallengeRepository {
|
|
25
|
+
constructor(private readonly prisma: PrismaClient) {}
|
|
26
|
+
|
|
27
|
+
async createChallenge(record: EmailChallengeRecord): Promise<void> {
|
|
28
|
+
await this.prisma.emailChallenge.create({
|
|
29
|
+
data: {
|
|
30
|
+
id: record.id,
|
|
31
|
+
emailHash: record.emailHash,
|
|
32
|
+
purposeHash: record.purposeHash,
|
|
33
|
+
codeHash: record.codeHash,
|
|
34
|
+
attempts: record.attempts,
|
|
35
|
+
consumedAt: record.consumedAt,
|
|
36
|
+
expiresAt: record.expiresAt,
|
|
37
|
+
createdAt: record.createdAt,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Whatever its state: the package decides what expired, consumed and exhausted mean. */
|
|
43
|
+
async findChallenge(id: string): Promise<EmailChallengeRecord | null> {
|
|
44
|
+
return this.prisma.emailChallenge.findUnique({ where: { id } });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** One conditional update: never a read followed by a write. */
|
|
48
|
+
async registerAttempt(id: string, maxAttempts: number): Promise<boolean> {
|
|
49
|
+
const { count } = await this.prisma.emailChallenge.updateMany({
|
|
50
|
+
where: { id, consumedAt: null, attempts: { lt: maxAttempts } },
|
|
51
|
+
data: { attempts: { increment: 1 } },
|
|
52
|
+
});
|
|
53
|
+
return count === 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** One conditional update: never a read followed by a write. */
|
|
57
|
+
async consumeChallenge(id: string): Promise<boolean> {
|
|
58
|
+
const { count } = await this.prisma.emailChallenge.updateMany({
|
|
59
|
+
where: { id, consumedAt: null },
|
|
60
|
+
data: { consumedAt: new Date() },
|
|
61
|
+
});
|
|
62
|
+
return count === 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async invalidateChallenges(filter: { purposeHash: string; emailHash?: string }): Promise<number> {
|
|
66
|
+
const { count } = await this.prisma.emailChallenge.updateMany({
|
|
67
|
+
where: {
|
|
68
|
+
purposeHash: filter.purposeHash,
|
|
69
|
+
// Only when given. `emailHash: undefined` would mean the same to Prisma,
|
|
70
|
+
// but spelling it out keeps the intent from depending on that.
|
|
71
|
+
...(filter.emailHash !== undefined ? { emailHash: filter.emailHash } : {}),
|
|
72
|
+
consumedAt: null,
|
|
73
|
+
},
|
|
74
|
+
data: { consumedAt: new Date() },
|
|
75
|
+
});
|
|
76
|
+
return count;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async deleteExpiredChallenges(): Promise<number> {
|
|
80
|
+
const { count } = await this.prisma.emailChallenge.deleteMany({
|
|
81
|
+
where: { expiresAt: { lt: new Date() } },
|
|
82
|
+
});
|
|
83
|
+
return count;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Reference schema for IEmailChallengeRepository, as in the README ("Email
|
|
2
|
+
// Challenges"). Verified against PostgreSQL 16 with
|
|
3
|
+
// `assertEmailChallengeRepositoryContract`.
|
|
4
|
+
//
|
|
5
|
+
// Merge this model into your schema. It has no relation to your User model, on
|
|
6
|
+
// purpose: these codes go to people who are not users.
|
|
7
|
+
//
|
|
8
|
+
// Nothing in a row is readable. The address, the purpose and the code are
|
|
9
|
+
// keyed hashes computed by the package (64 hex characters each), and the id is
|
|
10
|
+
// 43 random base64url characters.
|
|
11
|
+
|
|
12
|
+
model EmailChallenge {
|
|
13
|
+
id String @id // generated by the package, not by the database
|
|
14
|
+
emailHash String
|
|
15
|
+
purposeHash String
|
|
16
|
+
codeHash String
|
|
17
|
+
attempts Int @default(0)
|
|
18
|
+
consumedAt DateTime? // null while the code can still be used
|
|
19
|
+
expiresAt DateTime
|
|
20
|
+
createdAt DateTime
|
|
21
|
+
|
|
22
|
+
@@index([purposeHash, emailHash])
|
|
23
|
+
@@index([expiresAt])
|
|
24
|
+
}
|