@proteinjs/user-server 1.7.0 → 1.8.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 (102) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/generated/index.d.ts.map +1 -1
  3. package/dist/generated/index.js +9 -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/PasswordHasher.d.ts +45 -0
  10. package/dist/src/authentication/PasswordHasher.d.ts.map +1 -0
  11. package/dist/src/authentication/PasswordHasher.js +152 -0
  12. package/dist/src/authentication/PasswordHasher.js.map +1 -0
  13. package/dist/src/authentication/UserStatusTableWatcher.d.ts +19 -0
  14. package/dist/src/authentication/UserStatusTableWatcher.d.ts.map +1 -0
  15. package/dist/src/authentication/UserStatusTableWatcher.js +115 -0
  16. package/dist/src/authentication/UserStatusTableWatcher.js.map +1 -0
  17. package/dist/src/authentication/authenticate.d.ts.map +1 -1
  18. package/dist/src/authentication/authenticate.js +41 -13
  19. package/dist/src/authentication/authenticate.js.map +1 -1
  20. package/dist/src/authorization/userCache.d.ts.map +1 -1
  21. package/dist/src/authorization/userCache.js +10 -1
  22. package/dist/src/authorization/userCache.js.map +1 -1
  23. package/dist/src/emails/AccountDeletionEmailConfigs.d.ts +35 -0
  24. package/dist/src/emails/AccountDeletionEmailConfigs.d.ts.map +1 -0
  25. package/dist/src/emails/AccountDeletionEmailConfigs.js +36 -0
  26. package/dist/src/emails/AccountDeletionEmailConfigs.js.map +1 -0
  27. package/dist/src/emails/AccountDeletionEmails.d.ts +13 -0
  28. package/dist/src/emails/AccountDeletionEmails.d.ts.map +1 -0
  29. package/dist/src/emails/AccountDeletionEmails.js +98 -0
  30. package/dist/src/emails/AccountDeletionEmails.js.map +1 -0
  31. package/dist/src/routes/executePasswordReset.js +5 -3
  32. package/dist/src/routes/executePasswordReset.js.map +1 -1
  33. package/dist/src/routes/login.d.ts.map +1 -1
  34. package/dist/src/routes/login.js +26 -2
  35. package/dist/src/routes/login.js.map +1 -1
  36. package/dist/src/services/AccountDeletion.d.ts +52 -0
  37. package/dist/src/services/AccountDeletion.d.ts.map +1 -0
  38. package/dist/src/services/AccountDeletion.js +426 -0
  39. package/dist/src/services/AccountDeletion.js.map +1 -0
  40. package/dist/src/services/MachineCredentials.d.ts +21 -0
  41. package/dist/src/services/MachineCredentials.d.ts.map +1 -0
  42. package/dist/src/services/MachineCredentials.js +164 -0
  43. package/dist/src/services/MachineCredentials.js.map +1 -0
  44. package/dist/src/services/Roles.d.ts.map +1 -1
  45. package/dist/src/services/Roles.js +7 -0
  46. package/dist/src/services/Roles.js.map +1 -1
  47. package/dist/src/services/SetUserStatus.d.ts +18 -0
  48. package/dist/src/services/SetUserStatus.d.ts.map +1 -0
  49. package/dist/src/services/SetUserStatus.js +118 -0
  50. package/dist/src/services/SetUserStatus.js.map +1 -0
  51. package/dist/src/services/Signup.d.ts +2 -2
  52. package/dist/src/services/Signup.d.ts.map +1 -1
  53. package/dist/src/services/Signup.js +22 -17
  54. package/dist/src/services/Signup.js.map +1 -1
  55. package/dist/src/services/UpdateUserInfo.d.ts.map +1 -1
  56. package/dist/src/services/UpdateUserInfo.js +20 -17
  57. package/dist/src/services/UpdateUserInfo.js.map +1 -1
  58. package/dist/test/AccountDeletion.integration.test.d.ts +2 -0
  59. package/dist/test/AccountDeletion.integration.test.d.ts.map +1 -0
  60. package/dist/test/AccountDeletion.integration.test.js +710 -0
  61. package/dist/test/AccountDeletion.integration.test.js.map +1 -0
  62. package/dist/test/DevLogin.test.js +12 -11
  63. package/dist/test/DevLogin.test.js.map +1 -1
  64. package/dist/test/MachineAccounts.integration.test.d.ts +2 -0
  65. package/dist/test/MachineAccounts.integration.test.d.ts.map +1 -0
  66. package/dist/test/MachineAccounts.integration.test.js +597 -0
  67. package/dist/test/MachineAccounts.integration.test.js.map +1 -0
  68. package/dist/test/PasswordMigration.integration.test.d.ts +2 -0
  69. package/dist/test/PasswordMigration.integration.test.d.ts.map +1 -0
  70. package/dist/test/PasswordMigration.integration.test.js +332 -0
  71. package/dist/test/PasswordMigration.integration.test.js.map +1 -0
  72. package/dist/test/SetUserStatus.integration.test.d.ts +2 -0
  73. package/dist/test/SetUserStatus.integration.test.d.ts.map +1 -0
  74. package/dist/test/SetUserStatus.integration.test.js +266 -0
  75. package/dist/test/SetUserStatus.integration.test.js.map +1 -0
  76. package/dist/test/UserStatusGate.integration.test.d.ts +2 -0
  77. package/dist/test/UserStatusGate.integration.test.d.ts.map +1 -0
  78. package/dist/test/UserStatusGate.integration.test.js +162 -0
  79. package/dist/test/UserStatusGate.integration.test.js.map +1 -0
  80. package/generated/index.ts +9 -1
  81. package/index.ts +3 -0
  82. package/package.json +8 -6
  83. package/src/authentication/PasswordHasher.ts +87 -0
  84. package/src/authentication/UserStatusTableWatcher.ts +56 -0
  85. package/src/authentication/authenticate.ts +31 -6
  86. package/src/authorization/userCache.ts +9 -1
  87. package/src/emails/AccountDeletionEmailConfigs.ts +79 -0
  88. package/src/emails/AccountDeletionEmails.ts +39 -0
  89. package/src/routes/executePasswordReset.ts +2 -2
  90. package/src/routes/login.ts +23 -0
  91. package/src/services/AccountDeletion.ts +291 -0
  92. package/src/services/MachineCredentials.ts +94 -0
  93. package/src/services/Roles.ts +10 -0
  94. package/src/services/SetUserStatus.ts +56 -0
  95. package/src/services/Signup.ts +4 -4
  96. package/src/services/UpdateUserInfo.ts +4 -5
  97. package/test/AccountDeletion.integration.test.ts +391 -0
  98. package/test/DevLogin.test.ts +5 -4
  99. package/test/MachineAccounts.integration.test.ts +312 -0
  100. package/test/PasswordMigration.integration.test.ts +132 -0
  101. package/test/SetUserStatus.integration.test.ts +120 -0
  102. package/test/UserStatusGate.integration.test.ts +68 -0
@@ -0,0 +1,332 @@
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __generator = (this && this.__generator) || function (thisArg, body) {
46
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
47
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
48
+ function verb(n) { return function (v) { return step([n, v]); }; }
49
+ function step(op) {
50
+ if (f) throw new TypeError("Generator is already executing.");
51
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
52
+ 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;
53
+ if (y = 0, t) op = [op[0] & 2, t.value];
54
+ switch (op[0]) {
55
+ case 0: case 1: t = op; break;
56
+ case 4: _.label++; return { value: op[1], done: false };
57
+ case 5: _.label++; y = op[1]; op = [0]; continue;
58
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
59
+ default:
60
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
61
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
62
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
63
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
64
+ if (t[2]) _.ops.pop();
65
+ _.trys.pop(); continue;
66
+ }
67
+ op = body.call(thisArg, _);
68
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
69
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
70
+ }
71
+ };
72
+ var __importDefault = (this && this.__importDefault) || function (mod) {
73
+ return (mod && mod.__esModule) ? mod : { "default": mod };
74
+ };
75
+ Object.defineProperty(exports, "__esModule", { value: true });
76
+ var sha256_1 = __importDefault(require("crypto-js/sha256"));
77
+ var argon2 = __importStar(require("argon2"));
78
+ var moment_1 = __importDefault(require("moment"));
79
+ var db_1 = require("@proteinjs/db");
80
+ var user_1 = require("@proteinjs/user");
81
+ var authenticate_1 = require("../src/authentication/authenticate");
82
+ var PasswordHasher_1 = require("../src/authentication/PasswordHasher");
83
+ var Signup_1 = require("../src/services/Signup");
84
+ var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
85
+ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
86
+ var ARGON2ID_PREFIX = '$argon2id$';
87
+ var SHA256_HEX = /^[0-9a-f]{64}$/;
88
+ /**
89
+ * The sha256→argon2id migration: authentication queries by EMAIL ONLY and compares in code
90
+ * (query-by-hash is dead), legacy sha256 rows upgrade in place on their next successful login
91
+ * (verify-then-rehash), every password write produces only the new self-describing format, and
92
+ * machine rows (generated 256-bit secrets) stay sha256 by design — cheap per-poll verifies.
93
+ */
94
+ describe('Password KDF migration', function () {
95
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
96
+ return __generator(this, function (_a) {
97
+ switch (_a.label) {
98
+ case 0: return [4 /*yield*/, testEnv.beforeAll()];
99
+ case 1:
100
+ _a.sent();
101
+ return [2 /*return*/];
102
+ }
103
+ });
104
+ }); }, 120000);
105
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
106
+ return __generator(this, function (_a) {
107
+ switch (_a.label) {
108
+ case 0: return [4 /*yield*/, testEnv.afterAll()];
109
+ case 1:
110
+ _a.sent();
111
+ return [2 /*return*/];
112
+ }
113
+ });
114
+ }); });
115
+ beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
116
+ return __generator(this, function (_a) {
117
+ switch (_a.label) {
118
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().delete(user_1.tables.User, {})];
119
+ case 1:
120
+ _a.sent();
121
+ return [2 /*return*/];
122
+ }
123
+ });
124
+ }); });
125
+ var insertUser = function (fields) { 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*/, (0, db_1.getDbAsSystem)().insert(user_1.tables.User, __assign({ name: 'Test user', emailVerified: true, roles: [] }, fields))];
129
+ case 1: return [2 /*return*/, _a.sent()];
130
+ }
131
+ });
132
+ }); };
133
+ var userRow = function (email) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
134
+ switch (_a.label) {
135
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { email: email })];
136
+ case 1: return [2 /*return*/, _a.sent()];
137
+ }
138
+ }); }); };
139
+ it('legacy sha256 row: login succeeds and the row is upgraded in place to argon2id', function () { return __awaiter(void 0, void 0, void 0, function () {
140
+ var legacyHash, _a, upgraded, _b, _c;
141
+ return __generator(this, function (_d) {
142
+ switch (_d.label) {
143
+ case 0:
144
+ legacyHash = (0, sha256_1.default)('hunter2 was fine in 2004').toString();
145
+ return [4 /*yield*/, insertUser({ email: 'legacy@test.local', password: legacyHash })];
146
+ case 1:
147
+ _d.sent();
148
+ _a = expect;
149
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('legacy@test.local', 'hunter2 was fine in 2004')];
150
+ case 2:
151
+ _a.apply(void 0, [_d.sent()]).toBe(true);
152
+ return [4 /*yield*/, userRow('legacy@test.local')];
153
+ case 3:
154
+ upgraded = (_d.sent()).password;
155
+ expect(upgraded).not.toBe(legacyHash);
156
+ expect(upgraded.startsWith(ARGON2ID_PREFIX)).toBe(true);
157
+ return [4 /*yield*/, expect(argon2.verify(upgraded, 'hunter2 was fine in 2004')).resolves.toBe(true)];
158
+ case 4:
159
+ _d.sent();
160
+ // The migrated row logs in through the argon2 leg — and is NOT rehashed again.
161
+ _b = expect;
162
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('legacy@test.local', 'hunter2 was fine in 2004')];
163
+ case 5:
164
+ // The migrated row logs in through the argon2 leg — and is NOT rehashed again.
165
+ _b.apply(void 0, [_d.sent()]).toBe(true);
166
+ _c = expect;
167
+ return [4 /*yield*/, userRow('legacy@test.local')];
168
+ case 6:
169
+ _c.apply(void 0, [(_d.sent()).password]).toBe(upgraded);
170
+ return [2 /*return*/];
171
+ }
172
+ });
173
+ }); });
174
+ it('new-format row: login verifies against the stored encoded hash', function () { return __awaiter(void 0, void 0, void 0, function () {
175
+ var encoded, _a, _b;
176
+ return __generator(this, function (_c) {
177
+ switch (_c.label) {
178
+ case 0: return [4 /*yield*/, new PasswordHasher_1.PasswordHasher().hash('correct horse battery staple')];
179
+ case 1:
180
+ encoded = _c.sent();
181
+ return [4 /*yield*/, insertUser({ email: 'modern@test.local', password: encoded })];
182
+ case 2:
183
+ _c.sent();
184
+ _a = expect;
185
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('modern@test.local', 'correct horse battery staple')];
186
+ case 3:
187
+ _a.apply(void 0, [_c.sent()]).toBe(true);
188
+ _b = expect;
189
+ return [4 /*yield*/, userRow('modern@test.local')];
190
+ case 4:
191
+ _b.apply(void 0, [(_c.sent()).password]).toBe(encoded);
192
+ return [2 /*return*/];
193
+ }
194
+ });
195
+ }); });
196
+ it('wrong password fails for both stored formats, and never mutates the row', function () { return __awaiter(void 0, void 0, void 0, function () {
197
+ var legacyHash, _a, _b, _c, _d;
198
+ var _e;
199
+ return __generator(this, function (_f) {
200
+ switch (_f.label) {
201
+ case 0:
202
+ legacyHash = (0, sha256_1.default)('right password').toString();
203
+ return [4 /*yield*/, insertUser({ email: 'legacy@test.local', password: legacyHash })];
204
+ case 1:
205
+ _f.sent();
206
+ _a = insertUser;
207
+ _e = { email: 'modern@test.local' };
208
+ return [4 /*yield*/, new PasswordHasher_1.PasswordHasher().hash('right password')];
209
+ case 2: return [4 /*yield*/, _a.apply(void 0, [(_e.password = _f.sent(), _e)])];
210
+ case 3:
211
+ _f.sent();
212
+ _b = expect;
213
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('legacy@test.local', 'wrong password')];
214
+ case 4:
215
+ _b.apply(void 0, [_f.sent()]).toBe('User name or password incorrect');
216
+ _c = expect;
217
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('modern@test.local', 'wrong password')];
218
+ case 5:
219
+ _c.apply(void 0, [_f.sent()]).toBe('User name or password incorrect');
220
+ // A failed attempt is not a migration event: the legacy row still holds its sha256.
221
+ _d = expect;
222
+ return [4 /*yield*/, userRow('legacy@test.local')];
223
+ case 6:
224
+ // A failed attempt is not a migration event: the legacy row still holds its sha256.
225
+ _d.apply(void 0, [(_f.sent()).password]).toBe(legacyHash);
226
+ return [2 /*return*/];
227
+ }
228
+ });
229
+ }); });
230
+ it('unknown email fails the same way (no query-by-hash oracle)', function () { return __awaiter(void 0, void 0, void 0, function () {
231
+ var _a;
232
+ return __generator(this, function (_b) {
233
+ switch (_b.label) {
234
+ case 0:
235
+ _a = expect;
236
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('nobody@test.local', 'anything')];
237
+ case 1:
238
+ _a.apply(void 0, [_b.sent()]).toBe('User name or password incorrect');
239
+ return [2 /*return*/];
240
+ }
241
+ });
242
+ }); });
243
+ it('new registrations write only the new format', function () { return __awaiter(void 0, void 0, void 0, function () {
244
+ var row, _a;
245
+ return __generator(this, function (_b) {
246
+ switch (_b.label) {
247
+ case 0: return [4 /*yield*/, new Signup_1.Signup().createAccount({
248
+ name: 'New user',
249
+ email: 'new@test.local',
250
+ password: 'first password',
251
+ emailVerified: false,
252
+ invitedBy: null,
253
+ })];
254
+ case 1:
255
+ _b.sent();
256
+ return [4 /*yield*/, userRow('new@test.local')];
257
+ case 2:
258
+ row = _b.sent();
259
+ expect(row.password.startsWith(ARGON2ID_PREFIX)).toBe(true);
260
+ expect(row.password).not.toBe((0, sha256_1.default)('first password').toString());
261
+ _a = expect;
262
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('new@test.local', 'first password')];
263
+ case 3:
264
+ _a.apply(void 0, [_b.sent()]).toBe(true);
265
+ return [2 /*return*/];
266
+ }
267
+ });
268
+ }); });
269
+ it('deactivated and pending-deletion gates are unchanged across both formats', function () { return __awaiter(void 0, void 0, void 0, function () {
270
+ var _a, _b, _c;
271
+ var _d;
272
+ return __generator(this, function (_e) {
273
+ switch (_e.label) {
274
+ case 0:
275
+ // Staff-deactivated account: correct credentials are still refused a session.
276
+ return [4 /*yield*/, insertUser({ email: 'off@test.local', password: (0, sha256_1.default)('pw').toString(), status: 'deactivated' })];
277
+ case 1:
278
+ // Staff-deactivated account: correct credentials are still refused a session.
279
+ _e.sent();
280
+ _a = expect;
281
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('off@test.local', 'pw')];
282
+ case 2:
283
+ _a.apply(void 0, [_e.sent()]).toBe('This account has been deactivated');
284
+ _b = insertUser;
285
+ _d = {
286
+ email: 'pending@test.local'
287
+ };
288
+ return [4 /*yield*/, new PasswordHasher_1.PasswordHasher().hash('pw')];
289
+ case 3:
290
+ // Pending-deletion account (deactivated + deleteRequestedAt): login IS the cancel signal —
291
+ // authenticate admits it, for migrated rows too.
292
+ return [4 /*yield*/, _b.apply(void 0, [(_d.password = _e.sent(),
293
+ _d.status = 'deactivated',
294
+ _d.deleteRequestedAt = (0, moment_1.default)(),
295
+ _d)])];
296
+ case 4:
297
+ // Pending-deletion account (deactivated + deleteRequestedAt): login IS the cancel signal —
298
+ // authenticate admits it, for migrated rows too.
299
+ _e.sent();
300
+ _c = expect;
301
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('pending@test.local', 'pw')];
302
+ case 5:
303
+ _c.apply(void 0, [_e.sent()]).toBe(true);
304
+ return [2 /*return*/];
305
+ }
306
+ });
307
+ }); });
308
+ it('machine rows authenticate through the same owner but never leave sha256', function () { return __awaiter(void 0, void 0, void 0, function () {
309
+ var secret, machineHash, _a, row;
310
+ return __generator(this, function (_b) {
311
+ switch (_b.label) {
312
+ case 0:
313
+ secret = '9f'.repeat(32);
314
+ machineHash = (0, sha256_1.default)(secret).toString();
315
+ return [4 /*yield*/, insertUser({ email: 'machine@test.local', password: machineHash, isLoadedFromSource: true })];
316
+ case 1:
317
+ _b.sent();
318
+ _a = expect;
319
+ return [4 /*yield*/, (0, authenticate_1.authenticate)('machine@test.local', secret)];
320
+ case 2:
321
+ _a.apply(void 0, [_b.sent()]).toBe(true);
322
+ return [4 /*yield*/, userRow('machine@test.local')];
323
+ case 3:
324
+ row = _b.sent();
325
+ expect(row.password).toBe(machineHash);
326
+ expect(row.password).toMatch(SHA256_HEX);
327
+ return [2 /*return*/];
328
+ }
329
+ });
330
+ }); });
331
+ });
332
+ //# sourceMappingURL=PasswordMigration.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PasswordMigration.integration.test.js","sourceRoot":"","sources":["../../test/PasswordMigration.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SetUserStatus.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SetUserStatus.integration.test.d.ts","sourceRoot":"","sources":["../../test/SetUserStatus.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,266 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ var db_1 = require("@proteinjs/db");
40
+ var reflection_1 = require("@proteinjs/reflection");
41
+ // Deep import (test-only): ServiceAuth is the real RPC door but is not index-exported by
42
+ // @proteinjs/service — the door test below runs the actual gate rather than pinning metadata.
43
+ var ServiceAuth_1 = require("@proteinjs/service/dist/src/ServiceAuth");
44
+ var user_1 = require("@proteinjs/user");
45
+ var SetUserStatus_1 = require("../src/services/SetUserStatus");
46
+ var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
47
+ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
48
+ /**
49
+ * The SetUserStatus service is the ONE write path for account standing: the status update and
50
+ * its `user_status_event` audit row commit together. Outcomes asserted against the emulator:
51
+ * the rows written, not the calls made.
52
+ *
53
+ * The service door is exercised through ServiceAuth itself (the same gate the RPC path runs):
54
+ * the explicit `roles: ['admin']` block refuses everyone but admins.
55
+ */
56
+ describe('SetUserStatus service — admin door, standing writes, audit trail', function () {
57
+ var admin;
58
+ var nonAdmin;
59
+ var target;
60
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
61
+ return __generator(this, function (_a) {
62
+ switch (_a.label) {
63
+ case 0: return [4 /*yield*/, testEnv.beforeAll()];
64
+ case 1:
65
+ _a.sent();
66
+ // ServiceAuth funnels through UserAuth, which resolves the current user from the
67
+ // source-graph-registered AuthenticatedUserRepo — seed it the way the env seeds session
68
+ // storage (tests do not load the generated source graph).
69
+ reflection_1.SourceRepository.get().objectCache['@proteinjs/user-auth/AuthenticatedUserRepo'] = [new user_1.UserRepo()];
70
+ return [2 /*return*/];
71
+ }
72
+ });
73
+ }); }, 120000);
74
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
75
+ return __generator(this, function (_a) {
76
+ switch (_a.label) {
77
+ case 0: return [4 /*yield*/, testEnv.afterAll()];
78
+ case 1:
79
+ _a.sent();
80
+ return [2 /*return*/];
81
+ }
82
+ });
83
+ }); });
84
+ beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
85
+ var db;
86
+ return __generator(this, function (_a) {
87
+ switch (_a.label) {
88
+ case 0:
89
+ db = (0, db_1.getDbAsSystem)();
90
+ return [4 /*yield*/, db.delete(user_1.tables.UserStatusEvent, {})];
91
+ case 1:
92
+ _a.sent();
93
+ return [4 /*yield*/, db.delete(user_1.tables.User, {})];
94
+ case 2:
95
+ _a.sent();
96
+ return [4 /*yield*/, testEnv.createUser({ name: 'Admin actor', email: 'status-admin@test.local', roles: ['admin'] })];
97
+ case 3:
98
+ admin = _a.sent();
99
+ return [4 /*yield*/, testEnv.createUser({ name: 'Plain actor', email: 'status-plain@test.local', roles: ['ops'] })];
100
+ case 4:
101
+ nonAdmin = _a.sent();
102
+ return [4 /*yield*/, testEnv.createUser({ name: 'Target user', email: 'status-target@test.local' })];
103
+ case 5:
104
+ target = _a.sent();
105
+ return [2 /*return*/];
106
+ }
107
+ });
108
+ }); });
109
+ var targetStatus = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
110
+ switch (_a.label) {
111
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { id: target.id })];
112
+ case 1: return [2 /*return*/, (_a.sent()).status];
113
+ }
114
+ }); }); };
115
+ var auditRows = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
116
+ switch (_a.label) {
117
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.UserStatusEvent, {})];
118
+ case 1: return [2 /*return*/, _a.sent()];
119
+ }
120
+ }); }); };
121
+ var canRun = function () {
122
+ return ServiceAuth_1.ServiceAuth.canRunService(new SetUserStatus_1.SetUserStatus(), { name: 'setUserStatus' }, [target.id, 'deactivated']);
123
+ };
124
+ it('refuses the door for a non-admin and admits an admin', function () {
125
+ testEnv.actAs(nonAdmin);
126
+ expect(canRun()).toBe(false);
127
+ testEnv.actAs(admin);
128
+ expect(canRun()).toBe(true);
129
+ });
130
+ it('deactivate writes the standing on the user row and one audit row', function () { return __awaiter(void 0, void 0, void 0, function () {
131
+ var _a, events;
132
+ return __generator(this, function (_b) {
133
+ switch (_b.label) {
134
+ case 0:
135
+ testEnv.actAs(admin);
136
+ return [4 /*yield*/, new SetUserStatus_1.SetUserStatus().setUserStatus(target.id, 'deactivated')];
137
+ case 1:
138
+ _b.sent();
139
+ _a = expect;
140
+ return [4 /*yield*/, targetStatus()];
141
+ case 2:
142
+ _a.apply(void 0, [_b.sent()]).toBe('deactivated');
143
+ return [4 /*yield*/, auditRows()];
144
+ case 3:
145
+ events = _b.sent();
146
+ expect(events).toHaveLength(1);
147
+ expect(events[0]).toMatchObject({ actor: admin.id, target: target.id, status: 'deactivated' });
148
+ expect(events[0].created).toBeDefined();
149
+ return [2 /*return*/];
150
+ }
151
+ });
152
+ }); });
153
+ it('setting the standing the user already holds changes nothing and writes no audit row', function () { return __awaiter(void 0, void 0, void 0, function () {
154
+ var service, _a, _b;
155
+ return __generator(this, function (_c) {
156
+ switch (_c.label) {
157
+ case 0:
158
+ testEnv.actAs(admin);
159
+ service = new SetUserStatus_1.SetUserStatus();
160
+ return [4 /*yield*/, service.setUserStatus(target.id, 'deactivated')];
161
+ case 1:
162
+ _c.sent();
163
+ return [4 /*yield*/, service.setUserStatus(target.id, 'deactivated')];
164
+ case 2:
165
+ _c.sent();
166
+ _a = expect;
167
+ return [4 /*yield*/, targetStatus()];
168
+ case 3:
169
+ _a.apply(void 0, [_c.sent()]).toBe('deactivated');
170
+ _b = expect;
171
+ return [4 /*yield*/, auditRows()];
172
+ case 4:
173
+ _b.apply(void 0, [_c.sent()]).toHaveLength(1);
174
+ return [2 /*return*/];
175
+ }
176
+ });
177
+ }); });
178
+ it('treats a null standing (row predating the column) as active — no write, no audit row', function () { return __awaiter(void 0, void 0, void 0, function () {
179
+ var _a, _b;
180
+ return __generator(this, function (_c) {
181
+ switch (_c.label) {
182
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().update(user_1.tables.User, { id: target.id, status: null })];
183
+ case 1:
184
+ _c.sent();
185
+ testEnv.actAs(admin);
186
+ return [4 /*yield*/, new SetUserStatus_1.SetUserStatus().setUserStatus(target.id, 'active')];
187
+ case 2:
188
+ _c.sent();
189
+ _a = expect;
190
+ return [4 /*yield*/, targetStatus()];
191
+ case 3:
192
+ _a.apply(void 0, [_c.sent()]).toBeFalsy();
193
+ _b = expect;
194
+ return [4 /*yield*/, auditRows()];
195
+ case 4:
196
+ _b.apply(void 0, [_c.sent()]).toHaveLength(0);
197
+ return [2 /*return*/];
198
+ }
199
+ });
200
+ }); });
201
+ it('reactivate flips the standing back and audits it', function () { return __awaiter(void 0, void 0, void 0, function () {
202
+ var service, _a, events;
203
+ return __generator(this, function (_b) {
204
+ switch (_b.label) {
205
+ case 0:
206
+ testEnv.actAs(admin);
207
+ service = new SetUserStatus_1.SetUserStatus();
208
+ return [4 /*yield*/, service.setUserStatus(target.id, 'deactivated')];
209
+ case 1:
210
+ _b.sent();
211
+ return [4 /*yield*/, service.setUserStatus(target.id, 'active')];
212
+ case 2:
213
+ _b.sent();
214
+ _a = expect;
215
+ return [4 /*yield*/, targetStatus()];
216
+ case 3:
217
+ _a.apply(void 0, [_b.sent()]).toBe('active');
218
+ return [4 /*yield*/, auditRows()];
219
+ case 4:
220
+ events = _b.sent();
221
+ expect(events).toHaveLength(2);
222
+ expect(events.map(function (event) { return event.status; }).sort()).toEqual(['active', 'deactivated']);
223
+ return [2 /*return*/];
224
+ }
225
+ });
226
+ }); });
227
+ it('refuses a standing the vocabulary does not know, and writes nothing', function () { return __awaiter(void 0, void 0, void 0, function () {
228
+ var _a, _b;
229
+ return __generator(this, function (_c) {
230
+ switch (_c.label) {
231
+ case 0:
232
+ testEnv.actAs(admin);
233
+ return [4 /*yield*/, expect(new SetUserStatus_1.SetUserStatus().setUserStatus(target.id, 'suspended')).rejects.toThrow("'suspended' is not a known user status. Pick one of: active, deactivated.")];
234
+ case 1:
235
+ _c.sent();
236
+ _a = expect;
237
+ return [4 /*yield*/, targetStatus()];
238
+ case 2:
239
+ _a.apply(void 0, [_c.sent()]).toBe('active');
240
+ _b = expect;
241
+ return [4 /*yield*/, auditRows()];
242
+ case 3:
243
+ _b.apply(void 0, [_c.sent()]).toHaveLength(0);
244
+ return [2 /*return*/];
245
+ }
246
+ });
247
+ }); });
248
+ it('refuses a change for a user that does not exist', function () { return __awaiter(void 0, void 0, void 0, function () {
249
+ var _a;
250
+ return __generator(this, function (_b) {
251
+ switch (_b.label) {
252
+ case 0:
253
+ testEnv.actAs(admin);
254
+ return [4 /*yield*/, expect(new SetUserStatus_1.SetUserStatus().setUserStatus('nobody-1', 'deactivated')).rejects.toThrow('No user found for id: nobody-1')];
255
+ case 1:
256
+ _b.sent();
257
+ _a = expect;
258
+ return [4 /*yield*/, auditRows()];
259
+ case 2:
260
+ _a.apply(void 0, [_b.sent()]).toHaveLength(0);
261
+ return [2 /*return*/];
262
+ }
263
+ });
264
+ }); });
265
+ });
266
+ //# sourceMappingURL=SetUserStatus.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SetUserStatus.integration.test.js","sourceRoot":"","sources":["../../test/SetUserStatus.integration.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":""}