@proteinjs/user-server 1.8.0 → 1.9.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/generated/index.d.ts.map +1 -1
  3. package/dist/generated/index.js +3 -1
  4. package/dist/generated/index.js.map +1 -1
  5. package/dist/src/authentication/DbSessionStore.d.ts +3 -2
  6. package/dist/src/authentication/DbSessionStore.d.ts.map +1 -1
  7. package/dist/src/authentication/DbSessionStore.js +3 -2
  8. package/dist/src/authentication/DbSessionStore.js.map +1 -1
  9. package/dist/src/authentication/establishSession.d.ts +30 -0
  10. package/dist/src/authentication/establishSession.d.ts.map +1 -0
  11. package/dist/src/authentication/establishSession.js +83 -0
  12. package/dist/src/authentication/establishSession.js.map +1 -0
  13. package/dist/src/routes/devLogin.d.ts.map +1 -1
  14. package/dist/src/routes/devLogin.js +6 -12
  15. package/dist/src/routes/devLogin.js.map +1 -1
  16. package/dist/src/routes/login.d.ts.map +1 -1
  17. package/dist/src/routes/login.js +2 -3
  18. package/dist/src/routes/login.js.map +1 -1
  19. package/dist/src/routes/logout.d.ts +10 -0
  20. package/dist/src/routes/logout.d.ts.map +1 -1
  21. package/dist/src/routes/logout.js +13 -32
  22. package/dist/src/routes/logout.js.map +1 -1
  23. package/dist/src/routes/signup.d.ts +19 -0
  24. package/dist/src/routes/signup.d.ts.map +1 -0
  25. package/dist/src/routes/signup.js +102 -0
  26. package/dist/src/routes/signup.js.map +1 -0
  27. package/dist/src/routes/validateResetPasswordToken.d.ts.map +1 -1
  28. package/dist/src/routes/validateResetPasswordToken.js +5 -1
  29. package/dist/src/routes/validateResetPasswordToken.js.map +1 -1
  30. package/dist/src/services/Signup.d.ts +18 -1
  31. package/dist/src/services/Signup.d.ts.map +1 -1
  32. package/dist/src/services/Signup.js +8 -2
  33. package/dist/src/services/Signup.js.map +1 -1
  34. package/dist/test/AccountDeletion.integration.test.js +24 -16
  35. package/dist/test/AccountDeletion.integration.test.js.map +1 -1
  36. package/dist/test/DevLogin.test.js +15 -20
  37. package/dist/test/DevLogin.test.js.map +1 -1
  38. package/dist/test/LogoutRoute.test.d.ts +2 -0
  39. package/dist/test/LogoutRoute.test.d.ts.map +1 -0
  40. package/dist/test/LogoutRoute.test.js +81 -0
  41. package/dist/test/LogoutRoute.test.js.map +1 -0
  42. package/dist/test/Signup.test.js +4 -2
  43. package/dist/test/Signup.test.js.map +1 -1
  44. package/dist/test/SignupRoute.test.d.ts +2 -0
  45. package/dist/test/SignupRoute.test.d.ts.map +1 -0
  46. package/dist/test/SignupRoute.test.js +338 -0
  47. package/dist/test/SignupRoute.test.js.map +1 -0
  48. package/dist/test/ValidateResetToken.test.d.ts +2 -0
  49. package/dist/test/ValidateResetToken.test.d.ts.map +1 -0
  50. package/dist/test/ValidateResetToken.test.js +170 -0
  51. package/dist/test/ValidateResetToken.test.js.map +1 -0
  52. package/dist/test/passportSessionHarness.d.ts +31 -0
  53. package/dist/test/passportSessionHarness.d.ts.map +1 -0
  54. package/dist/test/passportSessionHarness.js +107 -0
  55. package/dist/test/passportSessionHarness.js.map +1 -0
  56. package/generated/index.ts +3 -1
  57. package/package.json +6 -4
  58. package/src/authentication/DbSessionStore.ts +3 -2
  59. package/src/authentication/establishSession.ts +33 -0
  60. package/src/routes/devLogin.ts +4 -6
  61. package/src/routes/login.ts +2 -3
  62. package/src/routes/logout.ts +13 -18
  63. package/src/routes/signup.ts +55 -0
  64. package/src/routes/validateResetPasswordToken.ts +5 -1
  65. package/src/services/Signup.ts +21 -2
  66. package/test/AccountDeletion.integration.test.ts +15 -11
  67. package/test/DevLogin.test.ts +11 -14
  68. package/test/LogoutRoute.test.ts +33 -0
  69. package/test/Signup.test.ts +4 -2
  70. package/test/SignupRoute.test.ts +219 -0
  71. package/test/ValidateResetToken.test.ts +86 -0
  72. package/test/passportSessionHarness.ts +58 -0
@@ -0,0 +1,338 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ var moment_1 = __importDefault(require("moment"));
43
+ /**
44
+ * `POST /user/signup` — signup with auto-login. Signup used to be an RPC service, and services
45
+ * never see the request, so the client was bounced to the login form to type the credentials it
46
+ * had JUST submitted. Session establishment is a request-level concern; signup now lives at the
47
+ * route layer beside its siblings (login, dev login) and mints the session through the same
48
+ * single owner (`establishSession`) in the same request.
49
+ *
50
+ * Covered here, outcomes only (rows written, session minted), against the Spanner emulator:
51
+ * - plain signup: account row created, session established in the same request;
52
+ * - invited signup: email resolved from the invite, invite consumed, session established;
53
+ * - already-registered email: response body indistinguishable from success, but NO session —
54
+ * auto-login must never hand out a session for an account the caller didn't just create;
55
+ * - invalid token / invite-only violations: honest error, no session, no account row.
56
+ *
57
+ * The email transport is stubbed at the module boundary (SignupInvite.test.ts pattern); the db
58
+ * stays real.
59
+ */
60
+ var sendEmail = jest.fn();
61
+ jest.mock('@proteinjs/email-server', function () { return ({
62
+ EmailSender: jest.fn().mockImplementation(function () { return ({ sendEmail: sendEmail }); }),
63
+ getDefaultInviteEmailConfigFactory: function () { return ({
64
+ getConfig: function () { return ({ getEmailContent: function () { return ({ text: 'invite', html: '<p>invite</p>' }); } }); },
65
+ }); },
66
+ getDefaultSignupConfirmationEmailConfigFactory: function () { return ({
67
+ getConfig: function () { return ({
68
+ getNewUserEmailContent: function () { return ({ text: 'welcome', html: '<p>welcome</p>' }); },
69
+ getExistingUserEmailContent: function () { return ({ text: 'exists', html: '<p>exists</p>' }); },
70
+ }); },
71
+ }); },
72
+ }); });
73
+ var db_1 = require("@proteinjs/db");
74
+ var reflection_1 = require("@proteinjs/reflection");
75
+ var user_1 = require("@proteinjs/user");
76
+ var signup_1 = require("../src/routes/signup");
77
+ var passportSessionHarness_1 = require("./passportSessionHarness");
78
+ var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
79
+ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
80
+ var INVITE_CONFIG_KEY = '@proteinjs/user-server/DefaultInviteConfigFactory';
81
+ /** Seed the invite-config lookup (tests don't load the generated source graph). */
82
+ var setInviteConfig = function (factories) {
83
+ reflection_1.SourceRepository.get().objectCache[INVITE_CONFIG_KEY] = factories;
84
+ };
85
+ var invokeSignup = function (body) { return __awaiter(void 0, void 0, void 0, function () {
86
+ var _a, request, events, outcome, response;
87
+ var _b;
88
+ return __generator(this, function (_c) {
89
+ switch (_c.label) {
90
+ case 0: return [4 /*yield*/, (0, passportSessionHarness_1.createPassportRequest)({ body: body })];
91
+ case 1:
92
+ _a = _c.sent(), request = _a.request, events = _a.events;
93
+ outcome = { sessionEvents: events };
94
+ response = {
95
+ status: function (code) {
96
+ outcome.status = code;
97
+ return this;
98
+ },
99
+ send: function (body) {
100
+ outcome.body = body;
101
+ },
102
+ };
103
+ return [4 /*yield*/, signup_1.signup.onRequest(request, response)];
104
+ case 2:
105
+ _c.sent();
106
+ // The OUTCOME of establishment: the account email bound onto the (post-regeneration) session.
107
+ outcome.loggedInAs = (_b = request.session.passport) === null || _b === void 0 ? void 0 : _b.user;
108
+ return [2 /*return*/, outcome];
109
+ }
110
+ });
111
+ }); };
112
+ var getUserRow = function (email) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
113
+ switch (_a.label) {
114
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { email: email })];
115
+ case 1: return [2 /*return*/, _a.sent()];
116
+ }
117
+ }); }); };
118
+ var userRowCount = function (email) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
119
+ switch (_a.label) {
120
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.User, { email: email })];
121
+ case 1: return [2 /*return*/, (_a.sent()).length];
122
+ }
123
+ }); }); };
124
+ describe('signup route — auto-login after signup', function () {
125
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
126
+ return __generator(this, function (_a) {
127
+ switch (_a.label) {
128
+ case 0: return [4 /*yield*/, testEnv.beforeAll()];
129
+ case 1:
130
+ _a.sent();
131
+ setInviteConfig([]); // default config: invite optional
132
+ return [2 /*return*/];
133
+ }
134
+ });
135
+ }); }, 120000);
136
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
137
+ return __generator(this, function (_a) {
138
+ switch (_a.label) {
139
+ case 0: return [4 /*yield*/, testEnv.afterAll()];
140
+ case 1:
141
+ _a.sent();
142
+ return [2 /*return*/];
143
+ }
144
+ });
145
+ }); });
146
+ beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
147
+ var db;
148
+ return __generator(this, function (_a) {
149
+ switch (_a.label) {
150
+ case 0:
151
+ jest.clearAllMocks();
152
+ setInviteConfig([]);
153
+ db = (0, db_1.getDbAsSystem)();
154
+ return [4 /*yield*/, db.delete(user_1.tables.Invite, {})];
155
+ case 1:
156
+ _a.sent();
157
+ return [4 /*yield*/, db.delete(user_1.tables.User, {})];
158
+ case 2:
159
+ _a.sent();
160
+ return [2 /*return*/];
161
+ }
162
+ });
163
+ }); });
164
+ it('plain signup creates the account and establishes the session in the same request', function () { return __awaiter(void 0, void 0, void 0, function () {
165
+ var outcome, created;
166
+ return __generator(this, function (_a) {
167
+ switch (_a.label) {
168
+ case 0: return [4 /*yield*/, invokeSignup({
169
+ name: 'Plain Signup',
170
+ email: 'Signup.Plain@Test.local',
171
+ password: 'pw-plain-1',
172
+ })];
173
+ case 1:
174
+ outcome = _a.sent();
175
+ expect(outcome.body).toEqual({});
176
+ expect(outcome.loggedInAs).toBe('signup.plain@test.local');
177
+ // Fresh id on privilege change (fixation), then login, then commit-before-response (the
178
+ // client's follow-up navigation must never race the store write and land on /login).
179
+ expect(outcome.sessionEvents).toEqual(['regenerate', 'login', 'save']);
180
+ return [4 /*yield*/, getUserRow('signup.plain@test.local')];
181
+ case 2:
182
+ created = _a.sent();
183
+ expect(created).toBeDefined();
184
+ // At-rest contract: argon2id from the first write (the per-login-migration KDF stores
185
+ // new credentials as argon2id directly — never a legacy sha256 row).
186
+ expect(created.password).toMatch(/^\$argon2id\$/);
187
+ expect(created.password).not.toContain('pw-plain-1');
188
+ expect(created.emailVerified).toBe(false);
189
+ expect(created.roles).toEqual([]);
190
+ expect(sendEmail).toHaveBeenCalledTimes(1); // welcome email still goes out
191
+ return [2 /*return*/];
192
+ }
193
+ });
194
+ }); });
195
+ it('invited signup resolves the email from the invite, consumes it, and establishes the session', function () { return __awaiter(void 0, void 0, void 0, function () {
196
+ var db, outcome, created, _a;
197
+ return __generator(this, function (_b) {
198
+ switch (_b.label) {
199
+ case 0:
200
+ db = (0, db_1.getDbAsSystem)();
201
+ return [4 /*yield*/, db.insert(user_1.tables.Invite, {
202
+ email: 'invited@test.local',
203
+ token: 'invite-token-1',
204
+ tokenExpiresAt: (0, moment_1.default)().add(1, 'day'),
205
+ invitedBy: 'inviter-1',
206
+ })];
207
+ case 1:
208
+ _b.sent();
209
+ return [4 /*yield*/, invokeSignup({
210
+ name: 'Invited Signup',
211
+ password: 'pw-invited-1',
212
+ token: 'invite-token-1',
213
+ })];
214
+ case 2:
215
+ outcome = _b.sent();
216
+ expect(outcome.body).toEqual({});
217
+ expect(outcome.loggedInAs).toBe('invited@test.local');
218
+ expect(outcome.sessionEvents).toEqual(['regenerate', 'login', 'save']);
219
+ return [4 /*yield*/, getUserRow('invited@test.local')];
220
+ case 3:
221
+ created = _b.sent();
222
+ expect(created).toBeDefined();
223
+ expect(created.emailVerified).toBe(true); // the email came from the invite record
224
+ expect(created.invitedBy).toBe('inviter-1');
225
+ _a = expect;
226
+ return [4 /*yield*/, db.get(user_1.tables.Invite, { token: 'invite-token-1' })];
227
+ case 4:
228
+ _a.apply(void 0, [_b.sent()]).toBeUndefined();
229
+ return [2 /*return*/];
230
+ }
231
+ });
232
+ }); });
233
+ it('an already-registered email answers indistinguishably but mints NO session', function () { return __awaiter(void 0, void 0, void 0, function () {
234
+ var outcome, _a, existing;
235
+ return __generator(this, function (_b) {
236
+ switch (_b.label) {
237
+ case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Existing User', email: 'existing@test.local' })];
238
+ case 1:
239
+ _b.sent();
240
+ return [4 /*yield*/, invokeSignup({
241
+ name: 'Existing User',
242
+ email: 'existing@test.local',
243
+ password: 'pw-existing-1',
244
+ })];
245
+ case 2:
246
+ outcome = _b.sent();
247
+ // The response body must be exactly the success shape (anti-enumeration: existence is
248
+ // reported to the mailbox owner by email, never to the caller)...
249
+ expect(outcome.body).toEqual({});
250
+ // ...but auto-login must never mint a session for an account the caller didn't just create.
251
+ expect(outcome.loggedInAs).toBeUndefined();
252
+ expect(outcome.sessionEvents).toEqual([]);
253
+ _a = expect;
254
+ return [4 /*yield*/, userRowCount('existing@test.local')];
255
+ case 3:
256
+ _a.apply(void 0, [_b.sent()]).toBe(1);
257
+ return [4 /*yield*/, getUserRow('existing@test.local')];
258
+ case 4:
259
+ existing = _b.sent();
260
+ expect(existing.password).toBe('test'); // untouched — seeded by testEnv.createUser
261
+ expect(sendEmail).toHaveBeenCalledTimes(1); // "account already exists" email
262
+ return [2 /*return*/];
263
+ }
264
+ });
265
+ }); });
266
+ it('an unknown invite token gets the honest error — no session, no account', function () { return __awaiter(void 0, void 0, void 0, function () {
267
+ var outcome, _a;
268
+ var _b;
269
+ return __generator(this, function (_c) {
270
+ switch (_c.label) {
271
+ case 0: return [4 /*yield*/, invokeSignup({
272
+ name: 'Token Guess',
273
+ password: 'pw-guess-1',
274
+ token: 'never-existed',
275
+ })];
276
+ case 1:
277
+ outcome = _c.sent();
278
+ expect((_b = outcome.body) === null || _b === void 0 ? void 0 : _b.error).toMatch(/no longer valid/i);
279
+ expect(outcome.loggedInAs).toBeUndefined();
280
+ expect(outcome.sessionEvents).toEqual([]);
281
+ _a = expect;
282
+ return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.User, {})];
283
+ case 2:
284
+ _a.apply(void 0, [(_c.sent()).length]).toBe(0);
285
+ return [2 /*return*/];
286
+ }
287
+ });
288
+ }); });
289
+ it('invite-only mode refuses a tokenless signup — no session, no account', function () { return __awaiter(void 0, void 0, void 0, function () {
290
+ var outcome, _a;
291
+ var _b;
292
+ return __generator(this, function (_c) {
293
+ switch (_c.label) {
294
+ case 0:
295
+ setInviteConfig([{ getConfig: function () { return ({ isInviteOnly: true }); } }]);
296
+ return [4 /*yield*/, invokeSignup({
297
+ name: 'No Invite',
298
+ email: 'no.invite@test.local',
299
+ password: 'pw-noinvite-1',
300
+ })];
301
+ case 1:
302
+ outcome = _c.sent();
303
+ expect((_b = outcome.body) === null || _b === void 0 ? void 0 : _b.error).toMatch(/invite is required/i);
304
+ expect(outcome.loggedInAs).toBeUndefined();
305
+ expect(outcome.sessionEvents).toEqual([]);
306
+ _a = expect;
307
+ return [4 /*yield*/, getUserRow('no.invite@test.local')];
308
+ case 2:
309
+ _a.apply(void 0, [_c.sent()]).toBeUndefined();
310
+ return [2 /*return*/];
311
+ }
312
+ });
313
+ }); });
314
+ it('a blank name or password is refused before any write', function () { return __awaiter(void 0, void 0, void 0, function () {
315
+ var missingName, missingPassword, _a;
316
+ var _b, _c;
317
+ return __generator(this, function (_d) {
318
+ switch (_d.label) {
319
+ case 0: return [4 /*yield*/, invokeSignup({ email: 'blank@test.local', password: 'pw-blank-1' })];
320
+ case 1:
321
+ missingName = _d.sent();
322
+ expect((_b = missingName.body) === null || _b === void 0 ? void 0 : _b.error).toBeTruthy();
323
+ expect(missingName.sessionEvents).toEqual([]);
324
+ return [4 /*yield*/, invokeSignup({ name: 'Blank', email: 'blank@test.local' })];
325
+ case 2:
326
+ missingPassword = _d.sent();
327
+ expect((_c = missingPassword.body) === null || _c === void 0 ? void 0 : _c.error).toBeTruthy();
328
+ expect(missingPassword.sessionEvents).toEqual([]);
329
+ _a = expect;
330
+ return [4 /*yield*/, getUserRow('blank@test.local')];
331
+ case 3:
332
+ _a.apply(void 0, [_d.sent()]).toBeUndefined();
333
+ return [2 /*return*/];
334
+ }
335
+ });
336
+ }); });
337
+ });
338
+ //# sourceMappingURL=SignupRoute.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignupRoute.test.js","sourceRoot":"","sources":["../../test/SignupRoute.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ValidateResetToken.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidateResetToken.test.d.ts","sourceRoot":"","sources":["../../test/ValidateResetToken.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ var moment_1 = __importDefault(require("moment"));
43
+ var db_1 = require("@proteinjs/db");
44
+ var user_1 = require("@proteinjs/user");
45
+ var validateResetPasswordToken_1 = require("../src/routes/validateResetPasswordToken");
46
+ var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
47
+ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
48
+ var invokeValidate = function (query) { return __awaiter(void 0, void 0, void 0, function () {
49
+ var outcome, response;
50
+ return __generator(this, function (_a) {
51
+ switch (_a.label) {
52
+ case 0:
53
+ outcome = {};
54
+ response = {
55
+ status: function (code) {
56
+ outcome.status = code;
57
+ return this;
58
+ },
59
+ send: function (body) {
60
+ outcome.body = body;
61
+ },
62
+ };
63
+ return [4 /*yield*/, validateResetPasswordToken_1.validateResetPasswordToken.onRequest({ query: query }, response)];
64
+ case 1:
65
+ _a.sent();
66
+ return [2 /*return*/, outcome];
67
+ }
68
+ });
69
+ }); };
70
+ var armResetToken = function (email, token, expiration) { return __awaiter(void 0, void 0, void 0, function () {
71
+ var user;
72
+ return __generator(this, function (_a) {
73
+ switch (_a.label) {
74
+ case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Reset User', email: email })];
75
+ case 1:
76
+ user = _a.sent();
77
+ return [4 /*yield*/, (0, db_1.getDbAsSystem)().update(user_1.tables.User, {
78
+ id: user.id,
79
+ passwordResetToken: token,
80
+ passwordResetTokenExpiration: expiration,
81
+ })];
82
+ case 2:
83
+ _a.sent();
84
+ return [2 /*return*/];
85
+ }
86
+ });
87
+ }); };
88
+ describe('validateResetPasswordToken route', function () {
89
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
90
+ return __generator(this, function (_a) {
91
+ switch (_a.label) {
92
+ case 0: return [4 /*yield*/, testEnv.beforeAll()];
93
+ case 1:
94
+ _a.sent();
95
+ return [2 /*return*/];
96
+ }
97
+ });
98
+ }); });
99
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
100
+ return __generator(this, function (_a) {
101
+ switch (_a.label) {
102
+ case 0: return [4 /*yield*/, testEnv.afterAll()];
103
+ case 1:
104
+ _a.sent();
105
+ return [2 /*return*/];
106
+ }
107
+ });
108
+ }); });
109
+ it('a valid token resolves isValid WITH the account email (the reset form identifier)', function () { return __awaiter(void 0, void 0, void 0, function () {
110
+ var outcome;
111
+ return __generator(this, function (_a) {
112
+ switch (_a.label) {
113
+ case 0: return [4 /*yield*/, armResetToken('reset-valid@test.local', 'tok-valid-1', (0, moment_1.default)().add(1, 'hour'))];
114
+ case 1:
115
+ _a.sent();
116
+ return [4 /*yield*/, invokeValidate({ token: 'tok-valid-1' })];
117
+ case 2:
118
+ outcome = _a.sent();
119
+ expect(outcome.status).toBe(200);
120
+ expect(outcome.body).toEqual({ isValid: true, email: 'reset-valid@test.local' });
121
+ return [2 /*return*/];
122
+ }
123
+ });
124
+ }); });
125
+ it('an expired token resolves invalid and leaks no email', function () { return __awaiter(void 0, void 0, void 0, function () {
126
+ var outcome;
127
+ return __generator(this, function (_a) {
128
+ switch (_a.label) {
129
+ case 0: return [4 /*yield*/, armResetToken('reset-expired@test.local', 'tok-expired-1', (0, moment_1.default)().subtract(1, 'minute'))];
130
+ case 1:
131
+ _a.sent();
132
+ return [4 /*yield*/, invokeValidate({ token: 'tok-expired-1' })];
133
+ case 2:
134
+ outcome = _a.sent();
135
+ expect(outcome.status).toBe(200);
136
+ expect(outcome.body.isValid).toBe(false);
137
+ expect(outcome.body.email).toBeUndefined();
138
+ return [2 /*return*/];
139
+ }
140
+ });
141
+ }); });
142
+ it('an unknown token resolves invalid and leaks no email', function () { return __awaiter(void 0, void 0, void 0, function () {
143
+ var outcome;
144
+ return __generator(this, function (_a) {
145
+ switch (_a.label) {
146
+ case 0: return [4 /*yield*/, invokeValidate({ token: 'tok-never-issued' })];
147
+ case 1:
148
+ outcome = _a.sent();
149
+ expect(outcome.status).toBe(200);
150
+ expect(outcome.body.isValid).toBe(false);
151
+ expect(outcome.body.email).toBeUndefined();
152
+ return [2 /*return*/];
153
+ }
154
+ });
155
+ }); });
156
+ it('a missing token is a 400', function () { return __awaiter(void 0, void 0, void 0, function () {
157
+ var outcome;
158
+ return __generator(this, function (_a) {
159
+ switch (_a.label) {
160
+ case 0: return [4 /*yield*/, invokeValidate({})];
161
+ case 1:
162
+ outcome = _a.sent();
163
+ expect(outcome.status).toBe(400);
164
+ expect(outcome.body.isValid).toBe(false);
165
+ return [2 /*return*/];
166
+ }
167
+ });
168
+ }); });
169
+ });
170
+ //# sourceMappingURL=ValidateResetToken.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidateResetToken.test.js","sourceRoot":"","sources":["../../test/ValidateResetToken.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /** Session-lifecycle events in call order — the session-establishment contract under test. */
2
+ export type SessionEvent = 'regenerate' | 'login' | 'save';
3
+ export type PassportRequest = {
4
+ /** Express-shaped request whose `login`/`logout` are REAL passport machinery. */
5
+ request: any;
6
+ /**
7
+ * 'regenerate' / 'login' / 'save' in call order. The full contract of session establishment:
8
+ * regenerate FIRST (a fresh session id on privilege change — session fixation), then the bind
9
+ * of the account onto the fresh session, then save (the row must commit before the response).
10
+ */
11
+ events: SessionEvent[];
12
+ };
13
+ /**
14
+ * Builds a request whose `request.login` / `request.logout` are the GENUINE passport 0.6
15
+ * machinery, wired through `authenticator.initialize()` — the same middleware the server runs —
16
+ * over an express-session-shaped session mock.
17
+ *
18
+ * Why real passport and not a hand-mocked `login`: since passport 0.6 (the CVE-2022-25896
19
+ * session-fixation fix), the regenerate and the commit-before-response save live INSIDE
20
+ * `request.login` (SessionManager.logIn: regenerate → serializeUser → bind → save). A mocked
21
+ * `login` would assert nothing about either — the door suites must drive the real owner to
22
+ * prove the doors inherit the contract.
23
+ *
24
+ * serializeUser mirrors @proteinjs/server's identity pass-through (the session stores the
25
+ * account email directly), instrumented to record the bind ('login') between 'regenerate' and
26
+ * 'save'. The session mock replicates the one express-session behavior passport depends on:
27
+ * `regenerate` REPLACES `request.session` with a fresh session (new id, no passport state), so
28
+ * the bind provably lands on the post-regeneration session.
29
+ */
30
+ export declare const createPassportRequest: (extra?: Record<string, unknown>) => Promise<PassportRequest>;
31
+ //# sourceMappingURL=passportSessionHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passportSessionHarness.d.ts","sourceRoot":"","sources":["../../test/passportSessionHarness.ts"],"names":[],"mappings":"AAEA,8FAA8F;AAC9F,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG;IAC5B,iFAAiF;IACjF,OAAO,EAAE,GAAG,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,qBAAqB,WAAiB,OAAO,MAAM,EAAE,OAAO,CAAC,KAAQ,QAAQ,eAAe,CAwBxG,CAAC"}