@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,152 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __generator = (this && this.__generator) || function (thisArg, body) {
35
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
36
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
37
+ function verb(n) { return function (v) { return step([n, v]); }; }
38
+ function step(op) {
39
+ if (f) throw new TypeError("Generator is already executing.");
40
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
41
+ 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;
42
+ if (y = 0, t) op = [op[0] & 2, t.value];
43
+ switch (op[0]) {
44
+ case 0: case 1: t = op; break;
45
+ case 4: _.label++; return { value: op[1], done: false };
46
+ case 5: _.label++; y = op[1]; op = [0]; continue;
47
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
48
+ default:
49
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
50
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
51
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
52
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
53
+ if (t[2]) _.ops.pop();
54
+ _.trys.pop(); continue;
55
+ }
56
+ op = body.call(thisArg, _);
57
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
58
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
59
+ }
60
+ };
61
+ Object.defineProperty(exports, "__esModule", { value: true });
62
+ exports.PasswordHasher = void 0;
63
+ var crypto_1 = require("crypto");
64
+ var argon2 = __importStar(require("argon2"));
65
+ /**
66
+ * The one owner of credential hashing. Every path that writes or checks the user table's
67
+ * `password` column goes through this class: authenticate (login), Signup.createAccount,
68
+ * executePasswordReset, UpdateUserInfo.updatePassword, AccountDeletion re-auth, and
69
+ * MachineCredentials minting.
70
+ *
71
+ * Exactly two self-describing at-rest formats:
72
+ * - argon2id encoded (`$argon2id$v=19$m=...,t=...,p=...$<salt>$<hash>`) — human passwords.
73
+ * The per-user random salt and the cost parameters live inside the encoded string.
74
+ * - sha256 hex (64 chars, never starts with `$`) — the legacy human format (pre-KDF rows,
75
+ * upgraded in place on next login via verify-then-rehash) AND the permanent machine format
76
+ * (see `PasswordHashMode`).
77
+ */
78
+ var PasswordHasher = /** @class */ (function () {
79
+ function PasswordHasher() {
80
+ }
81
+ PasswordHasher.prototype.hash = function (password, mode) {
82
+ if (mode === void 0) { mode = 'human'; }
83
+ return __awaiter(this, void 0, void 0, function () {
84
+ return __generator(this, function (_a) {
85
+ switch (_a.label) {
86
+ case 0:
87
+ if (mode === 'machine') {
88
+ return [2 /*return*/, this.sha256Hex(password)];
89
+ }
90
+ return [4 /*yield*/, argon2.hash(password, PasswordHasher.ARGON2_OPTIONS)];
91
+ case 1: return [2 /*return*/, _a.sent()];
92
+ }
93
+ });
94
+ });
95
+ };
96
+ /**
97
+ * Format-discriminating verify. `storedHash` absent means the row has no credential yet
98
+ * (a machine row before its first mint) — no password matches it.
99
+ */
100
+ PasswordHasher.prototype.verify = function (storedHash, password) {
101
+ return __awaiter(this, void 0, void 0, function () {
102
+ return __generator(this, function (_a) {
103
+ switch (_a.label) {
104
+ case 0:
105
+ if (!storedHash) {
106
+ return [2 /*return*/, false];
107
+ }
108
+ if (!storedHash.startsWith(PasswordHasher.ARGON2ID_PREFIX)) return [3 /*break*/, 2];
109
+ return [4 /*yield*/, argon2.verify(storedHash, password)];
110
+ case 1: return [2 /*return*/, _a.sent()];
111
+ case 2: return [2 /*return*/, this.constantTimeEqual(storedHash, this.sha256Hex(password))];
112
+ }
113
+ });
114
+ });
115
+ };
116
+ /**
117
+ * True when a verified credential should be re-written in the current format: legacy sha256
118
+ * under `human` mode. Machine rows never rehash — sha256 IS their current format.
119
+ */
120
+ PasswordHasher.prototype.needsRehash = function (storedHash, mode) {
121
+ if (mode === void 0) { mode = 'human'; }
122
+ if (mode === 'machine') {
123
+ return false;
124
+ }
125
+ return !storedHash.startsWith(PasswordHasher.ARGON2ID_PREFIX);
126
+ };
127
+ /** Byte-identical to the legacy crypto-js `sha256(value).toString()` (UTF-8 in, lowercase hex out). */
128
+ PasswordHasher.prototype.sha256Hex = function (value) {
129
+ return (0, crypto_1.createHash)('sha256').update(value, 'utf8').digest('hex');
130
+ };
131
+ PasswordHasher.prototype.constantTimeEqual = function (stored, candidate) {
132
+ var storedBytes = Buffer.from(stored, 'utf8');
133
+ var candidateBytes = Buffer.from(candidate, 'utf8');
134
+ return storedBytes.length === candidateBytes.length && (0, crypto_1.timingSafeEqual)(storedBytes, candidateBytes);
135
+ };
136
+ /**
137
+ * argon2id cost, pinned so a package upgrade can't silently change what we write: 64 MiB
138
+ * memory, 3 passes, parallelism 4 — RFC 9106's second recommended parameter set (its
139
+ * memory-constrained option). Measured ~23ms/hash on an M-series dev machine — the ~100ms
140
+ * class on typical server vCPUs.
141
+ */
142
+ PasswordHasher.ARGON2_OPTIONS = {
143
+ type: argon2.argon2id,
144
+ memoryCost: 65536,
145
+ timeCost: 3,
146
+ parallelism: 4,
147
+ };
148
+ PasswordHasher.ARGON2ID_PREFIX = '$argon2id$';
149
+ return PasswordHasher;
150
+ }());
151
+ exports.PasswordHasher = PasswordHasher;
152
+ //# sourceMappingURL=PasswordHasher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PasswordHasher.js","sourceRoot":"","sources":["../../../src/authentication/PasswordHasher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAqD;AACrD,6CAAiC;AAUjC;;;;;;;;;;;;GAYG;AACH;IAAA;IA8DA,CAAC;IA9CO,6BAAI,GAAV,UAAW,QAAgB,EAAE,IAAgC;QAAhC,qBAAA,EAAA,cAAgC;;;;;wBAC3D,IAAI,IAAI,KAAK,SAAS,EAAE;4BACtB,sBAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAC;yBACjC;wBAEM,qBAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,EAAA;4BAAjE,sBAAO,SAA0D,EAAC;;;;KACnE;IAED;;;OAGG;IACG,+BAAM,GAAZ,UAAa,UAAqC,EAAE,QAAgB;;;;;wBAClE,IAAI,CAAC,UAAU,EAAE;4BACf,sBAAO,KAAK,EAAC;yBACd;6BAEG,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,eAAe,CAAC,EAArD,wBAAqD;wBAChD,qBAAM,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAA;4BAAhD,sBAAO,SAAyC,EAAC;4BAGnD,sBAAO,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAC;;;;KACrE;IAED;;;OAGG;IACH,oCAAW,GAAX,UAAY,UAAkB,EAAE,IAAgC;QAAhC,qBAAA,EAAA,cAAgC;QAC9D,IAAI,IAAI,KAAK,SAAS,EAAE;YACtB,OAAO,KAAK,CAAC;SACd;QAED,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;IAChE,CAAC;IAED,uGAAuG;IAC/F,kCAAS,GAAjB,UAAkB,KAAa;QAC7B,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IAEO,0CAAiB,GAAzB,UAA0B,MAAc,EAAE,SAAiB;QACzD,IAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,IAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,WAAW,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM,IAAI,IAAA,wBAAe,EAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IACtG,CAAC;IA5DD;;;;;OAKG;IACqB,6BAAc,GAAuB;QAC3D,IAAI,EAAE,MAAM,CAAC,QAAQ;QACrB,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,CAAC;QACX,WAAW,EAAE,CAAC;KACf,CAAC;IAEsB,8BAAe,GAAG,YAAY,CAAC;IAgDzD,qBAAC;CAAA,AA9DD,IA8DC;AA9DY,wCAAc"}
@@ -0,0 +1,19 @@
1
+ import { QueryBuilder, Table, TableWatcher } from '@proteinjs/db';
2
+ import { User } from '@proteinjs/user';
3
+ /**
4
+ * The one owner of "deactivated ⇒ sessions die": any user-table update writing
5
+ * `status: 'deactivated'` deletes the account's session rows (SocketIOSessionWatcher kicks the
6
+ * live sockets on that delete). Because the writers all go through `Db.update` — the staff
7
+ * toggle (SetUserStatus), account deletion, and the boot sync deactivating machine accounts
8
+ * removed from source — this fires for every present and future deactivation path.
9
+ *
10
+ * The delete runs post-commit (`runAfterCommit`): a transactional status flip that rolls back
11
+ * must not have killed sessions, and socket kicks must observe committed truth.
12
+ */
13
+ export declare class UserStatusTableWatcher implements TableWatcher<User> {
14
+ private logger;
15
+ name(): string;
16
+ table(): Table<User>;
17
+ afterUpdate<T extends User>(recordUpdateCount: number, record: Partial<T>, qb: QueryBuilder<T>): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=UserStatusTableWatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserStatusTableWatcher.d.ts","sourceRoot":"","sources":["../../../src/authentication/UserStatusTableWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAiB,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,IAAI,EAAU,MAAM,iBAAiB,CAAC;AAG/C;;;;;;;;;GASG;AACH,qBAAa,sBAAuB,YAAW,YAAY,CAAC,IAAI,CAAC;IAC/D,OAAO,CAAC,MAAM,CAA+C;IAE7D,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;IAId,WAAW,CAAC,CAAC,SAAS,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CA8BrH"}
@@ -0,0 +1,115 @@
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
+ exports.UserStatusTableWatcher = void 0;
40
+ var db_1 = require("@proteinjs/db");
41
+ var user_1 = require("@proteinjs/user");
42
+ var logger_1 = require("@proteinjs/logger");
43
+ /**
44
+ * The one owner of "deactivated ⇒ sessions die": any user-table update writing
45
+ * `status: 'deactivated'` deletes the account's session rows (SocketIOSessionWatcher kicks the
46
+ * live sockets on that delete). Because the writers all go through `Db.update` — the staff
47
+ * toggle (SetUserStatus), account deletion, and the boot sync deactivating machine accounts
48
+ * removed from source — this fires for every present and future deactivation path.
49
+ *
50
+ * The delete runs post-commit (`runAfterCommit`): a transactional status flip that rolls back
51
+ * must not have killed sessions, and socket kicks must observe committed truth.
52
+ */
53
+ var UserStatusTableWatcher = /** @class */ (function () {
54
+ function UserStatusTableWatcher() {
55
+ this.logger = new logger_1.Logger({ name: this.constructor.name });
56
+ }
57
+ UserStatusTableWatcher.prototype.name = function () {
58
+ return this.constructor.name;
59
+ };
60
+ UserStatusTableWatcher.prototype.table = function () {
61
+ return user_1.tables.User;
62
+ };
63
+ UserStatusTableWatcher.prototype.afterUpdate = function (recordUpdateCount, record, qb) {
64
+ return __awaiter(this, void 0, void 0, function () {
65
+ var db;
66
+ var _this = this;
67
+ return __generator(this, function (_a) {
68
+ switch (_a.label) {
69
+ case 0:
70
+ if (record.status !== 'deactivated' || recordUpdateCount === 0) {
71
+ return [2 /*return*/];
72
+ }
73
+ if (!record.id) {
74
+ // Every deactivation writer today updates by record id. A future query-based writer must
75
+ // extend this watcher — surface it loudly instead of silently leaving sessions alive.
76
+ this.logger.error({
77
+ message: "Deactivation write without a record id \u2014 sessions NOT killed. Extend UserStatusTableWatcher for query-based status writers.",
78
+ });
79
+ return [2 /*return*/];
80
+ }
81
+ db = (0, db_1.getDbAsSystem)();
82
+ return [4 /*yield*/, db.runAfterCommit(function () { return __awaiter(_this, void 0, void 0, function () {
83
+ var user, deletedSessions;
84
+ return __generator(this, function (_a) {
85
+ switch (_a.label) {
86
+ case 0: return [4 /*yield*/, db.get(user_1.tables.User, { id: record.id })];
87
+ case 1:
88
+ user = _a.sent();
89
+ if (!user) {
90
+ return [2 /*return*/]; // row deleted since the flip — nothing to resolve sessions against
91
+ }
92
+ return [4 /*yield*/, db.delete(user_1.tables.Session, { userEmail: user.email })];
93
+ case 2:
94
+ deletedSessions = _a.sent();
95
+ if (deletedSessions > 0) {
96
+ this.logger.info({
97
+ message: "Deactivation killed sessions",
98
+ obj: { email: user.email, sessions: deletedSessions },
99
+ });
100
+ }
101
+ return [2 /*return*/];
102
+ }
103
+ });
104
+ }); })];
105
+ case 1:
106
+ _a.sent();
107
+ return [2 /*return*/];
108
+ }
109
+ });
110
+ });
111
+ };
112
+ return UserStatusTableWatcher;
113
+ }());
114
+ exports.UserStatusTableWatcher = UserStatusTableWatcher;
115
+ //# sourceMappingURL=UserStatusTableWatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserStatusTableWatcher.js","sourceRoot":"","sources":["../../../src/authentication/UserStatusTableWatcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAAiF;AACjF,wCAA+C;AAC/C,4CAA2C;AAE3C;;;;;;;;;GASG;AACH;IAAA;QACU,WAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAwC/D,CAAC;IAtCC,qCAAI,GAAJ;QACE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED,sCAAK,GAAL;QACE,OAAO,aAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAEK,4CAAW,GAAjB,UAAkC,iBAAyB,EAAE,MAAkB,EAAE,EAAmB;;;;;;;wBAClG,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,IAAI,iBAAiB,KAAK,CAAC,EAAE;4BAC9D,sBAAO;yBACR;wBAED,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;4BACd,yFAAyF;4BACzF,sFAAsF;4BACtF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;gCAChB,OAAO,EAAE,kIAA6H;6BACvI,CAAC,CAAC;4BACH,sBAAO;yBACR;wBAEK,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBAC3B,qBAAM,EAAE,CAAC,cAAc,CAAC;;;;gDACT,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,EAAA;;4CAAnD,IAAI,GAAG,SAA4C;4CACzD,IAAI,CAAC,IAAI,EAAE;gDACT,sBAAO,CAAC,mEAAmE;6CAC5E;4CAEuB,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EAAA;;4CAA5E,eAAe,GAAG,SAA0D;4CAClF,IAAI,eAAe,GAAG,CAAC,EAAE;gDACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;oDACf,OAAO,EAAE,8BAA8B;oDACvC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE;iDACtD,CAAC,CAAC;6CACJ;;;;iCACF,CAAC,EAAA;;wBAbF,SAaE,CAAC;;;;;KACJ;IACH,6BAAC;AAAD,CAAC,AAzCD,IAyCC;AAzCY,wDAAsB"}
@@ -1 +1 @@
1
- {"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":"AAMA,wBAAgB,oBAAoB,CAAC,uBAAuB,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,uBAMpG;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CAqB1F"}
1
+ {"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":"AAMA,wBAAgB,oBAAoB,CAAC,uBAAuB,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,uBAMpG;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,CA8C1F"}
@@ -35,16 +35,13 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
35
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
36
  }
37
37
  };
38
- var __importDefault = (this && this.__importDefault) || function (mod) {
39
- return (mod && mod.__esModule) ? mod : { "default": mod };
40
- };
41
38
  Object.defineProperty(exports, "__esModule", { value: true });
42
39
  exports.authenticate = exports.createAuthentication = void 0;
43
- var sha256_1 = __importDefault(require("crypto-js/sha256"));
44
40
  var db_1 = require("@proteinjs/db");
45
41
  var user_1 = require("@proteinjs/user");
46
42
  var logger_1 = require("@proteinjs/logger");
47
43
  var DefaultAdminCredentials_1 = require("./DefaultAdminCredentials");
44
+ var PasswordHasher_1 = require("./PasswordHasher");
48
45
  function createAuthentication(defaultAdminCredentials) {
49
46
  if (defaultAdminCredentials) {
50
47
  DefaultAdminCredentials_1.DefaultAdminCredentials.setCredentials(defaultAdminCredentials);
@@ -54,9 +51,10 @@ function createAuthentication(defaultAdminCredentials) {
54
51
  exports.createAuthentication = createAuthentication;
55
52
  function authenticate(email, password) {
56
53
  return __awaiter(this, void 0, void 0, function () {
57
- var logger, defaultAdminCredentials, users;
58
- return __generator(this, function (_a) {
59
- switch (_a.label) {
54
+ var logger, defaultAdminCredentials, db, user, hasher, _a, mode, _b, _c, _d;
55
+ var _e;
56
+ return __generator(this, function (_f) {
57
+ switch (_f.label) {
60
58
  case 0:
61
59
  logger = new logger_1.Logger({ name: 'authenticate' });
62
60
  defaultAdminCredentials = DefaultAdminCredentials_1.DefaultAdminCredentials.getCredentials();
@@ -66,15 +64,45 @@ function authenticate(email, password) {
66
64
  logger.info({ message: 'Authenitcated default admin user' });
67
65
  return [2 /*return*/, true];
68
66
  }
69
- return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.User, {
70
- email: email.toLowerCase(),
71
- password: (0, sha256_1.default)(password).toString(),
72
- })];
67
+ db = (0, db_1.getDbAsSystem)();
68
+ return [4 /*yield*/, db.get(user_1.tables.User, { email: email.toLowerCase() })];
73
69
  case 1:
74
- users = _a.sent();
75
- if (users.length < 1) {
70
+ user = _f.sent();
71
+ hasher = new PasswordHasher_1.PasswordHasher();
72
+ _a = !user;
73
+ if (_a) return [3 /*break*/, 3];
74
+ return [4 /*yield*/, hasher.verify(user.password, password)];
75
+ case 2:
76
+ _a = !(_f.sent());
77
+ _f.label = 3;
78
+ case 3:
79
+ if (_a) {
76
80
  return [2 /*return*/, 'User name or password incorrect'];
77
81
  }
82
+ mode = user.isLoadedFromSource === true ? 'machine' : 'human';
83
+ if (!hasher.needsRehash(user.password, mode)) return [3 /*break*/, 6];
84
+ _c = (_b = db).update;
85
+ _d = [user_1.tables.User];
86
+ _e = { id: user.id };
87
+ return [4 /*yield*/, hasher.hash(password)];
88
+ case 4: return [4 /*yield*/, _c.apply(_b, _d.concat([(_e.password = _f.sent(), _e)]))];
89
+ case 5:
90
+ _f.sent();
91
+ _f.label = 6;
92
+ case 6:
93
+ // Deactivated accounts are refused a new session even with correct credentials; the session
94
+ // side of the same gate lives in userCache (deactivated sessions resolve as guest).
95
+ if (user.status === 'deactivated') {
96
+ // Pending-deletion accounts (deactivated by the account-deletion flow, not the staff toggle)
97
+ // may authenticate: logging back in IS the cancel signal — the login route runs the cancel
98
+ // hook before request.login and decides. No purgeAfter check here: the cancel's CAS claim is
99
+ // the arbiter, so a user beating the purge walker to a just-expired window wins honestly.
100
+ if (user.deleteRequestedAt != null) {
101
+ return [2 /*return*/, true];
102
+ }
103
+ logger.warn({ message: 'Refused login for deactivated account', obj: { email: email.toLowerCase() } });
104
+ return [2 /*return*/, 'This account has been deactivated'];
105
+ }
78
106
  return [2 /*return*/, true];
79
107
  }
80
108
  });
@@ -1 +1 @@
1
- {"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4DAAsC;AACtC,oCAA8C;AAC9C,wCAAyC;AACzC,4CAA2C;AAC3C,qEAAoE;AAEpE,SAAgB,oBAAoB,CAAC,uBAAgE;IACnG,IAAI,uBAAuB,EAAE;QAC3B,iDAAuB,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC;KACjE;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAND,oDAMC;AAED,SAAsB,YAAY,CAAC,KAAa,EAAE,QAAgB;;;;;;oBAC1D,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;oBAC9C,uBAAuB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;oBACzE,IACE,uBAAuB;wBACvB,uBAAuB,CAAC,QAAQ,IAAI,KAAK;wBACzC,uBAAuB,CAAC,QAAQ,IAAI,QAAQ,EAC5C;wBACA,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC,CAAC;wBAC7D,sBAAO,IAAI,EAAC;qBACb;oBAEa,qBAAM,IAAA,kBAAa,GAAE,CAAC,KAAK,CAAC,aAAM,CAAC,IAAI,EAAE;4BACrD,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE;4BAC1B,QAAQ,EAAE,IAAA,gBAAM,EAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE;yBACtC,CAAC,EAAA;;oBAHI,KAAK,GAAG,SAGZ;oBACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;wBACpB,sBAAO,iCAAiC,EAAC;qBAC1C;oBAED,sBAAO,IAAI,EAAC;;;;CACb;AArBD,oCAqBC"}
1
+ {"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../../src/authentication/authenticate.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAA8C;AAC9C,wCAAyC;AACzC,4CAA2C;AAC3C,qEAAoE;AACpE,mDAAkD;AAElD,SAAgB,oBAAoB,CAAC,uBAAgE;IACnG,IAAI,uBAAuB,EAAE;QAC3B,iDAAuB,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC;KACjE;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAND,oDAMC;AAED,SAAsB,YAAY,CAAC,KAAa,EAAE,QAAgB;;;;;;;oBAC1D,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;oBAC9C,uBAAuB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;oBACzE,IACE,uBAAuB;wBACvB,uBAAuB,CAAC,QAAQ,IAAI,KAAK;wBACzC,uBAAuB,CAAC,QAAQ,IAAI,QAAQ,EAC5C;wBACA,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC,CAAC;wBAC7D,sBAAO,IAAI,EAAC;qBACb;oBAKK,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;oBACd,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAhE,IAAI,GAAG,SAAyD;oBAChE,MAAM,GAAG,IAAI,+BAAc,EAAE,CAAC;oBAChC,KAAA,CAAC,IAAI,CAAA;4BAAL,wBAAK;oBAAM,qBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAA;;oBAA9C,KAAA,CAAC,CAAC,SAA4C,CAAC,CAAA;;;oBAA5D,QAA8D;wBAC5D,sBAAO,iCAAiC,EAAC;qBAC1C;oBAKK,IAAI,GAAG,IAAI,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;yBAChE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAvC,wBAAuC;oBACnC,KAAA,CAAA,KAAA,EAAE,CAAA,CAAC,MAAM,CAAA;0BAAC,aAAM,CAAC,IAAI;2BAAI,EAAE,EAAE,IAAI,CAAC,EAAE;oBAAY,qBAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAA;wBAAjF,qBAAM,yBAAsC,WAAQ,GAAE,SAA2B,QAAG,EAAA;;oBAApF,SAAoF,CAAC;;;oBAGvF,4FAA4F;oBAC5F,oFAAoF;oBACpF,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE;wBACjC,6FAA6F;wBAC7F,2FAA2F;wBAC3F,6FAA6F;wBAC7F,0FAA0F;wBAC1F,IAAI,IAAI,CAAC,iBAAiB,IAAI,IAAI,EAAE;4BAClC,sBAAO,IAAI,EAAC;yBACb;wBAED,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,uCAAuC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;wBACvG,sBAAO,mCAAmC,EAAC;qBAC5C;oBAED,sBAAO,IAAI,EAAC;;;;CACb;AA9CD,oCA8CC"}
@@ -1 +1 @@
1
- {"version":3,"file":"userCache.d.ts","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,IAAI,EAA6C,MAAM,iBAAiB,CAAC;AAKlF,eAAO,MAAM,SAAS,EAAE,gBAAgB,CAAC,IAAI,CAsC5C,CAAC"}
1
+ {"version":3,"file":"userCache.d.ts","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,IAAI,EAA6C,MAAM,iBAAiB,CAAC;AAKlF,eAAO,MAAM,SAAS,EAAE,gBAAgB,CAAC,IAAI,CA8C5C,CAAC"}
@@ -72,7 +72,16 @@ exports.userCache = {
72
72
  case 1: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { email: userEmail.toLowerCase() })];
73
73
  case 2:
74
74
  accountUser = _a.sent();
75
- if (accountUser) {
75
+ if (accountUser && accountUser.status === 'deactivated') {
76
+ // The session half of the deactivation gate (login half in authenticate): the session
77
+ // cache is rebuilt per request, so a live session stops resolving the moment the
78
+ // account is deactivated — every request runs as the unauthenticated guest.
79
+ logger.warn({
80
+ message: "Session references a deactivated account; resolving as unauthenticated",
81
+ obj: { sessionId: sessionId, userEmail: userEmail },
82
+ });
83
+ }
84
+ else if (accountUser) {
76
85
  delete accountUser['password'];
77
86
  user = accountUser;
78
87
  }
@@ -1 +1 @@
1
- {"version":3,"file":"userCache.js","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAE5B,oCAA8C;AAC9C,4CAA2C;AAC3C,wCAAkF;AAClF,qFAAoF;AAEpF,IAAM,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;AAEpC,QAAA,SAAS,GAA2B;IAC/C,GAAG,EAAE,6BAAsB;IAC3B,MAAM,EAAE,UAAO,SAAiB,EAAE,SAAiB;;;;;oBAC7C,IAAI,GAAG,gBAAS,CAAC;yBACjB,SAAS,EAAT,wBAAS;oBACL,gBAAgB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;yBAC9D,CAAA,gBAAgB,IAAI,SAAS,IAAI,gBAAgB,CAAC,QAAQ,CAAA,EAA1D,wBAA0D;oBACtD,SAAS,GAAS;wBACtB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,gBAAgB,CAAC,QAAQ;wBAChC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ;wBACnC,aAAa,EAAE,IAAI;wBACnB,KAAK,EAAE,CAAC,OAAO,CAAC;wBAChB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,EAAE,EAAE,OAAO;qBACZ,CAAC;oBACF,IAAI,GAAG,SAAS,CAAC;;wBAEG,qBAAM,IAAA,kBAAa,GAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAxF,WAAW,GAAG,SAA0E;oBAC9F,IAAI,WAAW,EAAE;wBACf,OAAQ,WAAmB,CAAC,UAAU,CAAC,CAAC;wBACxC,IAAI,GAAG,WAAW,CAAC;qBACpB;yBAAM;wBACL,0FAA0F;wBAC1F,+EAA+E;wBAC/E,sFAAsF;wBACtF,yDAAyD;wBACzD,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,iFAAiF;4BAC1F,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;;wBAIL,sBAAO,IAAI,EAAC;;;SACb;CACF,CAAC"}
1
+ {"version":3,"file":"userCache.js","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAE5B,oCAA8C;AAC9C,4CAA2C;AAC3C,wCAAkF;AAClF,qFAAoF;AAEpF,IAAM,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;AAEpC,QAAA,SAAS,GAA2B;IAC/C,GAAG,EAAE,6BAAsB;IAC3B,MAAM,EAAE,UAAO,SAAiB,EAAE,SAAiB;;;;;oBAC7C,IAAI,GAAG,gBAAS,CAAC;yBACjB,SAAS,EAAT,wBAAS;oBACL,gBAAgB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;yBAC9D,CAAA,gBAAgB,IAAI,SAAS,IAAI,gBAAgB,CAAC,QAAQ,CAAA,EAA1D,wBAA0D;oBACtD,SAAS,GAAS;wBACtB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,gBAAgB,CAAC,QAAQ;wBAChC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ;wBACnC,aAAa,EAAE,IAAI;wBACnB,KAAK,EAAE,CAAC,OAAO,CAAC;wBAChB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,EAAE,EAAE,OAAO;qBACZ,CAAC;oBACF,IAAI,GAAG,SAAS,CAAC;;wBAEG,qBAAM,IAAA,kBAAa,GAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAxF,WAAW,GAAG,SAA0E;oBAC9F,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;wBACvD,sFAAsF;wBACtF,iFAAiF;wBACjF,4EAA4E;wBAC5E,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,wEAAwE;4BACjF,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;yBAAM,IAAI,WAAW,EAAE;wBACtB,OAAQ,WAAmB,CAAC,UAAU,CAAC,CAAC;wBACxC,IAAI,GAAG,WAAW,CAAC;qBACpB;yBAAM;wBACL,0FAA0F;wBAC1F,+EAA+E;wBAC/E,sFAAsF;wBACtF,yDAAyD;wBACzD,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,iFAAiF;4BAC1F,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;;wBAIL,sBAAO,IAAI,EAAC;;;SACb;CACF,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { Loadable } from '@proteinjs/reflection';
2
+ import Mail from 'nodemailer/lib/mailer';
3
+ import { Moment } from 'moment';
4
+ /**
5
+ * Config-factory seams for the two account-deletion emails (the PasswordResetEmailConfig
6
+ * pattern; the interfaces live here because @proteinjs/email-server is a registry package).
7
+ * Both emails are self-contained notifications, so each getter carries default content (the
8
+ * PasswordUpdatedEmailConfig precedent) — an app implements the factory to override.
9
+ */
10
+ export interface AccountDeletionRequestedEmailConfig {
11
+ /** @see https://nodemailer.com/message/ for all available options */
12
+ options?: Mail.Options;
13
+ /** @param purgeAfter when the grace window ends and the account is permanently erased */
14
+ getEmailContent: (purgeAfter: Moment) => {
15
+ text: string;
16
+ html?: string;
17
+ };
18
+ }
19
+ export interface DefaultAccountDeletionRequestedEmailConfigFactory extends Loadable {
20
+ getConfig(): AccountDeletionRequestedEmailConfig;
21
+ }
22
+ export declare const getDefaultAccountDeletionRequestedEmailConfigFactory: () => DefaultAccountDeletionRequestedEmailConfigFactory;
23
+ export interface AccountDeletedEmailConfig {
24
+ /** @see https://nodemailer.com/message/ for all available options */
25
+ options?: Mail.Options;
26
+ getEmailContent: () => {
27
+ text: string;
28
+ html?: string;
29
+ };
30
+ }
31
+ export interface DefaultAccountDeletedEmailConfigFactory extends Loadable {
32
+ getConfig(): AccountDeletedEmailConfig;
33
+ }
34
+ export declare const getDefaultAccountDeletedEmailConfigFactory: () => DefaultAccountDeletedEmailConfigFactory;
35
+ //# sourceMappingURL=AccountDeletionEmailConfigs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountDeletionEmailConfigs.d.ts","sourceRoot":"","sources":["../../../src/emails/AccountDeletionEmailConfigs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAoB,MAAM,uBAAuB,CAAC;AACnE,OAAO,IAAI,MAAM,uBAAuB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;;GAKG;AAEH,MAAM,WAAW,mCAAmC;IAClD,qEAAqE;IACrE,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC;IACvB,yFAAyF;IACzF,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK;QACvC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,MAAM,WAAW,iDAAkD,SAAQ,QAAQ;IACjF,SAAS,IAAI,mCAAmC,CAAC;CAClD;AAED,eAAO,MAAM,oDAAoD,QAC3D,iDAoBH,CAAC;AAEJ,MAAM,WAAW,yBAAyB;IACxC,qEAAqE;IACrE,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC;IACvB,eAAe,EAAE,MAAM;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,MAAM,WAAW,uCAAwC,SAAQ,QAAQ;IACvE,SAAS,IAAI,yBAAyB,CAAC;CACxC;AAED,eAAO,MAAM,0CAA0C,QAAO,uCAiB7D,CAAC"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDefaultAccountDeletedEmailConfigFactory = exports.getDefaultAccountDeletionRequestedEmailConfigFactory = void 0;
4
+ var reflection_1 = require("@proteinjs/reflection");
5
+ var getDefaultAccountDeletionRequestedEmailConfigFactory = function () {
6
+ var defaultFactory = {
7
+ getConfig: function () { return ({
8
+ options: { subject: 'Your account is scheduled for deletion' },
9
+ getEmailContent: function (purgeAfter) { return ({
10
+ text: "Your account is scheduled for deletion. Your content is no longer visible to you or to " +
11
+ "anyone you shared it with. You can change your mind until ".concat(purgeAfter.format('MMMM D, YYYY'), " ") +
12
+ "by simply logging back in \u2014 that restores everything, including shares. After that date, your " +
13
+ "account and everything in it are permanently removed from our systems, and we'll email you to " +
14
+ "confirm when it's done. If you didn't request this, log back in now to cancel.",
15
+ }); },
16
+ }); },
17
+ };
18
+ var retrievedFactory = reflection_1.SourceRepository.get().object('@proteinjs/user-server/DefaultAccountDeletionRequestedEmailConfigFactory');
19
+ return retrievedFactory || defaultFactory;
20
+ };
21
+ exports.getDefaultAccountDeletionRequestedEmailConfigFactory = getDefaultAccountDeletionRequestedEmailConfigFactory;
22
+ var getDefaultAccountDeletedEmailConfigFactory = function () {
23
+ var defaultFactory = {
24
+ getConfig: function () { return ({
25
+ options: { subject: 'Your account has been deleted' },
26
+ getEmailContent: function () { return ({
27
+ text: "Your account and everything in it have been permanently removed from our systems. " +
28
+ "This is the confirmation you were promised when you requested deletion. Goodbye, and thank you.",
29
+ }); },
30
+ }); },
31
+ };
32
+ var retrievedFactory = reflection_1.SourceRepository.get().object('@proteinjs/user-server/DefaultAccountDeletedEmailConfigFactory');
33
+ return retrievedFactory || defaultFactory;
34
+ };
35
+ exports.getDefaultAccountDeletedEmailConfigFactory = getDefaultAccountDeletedEmailConfigFactory;
36
+ //# sourceMappingURL=AccountDeletionEmailConfigs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountDeletionEmailConfigs.js","sourceRoot":"","sources":["../../../src/emails/AccountDeletionEmailConfigs.ts"],"names":[],"mappings":";;;AAAA,oDAAmE;AAyB5D,IAAM,oDAAoD,GAC/D;IACE,IAAM,cAAc,GAAsD;QACxE,SAAS,EAAE,cAAM,OAAA,CAAC;YAChB,OAAO,EAAE,EAAE,OAAO,EAAE,wCAAwC,EAAE;YAC9D,eAAe,EAAE,UAAC,UAAkB,IAAK,OAAA,CAAC;gBACxC,IAAI,EACF,yFAAyF;oBACzF,oEAA6D,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC,MAAG;oBACjG,qGAAgG;oBAChG,gGAAgG;oBAChG,gFAAgF;aACnF,CAAC,EAPuC,CAOvC;SACH,CAAC,EAVe,CAUf;KACH,CAAC;IAEF,IAAM,gBAAgB,GAAG,6BAAgB,CAAC,GAAG,EAAE,CAAC,MAAM,CACpD,0EAA0E,CAC3E,CAAC;IAEF,OAAO,gBAAgB,IAAI,cAAc,CAAC;AAC5C,CAAC,CAAC;AArBS,QAAA,oDAAoD,wDAqB7D;AAeG,IAAM,0CAA0C,GAAG;IACxD,IAAM,cAAc,GAA4C;QAC9D,SAAS,EAAE,cAAM,OAAA,CAAC;YAChB,OAAO,EAAE,EAAE,OAAO,EAAE,+BAA+B,EAAE;YACrD,eAAe,EAAE,cAAM,OAAA,CAAC;gBACtB,IAAI,EACF,oFAAoF;oBACpF,iGAAiG;aACpG,CAAC,EAJqB,CAIrB;SACH,CAAC,EAPe,CAOf;KACH,CAAC;IAEF,IAAM,gBAAgB,GAAG,6BAAgB,CAAC,GAAG,EAAE,CAAC,MAAM,CACpD,gEAAgE,CACjE,CAAC;IAEF,OAAO,gBAAgB,IAAI,cAAc,CAAC;AAC5C,CAAC,CAAC;AAjBW,QAAA,0CAA0C,8CAiBrD"}
@@ -0,0 +1,13 @@
1
+ import { Moment } from 'moment';
2
+ /**
3
+ * Thin sender for the two account-deletion emails: deletion-requested (at deactivation — the
4
+ * only cancel channel an account-takeover victim has) and the store-required completion
5
+ * confirmation (sent by the purge walker after the user row is gone). Content comes from the
6
+ * config factories beside this class; transport is the app's DefaultEmailConfigFactory SMTP
7
+ * config via EmailSender.
8
+ */
9
+ export declare class AccountDeletionEmails {
10
+ sendDeletionRequested(to: string, purgeAfter: Moment): Promise<void>;
11
+ sendAccountDeleted(to: string): Promise<void>;
12
+ }
13
+ //# sourceMappingURL=AccountDeletionEmails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountDeletionEmails.d.ts","sourceRoot":"","sources":["../../../src/emails/AccountDeletionEmails.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAOhC;;;;;;GAMG;AACH,qBAAa,qBAAqB;IAC1B,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpE,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWpD"}