@proteinjs/user-server 1.7.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 (153) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/generated/index.d.ts.map +1 -1
  3. package/dist/generated/index.js +11 -1
  4. package/dist/generated/index.js.map +1 -1
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/src/authentication/DbSessionStore.d.ts +3 -2
  10. package/dist/src/authentication/DbSessionStore.d.ts.map +1 -1
  11. package/dist/src/authentication/DbSessionStore.js +3 -2
  12. package/dist/src/authentication/DbSessionStore.js.map +1 -1
  13. package/dist/src/authentication/PasswordHasher.d.ts +45 -0
  14. package/dist/src/authentication/PasswordHasher.d.ts.map +1 -0
  15. package/dist/src/authentication/PasswordHasher.js +152 -0
  16. package/dist/src/authentication/PasswordHasher.js.map +1 -0
  17. package/dist/src/authentication/UserStatusTableWatcher.d.ts +19 -0
  18. package/dist/src/authentication/UserStatusTableWatcher.d.ts.map +1 -0
  19. package/dist/src/authentication/UserStatusTableWatcher.js +115 -0
  20. package/dist/src/authentication/UserStatusTableWatcher.js.map +1 -0
  21. package/dist/src/authentication/authenticate.d.ts.map +1 -1
  22. package/dist/src/authentication/authenticate.js +41 -13
  23. package/dist/src/authentication/authenticate.js.map +1 -1
  24. package/dist/src/authentication/establishSession.d.ts +30 -0
  25. package/dist/src/authentication/establishSession.d.ts.map +1 -0
  26. package/dist/src/authentication/establishSession.js +83 -0
  27. package/dist/src/authentication/establishSession.js.map +1 -0
  28. package/dist/src/authorization/userCache.d.ts.map +1 -1
  29. package/dist/src/authorization/userCache.js +10 -1
  30. package/dist/src/authorization/userCache.js.map +1 -1
  31. package/dist/src/emails/AccountDeletionEmailConfigs.d.ts +35 -0
  32. package/dist/src/emails/AccountDeletionEmailConfigs.d.ts.map +1 -0
  33. package/dist/src/emails/AccountDeletionEmailConfigs.js +36 -0
  34. package/dist/src/emails/AccountDeletionEmailConfigs.js.map +1 -0
  35. package/dist/src/emails/AccountDeletionEmails.d.ts +13 -0
  36. package/dist/src/emails/AccountDeletionEmails.d.ts.map +1 -0
  37. package/dist/src/emails/AccountDeletionEmails.js +98 -0
  38. package/dist/src/emails/AccountDeletionEmails.js.map +1 -0
  39. package/dist/src/routes/devLogin.d.ts.map +1 -1
  40. package/dist/src/routes/devLogin.js +6 -12
  41. package/dist/src/routes/devLogin.js.map +1 -1
  42. package/dist/src/routes/executePasswordReset.js +5 -3
  43. package/dist/src/routes/executePasswordReset.js.map +1 -1
  44. package/dist/src/routes/login.d.ts.map +1 -1
  45. package/dist/src/routes/login.js +27 -4
  46. package/dist/src/routes/login.js.map +1 -1
  47. package/dist/src/routes/logout.d.ts +10 -0
  48. package/dist/src/routes/logout.d.ts.map +1 -1
  49. package/dist/src/routes/logout.js +13 -32
  50. package/dist/src/routes/logout.js.map +1 -1
  51. package/dist/src/routes/signup.d.ts +19 -0
  52. package/dist/src/routes/signup.d.ts.map +1 -0
  53. package/dist/src/routes/signup.js +102 -0
  54. package/dist/src/routes/signup.js.map +1 -0
  55. package/dist/src/routes/validateResetPasswordToken.d.ts.map +1 -1
  56. package/dist/src/routes/validateResetPasswordToken.js +5 -1
  57. package/dist/src/routes/validateResetPasswordToken.js.map +1 -1
  58. package/dist/src/services/AccountDeletion.d.ts +52 -0
  59. package/dist/src/services/AccountDeletion.d.ts.map +1 -0
  60. package/dist/src/services/AccountDeletion.js +426 -0
  61. package/dist/src/services/AccountDeletion.js.map +1 -0
  62. package/dist/src/services/MachineCredentials.d.ts +21 -0
  63. package/dist/src/services/MachineCredentials.d.ts.map +1 -0
  64. package/dist/src/services/MachineCredentials.js +164 -0
  65. package/dist/src/services/MachineCredentials.js.map +1 -0
  66. package/dist/src/services/Roles.d.ts.map +1 -1
  67. package/dist/src/services/Roles.js +7 -0
  68. package/dist/src/services/Roles.js.map +1 -1
  69. package/dist/src/services/SetUserStatus.d.ts +18 -0
  70. package/dist/src/services/SetUserStatus.d.ts.map +1 -0
  71. package/dist/src/services/SetUserStatus.js +118 -0
  72. package/dist/src/services/SetUserStatus.js.map +1 -0
  73. package/dist/src/services/Signup.d.ts +20 -3
  74. package/dist/src/services/Signup.d.ts.map +1 -1
  75. package/dist/src/services/Signup.js +30 -19
  76. package/dist/src/services/Signup.js.map +1 -1
  77. package/dist/src/services/UpdateUserInfo.d.ts.map +1 -1
  78. package/dist/src/services/UpdateUserInfo.js +20 -17
  79. package/dist/src/services/UpdateUserInfo.js.map +1 -1
  80. package/dist/test/AccountDeletion.integration.test.d.ts +2 -0
  81. package/dist/test/AccountDeletion.integration.test.d.ts.map +1 -0
  82. package/dist/test/AccountDeletion.integration.test.js +718 -0
  83. package/dist/test/AccountDeletion.integration.test.js.map +1 -0
  84. package/dist/test/DevLogin.test.js +27 -31
  85. package/dist/test/DevLogin.test.js.map +1 -1
  86. package/dist/test/LogoutRoute.test.d.ts +2 -0
  87. package/dist/test/LogoutRoute.test.d.ts.map +1 -0
  88. package/dist/test/LogoutRoute.test.js +81 -0
  89. package/dist/test/LogoutRoute.test.js.map +1 -0
  90. package/dist/test/MachineAccounts.integration.test.d.ts +2 -0
  91. package/dist/test/MachineAccounts.integration.test.d.ts.map +1 -0
  92. package/dist/test/MachineAccounts.integration.test.js +597 -0
  93. package/dist/test/MachineAccounts.integration.test.js.map +1 -0
  94. package/dist/test/PasswordMigration.integration.test.d.ts +2 -0
  95. package/dist/test/PasswordMigration.integration.test.d.ts.map +1 -0
  96. package/dist/test/PasswordMigration.integration.test.js +332 -0
  97. package/dist/test/PasswordMigration.integration.test.js.map +1 -0
  98. package/dist/test/SetUserStatus.integration.test.d.ts +2 -0
  99. package/dist/test/SetUserStatus.integration.test.d.ts.map +1 -0
  100. package/dist/test/SetUserStatus.integration.test.js +266 -0
  101. package/dist/test/SetUserStatus.integration.test.js.map +1 -0
  102. package/dist/test/Signup.test.js +4 -2
  103. package/dist/test/Signup.test.js.map +1 -1
  104. package/dist/test/SignupRoute.test.d.ts +2 -0
  105. package/dist/test/SignupRoute.test.d.ts.map +1 -0
  106. package/dist/test/SignupRoute.test.js +338 -0
  107. package/dist/test/SignupRoute.test.js.map +1 -0
  108. package/dist/test/UserStatusGate.integration.test.d.ts +2 -0
  109. package/dist/test/UserStatusGate.integration.test.d.ts.map +1 -0
  110. package/dist/test/UserStatusGate.integration.test.js +162 -0
  111. package/dist/test/UserStatusGate.integration.test.js.map +1 -0
  112. package/dist/test/ValidateResetToken.test.d.ts +2 -0
  113. package/dist/test/ValidateResetToken.test.d.ts.map +1 -0
  114. package/dist/test/ValidateResetToken.test.js +170 -0
  115. package/dist/test/ValidateResetToken.test.js.map +1 -0
  116. package/dist/test/passportSessionHarness.d.ts +31 -0
  117. package/dist/test/passportSessionHarness.d.ts.map +1 -0
  118. package/dist/test/passportSessionHarness.js +107 -0
  119. package/dist/test/passportSessionHarness.js.map +1 -0
  120. package/generated/index.ts +11 -1
  121. package/index.ts +3 -0
  122. package/package.json +11 -7
  123. package/src/authentication/DbSessionStore.ts +3 -2
  124. package/src/authentication/PasswordHasher.ts +87 -0
  125. package/src/authentication/UserStatusTableWatcher.ts +56 -0
  126. package/src/authentication/authenticate.ts +31 -6
  127. package/src/authentication/establishSession.ts +33 -0
  128. package/src/authorization/userCache.ts +9 -1
  129. package/src/emails/AccountDeletionEmailConfigs.ts +79 -0
  130. package/src/emails/AccountDeletionEmails.ts +39 -0
  131. package/src/routes/devLogin.ts +4 -6
  132. package/src/routes/executePasswordReset.ts +2 -2
  133. package/src/routes/login.ts +25 -3
  134. package/src/routes/logout.ts +13 -18
  135. package/src/routes/signup.ts +55 -0
  136. package/src/routes/validateResetPasswordToken.ts +5 -1
  137. package/src/services/AccountDeletion.ts +291 -0
  138. package/src/services/MachineCredentials.ts +94 -0
  139. package/src/services/Roles.ts +10 -0
  140. package/src/services/SetUserStatus.ts +56 -0
  141. package/src/services/Signup.ts +25 -6
  142. package/src/services/UpdateUserInfo.ts +4 -5
  143. package/test/AccountDeletion.integration.test.ts +395 -0
  144. package/test/DevLogin.test.ts +16 -18
  145. package/test/LogoutRoute.test.ts +33 -0
  146. package/test/MachineAccounts.integration.test.ts +312 -0
  147. package/test/PasswordMigration.integration.test.ts +132 -0
  148. package/test/SetUserStatus.integration.test.ts +120 -0
  149. package/test/Signup.test.ts +4 -2
  150. package/test/SignupRoute.test.ts +219 -0
  151. package/test/UserStatusGate.integration.test.ts +68 -0
  152. package/test/ValidateResetToken.test.ts +86 -0
  153. package/test/passportSessionHarness.ts +58 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SignupRoute.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignupRoute.test.d.ts","sourceRoot":"","sources":["../../test/SignupRoute.test.ts"],"names":[],"mappings":""}
@@ -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=UserStatusGate.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserStatusGate.integration.test.d.ts","sourceRoot":"","sources":["../../test/UserStatusGate.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ 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;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var sha256_1 = __importDefault(require("crypto-js/sha256"));
54
+ var db_1 = require("@proteinjs/db");
55
+ var user_1 = require("@proteinjs/user");
56
+ var authenticate_1 = require("../src/authentication/authenticate");
57
+ var userCache_1 = require("../src/authorization/userCache");
58
+ var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
59
+ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
60
+ /**
61
+ * The deactivation gate, both halves, asserted on outcomes against the emulator:
62
+ * - login half (authenticate): correct credentials on a deactivated account are refused;
63
+ * - session half (userCache): the session cache is rebuilt per request, so a live session stops
64
+ * resolving the moment its account is deactivated — requests run as the unauthenticated guest.
65
+ */
66
+ describe('user status gate — login refusal and session resolution', function () {
67
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
68
+ return __generator(this, function (_a) {
69
+ switch (_a.label) {
70
+ case 0: return [4 /*yield*/, testEnv.beforeAll()];
71
+ case 1:
72
+ _a.sent();
73
+ return [2 /*return*/];
74
+ }
75
+ });
76
+ }); }, 120000);
77
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
78
+ return __generator(this, function (_a) {
79
+ switch (_a.label) {
80
+ case 0: return [4 /*yield*/, testEnv.afterAll()];
81
+ case 1:
82
+ _a.sent();
83
+ return [2 /*return*/];
84
+ }
85
+ });
86
+ }); });
87
+ /** Insert an account the way the product stores it: lowercased email, sha256 password. */
88
+ var createAccount = function (email, password, status) { return __awaiter(void 0, void 0, void 0, function () {
89
+ return __generator(this, function (_a) {
90
+ switch (_a.label) {
91
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().insert(user_1.tables.User, __assign({ name: 'Gate test user', email: email, password: (0, sha256_1.default)(password).toString(), emailVerified: true, roles: [] }, (status ? { status: status } : {})))];
92
+ case 1: return [2 /*return*/, _a.sent()];
93
+ }
94
+ });
95
+ }); };
96
+ it('refuses login for a deactivated account even with correct credentials', function () { return __awaiter(void 0, void 0, void 0, function () {
97
+ var result;
98
+ return __generator(this, function (_a) {
99
+ switch (_a.label) {
100
+ case 0: return [4 /*yield*/, createAccount('deactivated-login@test.local', 'correct-password', 'deactivated')];
101
+ case 1:
102
+ _a.sent();
103
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('deactivated-login@test.local', 'correct-password')];
104
+ case 2:
105
+ result = _a.sent();
106
+ expect(result).toBe('This account has been deactivated');
107
+ return [2 /*return*/];
108
+ }
109
+ });
110
+ }); });
111
+ it('logs an active account in unaffected', function () { return __awaiter(void 0, void 0, void 0, function () {
112
+ var _a, _b;
113
+ return __generator(this, function (_c) {
114
+ switch (_c.label) {
115
+ case 0: return [4 /*yield*/, createAccount('active-login@test.local', 'correct-password')];
116
+ case 1:
117
+ _c.sent();
118
+ _a = expect;
119
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('active-login@test.local', 'correct-password')];
120
+ case 2:
121
+ _a.apply(void 0, [_c.sent()]).toBe(true);
122
+ _b = expect;
123
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('active-login@test.local', 'wrong-password')];
124
+ case 3:
125
+ _b.apply(void 0, [_c.sent()]).toBe('User name or password incorrect');
126
+ return [2 /*return*/];
127
+ }
128
+ });
129
+ }); });
130
+ it('stops resolving a live session once its user is deactivated, and resumes on reactivation', function () { return __awaiter(void 0, void 0, void 0, function () {
131
+ var account, before, during, after;
132
+ return __generator(this, function (_a) {
133
+ switch (_a.label) {
134
+ case 0: return [4 /*yield*/, createAccount('live-session@test.local', 'correct-password')];
135
+ case 1:
136
+ account = _a.sent();
137
+ return [4 /*yield*/, userCache_1.userCache.create('live-session', 'live-session@test.local')];
138
+ case 2:
139
+ before = _a.sent();
140
+ expect(before.id).toBe(account.id);
141
+ expect(before.email).toBe('live-session@test.local');
142
+ return [4 /*yield*/, (0, db_1.getDbAsSystem)().update(user_1.tables.User, { id: account.id, status: 'deactivated' })];
143
+ case 3:
144
+ _a.sent();
145
+ return [4 /*yield*/, userCache_1.userCache.create('live-session', 'live-session@test.local')];
146
+ case 4:
147
+ during = _a.sent();
148
+ expect(during.id).toBe('guest');
149
+ expect(during.roles).toEqual([]);
150
+ return [4 /*yield*/, (0, db_1.getDbAsSystem)().update(user_1.tables.User, { id: account.id, status: 'active' })];
151
+ case 5:
152
+ _a.sent();
153
+ return [4 /*yield*/, userCache_1.userCache.create('live-session', 'live-session@test.local')];
154
+ case 6:
155
+ after = _a.sent();
156
+ expect(after.id).toBe(account.id);
157
+ return [2 /*return*/];
158
+ }
159
+ });
160
+ }); });
161
+ });
162
+ //# sourceMappingURL=UserStatusGate.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserStatusGate.integration.test.js","sourceRoot":"","sources":["../../test/UserStatusGate.integration.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":""}