@proteinjs/user-server 1.22.0 → 1.22.2

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 (133) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/generated/index.js +1 -1
  3. package/dist/generated/index.js.map +1 -1
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +10 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/authentication/PasswordHasher.d.ts +9 -0
  9. package/dist/src/authentication/PasswordHasher.d.ts.map +1 -1
  10. package/dist/src/authentication/PasswordHasher.js +25 -0
  11. package/dist/src/authentication/PasswordHasher.js.map +1 -1
  12. package/dist/src/authentication/PasswordResetToken.d.ts +43 -12
  13. package/dist/src/authentication/PasswordResetToken.d.ts.map +1 -1
  14. package/dist/src/authentication/PasswordResetToken.js +86 -21
  15. package/dist/src/authentication/PasswordResetToken.js.map +1 -1
  16. package/dist/src/authentication/authenticate.d.ts +15 -0
  17. package/dist/src/authentication/authenticate.d.ts.map +1 -1
  18. package/dist/src/authentication/authenticate.js +55 -20
  19. package/dist/src/authentication/authenticate.js.map +1 -1
  20. package/dist/src/routes/devLogin.d.ts +1 -1
  21. package/dist/src/routes/devLogin.js +1 -1
  22. package/dist/src/routes/executePasswordReset.d.ts +6 -1
  23. package/dist/src/routes/executePasswordReset.d.ts.map +1 -1
  24. package/dist/src/routes/executePasswordReset.js +16 -7
  25. package/dist/src/routes/executePasswordReset.js.map +1 -1
  26. package/dist/src/routes/initiatePasswordReset.d.ts +10 -2
  27. package/dist/src/routes/initiatePasswordReset.d.ts.map +1 -1
  28. package/dist/src/routes/initiatePasswordReset.js +55 -34
  29. package/dist/src/routes/initiatePasswordReset.js.map +1 -1
  30. package/dist/src/routes/login.d.ts +8 -0
  31. package/dist/src/routes/login.d.ts.map +1 -1
  32. package/dist/src/routes/login.js +63 -22
  33. package/dist/src/routes/login.js.map +1 -1
  34. package/dist/src/throttle/ClientAddress.d.ts +35 -0
  35. package/dist/src/throttle/ClientAddress.d.ts.map +1 -0
  36. package/dist/src/throttle/ClientAddress.js +48 -0
  37. package/dist/src/throttle/ClientAddress.js.map +1 -0
  38. package/dist/src/throttle/PasswordResetThrottle.d.ts +39 -0
  39. package/dist/src/throttle/PasswordResetThrottle.d.ts.map +1 -0
  40. package/dist/src/throttle/PasswordResetThrottle.js +59 -0
  41. package/dist/src/throttle/PasswordResetThrottle.js.map +1 -0
  42. package/dist/src/throttle/RequestDigests.d.ts +42 -0
  43. package/dist/src/throttle/RequestDigests.d.ts.map +1 -0
  44. package/dist/src/throttle/RequestDigests.js +96 -0
  45. package/dist/src/throttle/RequestDigests.js.map +1 -0
  46. package/dist/src/throttle/SignInThrottle.d.ts +67 -0
  47. package/dist/src/throttle/SignInThrottle.d.ts.map +1 -0
  48. package/dist/src/throttle/SignInThrottle.js +91 -0
  49. package/dist/src/throttle/SignInThrottle.js.map +1 -0
  50. package/dist/src/throttle/SlidingWindow.d.ts +51 -0
  51. package/dist/src/throttle/SlidingWindow.d.ts.map +1 -0
  52. package/dist/src/throttle/SlidingWindow.js +85 -0
  53. package/dist/src/throttle/SlidingWindow.js.map +1 -0
  54. package/dist/test/ClientAddress.test.d.ts +2 -0
  55. package/dist/test/ClientAddress.test.d.ts.map +1 -0
  56. package/dist/test/ClientAddress.test.js +51 -0
  57. package/dist/test/ClientAddress.test.js.map +1 -0
  58. package/dist/test/DbTraffic.d.ts +29 -0
  59. package/dist/test/DbTraffic.d.ts.map +1 -0
  60. package/dist/test/DbTraffic.js +106 -0
  61. package/dist/test/DbTraffic.js.map +1 -0
  62. package/dist/test/DevLoginBootstrapAdmin.test.js +3 -4
  63. package/dist/test/DevLoginBootstrapAdmin.test.js.map +1 -1
  64. package/dist/test/DevLoginStaleCookieFirstHit.test.js +1 -1
  65. package/dist/test/DevLoginStaleCookieFirstHit.test.js.map +1 -1
  66. package/dist/test/ExecutePasswordReset.test.js +513 -124
  67. package/dist/test/ExecutePasswordReset.test.js.map +1 -1
  68. package/dist/test/InitiatePasswordReset.test.d.ts +2 -0
  69. package/dist/test/InitiatePasswordReset.test.d.ts.map +1 -0
  70. package/dist/test/InitiatePasswordReset.test.js +783 -0
  71. package/dist/test/InitiatePasswordReset.test.js.map +1 -0
  72. package/dist/test/LogCapture.d.ts +22 -0
  73. package/dist/test/LogCapture.d.ts.map +1 -0
  74. package/dist/test/LogCapture.js +127 -0
  75. package/dist/test/LogCapture.js.map +1 -0
  76. package/dist/test/LoginThrottle.integration.test.d.ts +2 -0
  77. package/dist/test/LoginThrottle.integration.test.d.ts.map +1 -0
  78. package/dist/test/LoginThrottle.integration.test.js +616 -0
  79. package/dist/test/LoginThrottle.integration.test.js.map +1 -0
  80. package/dist/test/MalformedResetTokens.d.ts +11 -0
  81. package/dist/test/MalformedResetTokens.d.ts.map +1 -0
  82. package/dist/test/MalformedResetTokens.js +35 -0
  83. package/dist/test/MalformedResetTokens.js.map +1 -0
  84. package/dist/test/RequestDigests.test.d.ts +2 -0
  85. package/dist/test/RequestDigests.test.d.ts.map +1 -0
  86. package/dist/test/RequestDigests.test.js +73 -0
  87. package/dist/test/RequestDigests.test.js.map +1 -0
  88. package/dist/test/SlidingWindow.test.d.ts +2 -0
  89. package/dist/test/SlidingWindow.test.d.ts.map +1 -0
  90. package/dist/test/SlidingWindow.test.js +72 -0
  91. package/dist/test/SlidingWindow.test.js.map +1 -0
  92. package/dist/test/ValidateResetToken.test.js +156 -33
  93. package/dist/test/ValidateResetToken.test.js.map +1 -1
  94. package/dist/test/emulatorLock.test.d.ts +2 -0
  95. package/dist/test/emulatorLock.test.d.ts.map +1 -0
  96. package/dist/test/emulatorLock.test.js +32 -0
  97. package/dist/test/emulatorLock.test.js.map +1 -0
  98. package/dist/test/emulatorLockName.test.d.ts +2 -0
  99. package/dist/test/emulatorLockName.test.d.ts.map +1 -0
  100. package/dist/test/emulatorLockName.test.js +36 -0
  101. package/dist/test/emulatorLockName.test.js.map +1 -0
  102. package/generated/index.ts +1 -1
  103. package/index.ts +6 -1
  104. package/jest.config.js +2 -2
  105. package/package.json +3 -3
  106. package/src/authentication/PasswordHasher.ts +18 -1
  107. package/src/authentication/PasswordResetToken.ts +74 -20
  108. package/src/authentication/authenticate.ts +36 -9
  109. package/src/routes/devLogin.ts +1 -1
  110. package/src/routes/executePasswordReset.ts +10 -2
  111. package/src/routes/initiatePasswordReset.ts +46 -25
  112. package/src/routes/login.ts +39 -8
  113. package/src/throttle/ClientAddress.ts +47 -0
  114. package/src/throttle/PasswordResetThrottle.ts +62 -0
  115. package/src/throttle/RequestDigests.ts +97 -0
  116. package/src/throttle/SignInThrottle.ts +98 -0
  117. package/src/throttle/SlidingWindow.ts +90 -0
  118. package/test/ClientAddress.test.ts +54 -0
  119. package/test/DbTraffic.ts +43 -0
  120. package/test/DevLoginBootstrapAdmin.test.ts +3 -4
  121. package/test/DevLoginStaleCookieFirstHit.test.ts +1 -1
  122. package/test/ExecutePasswordReset.test.ts +308 -70
  123. package/test/InitiatePasswordReset.test.ts +456 -0
  124. package/test/LogCapture.ts +54 -0
  125. package/test/LoginThrottle.integration.test.ts +339 -0
  126. package/test/MalformedResetTokens.ts +27 -0
  127. package/test/RequestDigests.test.ts +81 -0
  128. package/test/SlidingWindow.test.ts +85 -0
  129. package/test/ValidateResetToken.test.ts +108 -24
  130. package/test/emulatorLock.js +5 -6
  131. package/test/emulatorLock.test.ts +32 -0
  132. package/test/emulatorLockName.test.ts +33 -0
  133. package/test/setup.js +2 -0
@@ -0,0 +1,616 @@
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 __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
+ if (ar || !(i in from)) {
41
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
42
+ ar[i] = from[i];
43
+ }
44
+ }
45
+ return to.concat(ar || Array.prototype.slice.call(from));
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ var crypto_1 = require("crypto");
49
+ var db_1 = require("@proteinjs/db");
50
+ var user_1 = require("@proteinjs/user");
51
+ var login_1 = require("../src/routes/login");
52
+ var PasswordHasher_1 = require("../src/authentication/PasswordHasher");
53
+ var passportSessionHarness_1 = require("./passportSessionHarness");
54
+ var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
55
+ var LogCapture_1 = require("./LogCapture");
56
+ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
57
+ /**
58
+ * `POST /user/login`, end to end against the Spanner emulator, outcomes only (what the door
59
+ * answers, whether a session was bound, what the log holds):
60
+ * - per account: ten refused passwords in the window, then every try — the right password too —
61
+ * answers "Too many attempts. Try again in a few minutes." and binds no session; an address
62
+ * with no account walks the same steps with the same answers; a success clears the count;
63
+ * - per client address: fifty tries that are not successes, then the same answer for any account;
64
+ * successes never count, however many;
65
+ * - a blank submission counts toward the address window, never an account's;
66
+ * - the throttled answer takes as long as a refused password, and a refusal for an address with
67
+ * no account takes as long as one for an account (no timing tell either way);
68
+ * - every refusal is a "Sign-in refused" line and every throttled answer its own "Sign-in
69
+ * throttled" line, each carrying the account digest and the coarse IP hash — one digest for
70
+ * one address however it was typed — and never the address;
71
+ * - tries in flight at the same moment cannot all pass the account's window together;
72
+ * - a refusal for an account still in the legacy password format takes as long as any other;
73
+ * - a field that is not text is a blank one: the door answers, it never throws.
74
+ */
75
+ var WRONG = 'User name or password incorrect';
76
+ var THROTTLED = 'Too many attempts. Try again in a few minutes.';
77
+ var BLANK = 'Email and password cannot be blank';
78
+ var RIGHT_PASSWORD = 'the right horse battery';
79
+ /** One sign-in attempt from `ip` as the server sees it with no proxy in front (the dev shape). */
80
+ var attempt = function (ip, email, password) { return __awaiter(void 0, void 0, void 0, function () {
81
+ var sent, response, request;
82
+ var _a;
83
+ return __generator(this, function (_b) {
84
+ switch (_b.label) {
85
+ case 0:
86
+ response = {
87
+ send: function (body) {
88
+ sent = body;
89
+ },
90
+ status: function () { return response; },
91
+ };
92
+ return [4 /*yield*/, (0, passportSessionHarness_1.createPassportRequest)({
93
+ body: { email: email, password: password },
94
+ headers: {},
95
+ socket: { remoteAddress: ip },
96
+ app: { get: function () { return false; } },
97
+ })];
98
+ case 1:
99
+ request = (_b.sent()).request;
100
+ return [4 /*yield*/, login_1.login.onRequest(request, response)];
101
+ case 2:
102
+ _b.sent();
103
+ return [2 /*return*/, { sent: sent, signedInAs: (_a = request.session.passport) === null || _a === void 0 ? void 0 : _a.user }];
104
+ }
105
+ });
106
+ }); };
107
+ var errors = function (count, ip, email, password) { return __awaiter(void 0, void 0, void 0, function () {
108
+ var answers, i, _a, _b;
109
+ var _c;
110
+ return __generator(this, function (_d) {
111
+ switch (_d.label) {
112
+ case 0:
113
+ answers = [];
114
+ i = 0;
115
+ _d.label = 1;
116
+ case 1:
117
+ if (!(i < count)) return [3 /*break*/, 4];
118
+ _b = (_a = answers).push;
119
+ return [4 /*yield*/, attempt(ip(i), email(i), password)];
120
+ case 2:
121
+ _b.apply(_a, [(_c = (_d.sent()).sent) === null || _c === void 0 ? void 0 : _c.error]);
122
+ _d.label = 3;
123
+ case 3:
124
+ i++;
125
+ return [3 /*break*/, 1];
126
+ case 4: return [2 /*return*/, answers];
127
+ }
128
+ });
129
+ }); };
130
+ var createAccount = function (email) { return __awaiter(void 0, void 0, void 0, function () {
131
+ var user, _a, _b, _c;
132
+ var _d;
133
+ return __generator(this, function (_e) {
134
+ switch (_e.label) {
135
+ case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Throttle User', email: email })];
136
+ case 1:
137
+ user = _e.sent();
138
+ _b = (_a = (0, db_1.getDbAsSystem)()).update;
139
+ _c = [user_1.tables.User];
140
+ _d = { id: user.id };
141
+ return [4 /*yield*/, new PasswordHasher_1.PasswordHasher().hash(RIGHT_PASSWORD)];
142
+ case 2: return [4 /*yield*/, _b.apply(_a, _c.concat([(_d.password = _e.sent(), _d)]))];
143
+ case 3:
144
+ _e.sent();
145
+ return [2 /*return*/, user];
146
+ }
147
+ });
148
+ }); };
149
+ var elapsedMs = function (run) { return __awaiter(void 0, void 0, void 0, function () {
150
+ var start;
151
+ return __generator(this, function (_a) {
152
+ switch (_a.label) {
153
+ case 0:
154
+ start = process.hrtime.bigint();
155
+ return [4 /*yield*/, run()];
156
+ case 1:
157
+ _a.sent();
158
+ return [2 /*return*/, Number(process.hrtime.bigint() - start) / 1e6];
159
+ }
160
+ });
161
+ }); };
162
+ var median = function (values) { return __spreadArray([], values, true).sort(function (a, b) { return a - b; })[Math.floor(values.length / 2)]; };
163
+ /** Log text without terminal colour codes. */
164
+ var plain = function (text) { return text.replace(new RegExp("".concat(String.fromCharCode(27), "\\[[0-9;]*m"), 'g'), ''); };
165
+ /** The `field: '<16 hex>'` values on the lines that contain `marker`. */
166
+ var fieldsOn = function (log, marker, field) {
167
+ return log.lines
168
+ .map(plain)
169
+ .filter(function (line) { return line.includes(marker); })
170
+ .map(function (line) { var _a, _b; return (_b = (_a = new RegExp("".concat(field, ": '([0-9a-f]{16})'")).exec(line)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : 'missing'; });
171
+ };
172
+ describe('login route throttle', function () {
173
+ var originalSecret = process.env.SESSION_SECRET;
174
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
175
+ return __generator(this, function (_a) {
176
+ switch (_a.label) {
177
+ case 0:
178
+ process.env.SESSION_SECRET = 'login-throttle-test-secret';
179
+ return [4 /*yield*/, testEnv.beforeAll()];
180
+ case 1:
181
+ _a.sent();
182
+ return [2 /*return*/];
183
+ }
184
+ });
185
+ }); }, 120000);
186
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
187
+ return __generator(this, function (_a) {
188
+ switch (_a.label) {
189
+ case 0:
190
+ if (originalSecret === undefined) {
191
+ delete process.env.SESSION_SECRET;
192
+ }
193
+ else {
194
+ process.env.SESSION_SECRET = originalSecret;
195
+ }
196
+ return [4 /*yield*/, testEnv.afterAll()];
197
+ case 1:
198
+ _a.sent();
199
+ return [2 /*return*/];
200
+ }
201
+ });
202
+ }); });
203
+ it('ten wrong passwords are refused as today; the eleventh try — even with the right password — is "Too many attempts…" and no session', function () { return __awaiter(void 0, void 0, void 0, function () {
204
+ var ip, email, _a, _b, right;
205
+ return __generator(this, function (_c) {
206
+ switch (_c.label) {
207
+ case 0: return [4 /*yield*/, createAccount('throttle-known@test.local')];
208
+ case 1:
209
+ _c.sent();
210
+ ip = function (i) { return "198.51.100.".concat(i + 1); };
211
+ email = function (i) { return (i % 2 ? 'Throttle-Known@Test.local' : 'throttle-known@test.local'); };
212
+ _a = expect;
213
+ return [4 /*yield*/, errors(10, ip, email, 'wrong guess')];
214
+ case 2:
215
+ _a.apply(void 0, [_c.sent()]).toEqual(Array(10).fill(WRONG));
216
+ _b = expect;
217
+ return [4 /*yield*/, attempt('198.51.100.50', 'throttle-known@test.local', 'wrong guess')];
218
+ case 3:
219
+ _b.apply(void 0, [(_c.sent()).sent]).toEqual({
220
+ error: THROTTLED,
221
+ });
222
+ return [4 /*yield*/, attempt('198.51.100.51', 'throttle-known@test.local', RIGHT_PASSWORD)];
223
+ case 4:
224
+ right = _c.sent();
225
+ expect(right.sent).toEqual({ error: THROTTLED });
226
+ expect(right.signedInAs).toBeUndefined();
227
+ return [2 /*return*/];
228
+ }
229
+ });
230
+ }); });
231
+ it('an address with no account walks the same steps with the same answers', function () { return __awaiter(void 0, void 0, void 0, function () {
232
+ var ip, email, _a, _b;
233
+ return __generator(this, function (_c) {
234
+ switch (_c.label) {
235
+ case 0:
236
+ ip = function (i) { return "198.51.101.".concat(i + 1); };
237
+ email = function () { return 'throttle-nobody@test.local'; };
238
+ _a = expect;
239
+ return [4 /*yield*/, errors(10, ip, email, 'wrong guess')];
240
+ case 1:
241
+ _a.apply(void 0, [_c.sent()]).toEqual(Array(10).fill(WRONG));
242
+ _b = expect;
243
+ return [4 /*yield*/, attempt('198.51.101.50', 'throttle-nobody@test.local', 'wrong guess')];
244
+ case 2:
245
+ _b.apply(void 0, [(_c.sent()).sent]).toEqual({
246
+ error: THROTTLED,
247
+ });
248
+ return [2 /*return*/];
249
+ }
250
+ });
251
+ }); });
252
+ it("a success clears the account's count: after it, ten more wrong tries are refused as usual before the throttle", function () { return __awaiter(void 0, void 0, void 0, function () {
253
+ var ip, email, _a, success, again, _b, _c;
254
+ return __generator(this, function (_d) {
255
+ switch (_d.label) {
256
+ case 0: return [4 /*yield*/, createAccount('throttle-cleared@test.local')];
257
+ case 1:
258
+ _d.sent();
259
+ ip = function (i) { return "198.51.102.".concat(i + 1); };
260
+ email = function () { return 'throttle-cleared@test.local'; };
261
+ _a = expect;
262
+ return [4 /*yield*/, errors(9, ip, email, 'wrong guess')];
263
+ case 2:
264
+ _a.apply(void 0, [_d.sent()]).toEqual(Array(9).fill(WRONG));
265
+ return [4 /*yield*/, attempt('198.51.102.100', 'throttle-cleared@test.local', RIGHT_PASSWORD)];
266
+ case 3:
267
+ success = _d.sent();
268
+ expect(success.sent).toEqual({});
269
+ expect(success.signedInAs).toBe('throttle-cleared@test.local');
270
+ again = function (i) { return "198.51.102.".concat(i + 120); };
271
+ _b = expect;
272
+ return [4 /*yield*/, errors(10, again, email, 'wrong guess')];
273
+ case 4:
274
+ _b.apply(void 0, [_d.sent()]).toEqual(Array(10).fill(WRONG));
275
+ _c = expect;
276
+ return [4 /*yield*/, attempt('198.51.102.200', 'throttle-cleared@test.local', 'wrong guess')];
277
+ case 5:
278
+ _c.apply(void 0, [(_d.sent()).sent]).toEqual({
279
+ error: THROTTLED,
280
+ });
281
+ return [2 /*return*/];
282
+ }
283
+ });
284
+ }); });
285
+ it('fifty wrong tries from one client address across fifty accounts, then the same answer for any account; another address is unaffected', function () { return __awaiter(void 0, void 0, void 0, function () {
286
+ var ip, email, _a, right, elsewhere;
287
+ return __generator(this, function (_b) {
288
+ switch (_b.label) {
289
+ case 0: return [4 /*yield*/, createAccount('throttle-ip-target@test.local')];
290
+ case 1:
291
+ _b.sent();
292
+ ip = function () { return '203.0.113.20'; };
293
+ email = function (i) { return "throttle-ip-".concat(i, "@test.local"); };
294
+ _a = expect;
295
+ return [4 /*yield*/, errors(50, ip, email, 'wrong guess')];
296
+ case 2:
297
+ _a.apply(void 0, [_b.sent()]).toEqual(Array(50).fill(WRONG));
298
+ return [4 /*yield*/, attempt('203.0.113.20', 'throttle-ip-target@test.local', RIGHT_PASSWORD)];
299
+ case 3:
300
+ right = _b.sent();
301
+ expect(right.sent).toEqual({ error: THROTTLED });
302
+ expect(right.signedInAs).toBeUndefined();
303
+ return [4 /*yield*/, attempt('203.0.113.21', 'throttle-ip-target@test.local', RIGHT_PASSWORD)];
304
+ case 4:
305
+ elsewhere = _b.sent();
306
+ expect(elsewhere.sent).toEqual({});
307
+ expect(elsewhere.signedInAs).toBe('throttle-ip-target@test.local');
308
+ return [2 /*return*/];
309
+ }
310
+ });
311
+ }); });
312
+ it('successes never count against the address: thirty sign-ins from one address, then fifty wrong tries are still judged before the window shuts', function () { return __awaiter(void 0, void 0, void 0, function () {
313
+ var ip, i, signedIn, email, _a, _b;
314
+ return __generator(this, function (_c) {
315
+ switch (_c.label) {
316
+ case 0: return [4 /*yield*/, createAccount('throttle-office@test.local')];
317
+ case 1:
318
+ _c.sent();
319
+ ip = function () { return '203.0.113.30'; };
320
+ i = 0;
321
+ _c.label = 2;
322
+ case 2:
323
+ if (!(i < 30)) return [3 /*break*/, 5];
324
+ return [4 /*yield*/, attempt(ip(), 'throttle-office@test.local', RIGHT_PASSWORD)];
325
+ case 3:
326
+ signedIn = _c.sent();
327
+ expect(signedIn.sent).toEqual({});
328
+ expect(signedIn.signedInAs).toBe('throttle-office@test.local');
329
+ _c.label = 4;
330
+ case 4:
331
+ i++;
332
+ return [3 /*break*/, 2];
333
+ case 5:
334
+ email = function (i) { return "throttle-office-guess-".concat(i, "@test.local"); };
335
+ _a = expect;
336
+ return [4 /*yield*/, errors(50, ip, email, 'wrong guess')];
337
+ case 6:
338
+ _a.apply(void 0, [_c.sent()]).toEqual(Array(50).fill(WRONG));
339
+ _b = expect;
340
+ return [4 /*yield*/, attempt(ip(), 'throttle-office@test.local', RIGHT_PASSWORD)];
341
+ case 7:
342
+ _b.apply(void 0, [(_c.sent()).sent]).toEqual({ error: THROTTLED });
343
+ return [2 /*return*/];
344
+ }
345
+ });
346
+ }); });
347
+ it("blank submissions count toward the client address's window, never an account's", function () { return __awaiter(void 0, void 0, void 0, function () {
348
+ var ip, _a, _b, _c, _d;
349
+ return __generator(this, function (_e) {
350
+ switch (_e.label) {
351
+ case 0: return [4 /*yield*/, createAccount('throttle-blank@test.local')];
352
+ case 1:
353
+ _e.sent();
354
+ ip = function (i) { return "192.0.2.".concat(i + 1); };
355
+ _a = expect;
356
+ return [4 /*yield*/, errors(15, ip, function () { return 'throttle-blank@test.local'; }, '')];
357
+ case 2:
358
+ _a.apply(void 0, [_e.sent()]).toEqual(Array(15).fill(BLANK));
359
+ _b = expect;
360
+ return [4 /*yield*/, attempt('192.0.2.100', 'throttle-blank@test.local', 'wrong guess')];
361
+ case 3:
362
+ _b.apply(void 0, [(_e.sent()).sent]).toEqual({ error: WRONG });
363
+ // Fifty blank submissions from one address: its fifty-first try is throttled.
364
+ _c = expect;
365
+ return [4 /*yield*/, errors(50, function () { return '192.0.2.200'; }, function () { return ''; }, '')];
366
+ case 4:
367
+ // Fifty blank submissions from one address: its fifty-first try is throttled.
368
+ _c.apply(void 0, [_e.sent()]).toEqual(Array(50).fill(BLANK));
369
+ _d = expect;
370
+ return [4 /*yield*/, attempt('192.0.2.200', 'throttle-blank@test.local', RIGHT_PASSWORD)];
371
+ case 5:
372
+ _d.apply(void 0, [(_e.sent()).sent]).toEqual({
373
+ error: THROTTLED,
374
+ });
375
+ return [2 /*return*/];
376
+ }
377
+ });
378
+ }); });
379
+ it('no timing tell: the throttled answer takes as long as a refused password, and an address with no account is refused as slowly as one with', function () { return __awaiter(void 0, void 0, void 0, function () {
380
+ var refused, unknown, throttled, _loop_1, i, _a, r, u, t;
381
+ return __generator(this, function (_b) {
382
+ switch (_b.label) {
383
+ case 0: return [4 /*yield*/, createAccount('throttle-timing-open@test.local')];
384
+ case 1:
385
+ _b.sent();
386
+ return [4 /*yield*/, createAccount('throttle-timing-shut@test.local')];
387
+ case 2:
388
+ _b.sent();
389
+ // Push one account over its window (from addresses the samples never use).
390
+ return [4 /*yield*/, errors(10, function (i) { return "100.64.0.".concat(i + 1); }, function () { return 'throttle-timing-shut@test.local'; }, 'wrong guess')];
391
+ case 3:
392
+ // Push one account over its window (from addresses the samples never use).
393
+ _b.sent();
394
+ refused = [];
395
+ unknown = [];
396
+ throttled = [];
397
+ _loop_1 = function (i) {
398
+ var _c, _d, _e, _f, _g, _h;
399
+ return __generator(this, function (_j) {
400
+ switch (_j.label) {
401
+ case 0:
402
+ _d = (_c = refused).push;
403
+ return [4 /*yield*/, elapsedMs(function () { return attempt("100.64.1.".concat(i + 1), 'throttle-timing-open@test.local', 'wrong guess'); })];
404
+ case 1:
405
+ _d.apply(_c, [_j.sent()]);
406
+ _f = (_e = unknown).push;
407
+ return [4 /*yield*/, elapsedMs(function () { return attempt("100.64.2.".concat(i + 1), 'throttle-timing-none@test.local', 'wrong guess'); })];
408
+ case 2:
409
+ _f.apply(_e, [_j.sent()]);
410
+ _h = (_g = throttled).push;
411
+ return [4 /*yield*/, elapsedMs(function () { return attempt("100.64.3.".concat(i + 1), 'throttle-timing-shut@test.local', 'wrong guess'); })];
412
+ case 3:
413
+ _h.apply(_g, [_j.sent()]);
414
+ return [2 /*return*/];
415
+ }
416
+ });
417
+ };
418
+ i = 0;
419
+ _b.label = 4;
420
+ case 4:
421
+ if (!(i < 7)) return [3 /*break*/, 7];
422
+ return [5 /*yield**/, _loop_1(i)];
423
+ case 5:
424
+ _b.sent();
425
+ _b.label = 6;
426
+ case 6:
427
+ i++;
428
+ return [3 /*break*/, 4];
429
+ case 7:
430
+ _a = [median(refused), median(unknown), median(throttled)], r = _a[0], u = _a[1], t = _a[2];
431
+ // A refusal costs one database read and one password verification (argon2, tens of ms).
432
+ // The tolerance is wide on purpose — a throttled answer or an unknown address that SKIPPED
433
+ // the verification lands near zero or at the read alone, far outside it.
434
+ expect(t / r).toBeGreaterThan(0.6);
435
+ expect(t / r).toBeLessThan(1.6);
436
+ expect(u / r).toBeGreaterThan(0.6);
437
+ expect(u / r).toBeLessThan(1.6);
438
+ return [2 /*return*/];
439
+ }
440
+ });
441
+ }); });
442
+ it('every refusal and every throttled answer is its own line with the account digest and the coarse IP hash — one digest per address however typed, never the address', function () { return __awaiter(void 0, void 0, void 0, function () {
443
+ var spellings, log, refusedAccounts, throttledAccounts, person, ips, text, _i, _a, fragment;
444
+ return __generator(this, function (_b) {
445
+ switch (_b.label) {
446
+ case 0: return [4 /*yield*/, createAccount('throttle.privacy.person@test.local')];
447
+ case 1:
448
+ _b.sent();
449
+ spellings = [
450
+ 'throttle.privacy.person@test.local',
451
+ 'Throttle.Privacy.Person@TEST.local',
452
+ ' THROTTLE.PRIVACY.PERSON@test.local',
453
+ ];
454
+ return [4 /*yield*/, LogCapture_1.LogCapture.during(function () { return __awaiter(void 0, void 0, void 0, function () {
455
+ var i;
456
+ return __generator(this, function (_a) {
457
+ switch (_a.label) {
458
+ case 0:
459
+ i = 0;
460
+ _a.label = 1;
461
+ case 1:
462
+ if (!(i < 11)) return [3 /*break*/, 4];
463
+ return [4 /*yield*/, attempt('198.51.103.7', spellings[i % 3], 'wrong guess')];
464
+ case 2:
465
+ _a.sent();
466
+ _a.label = 3;
467
+ case 3:
468
+ i++;
469
+ return [3 /*break*/, 1];
470
+ case 4: return [4 /*yield*/, attempt('198.51.103.8', 'throttle.privacy.other@test.local', 'wrong guess')];
471
+ case 5:
472
+ _a.sent();
473
+ return [4 /*yield*/, attempt('198.51.103.8', '', '')];
474
+ case 6:
475
+ _a.sent();
476
+ return [2 /*return*/];
477
+ }
478
+ });
479
+ }); })];
480
+ case 2:
481
+ log = _b.sent();
482
+ refusedAccounts = fieldsOn(log, 'Sign-in refused', 'account');
483
+ throttledAccounts = fieldsOn(log, 'Sign-in throttled', 'account');
484
+ // Ten for the person, one for the other address, one for the blank submission (no account).
485
+ expect(refusedAccounts).toHaveLength(12);
486
+ expect(throttledAccounts).toHaveLength(1);
487
+ person = refusedAccounts[0];
488
+ expect(person).toMatch(/^[0-9a-f]{16}$/);
489
+ expect(refusedAccounts.slice(0, 10)).toEqual(Array(10).fill(person));
490
+ expect(throttledAccounts).toEqual([person]);
491
+ expect(refusedAccounts[10]).toMatch(/^[0-9a-f]{16}$/);
492
+ expect(refusedAccounts[10]).not.toBe(person);
493
+ expect(refusedAccounts[11]).toBe('missing');
494
+ ips = __spreadArray(__spreadArray([], fieldsOn(log, 'Sign-in refused', 'ip'), true), fieldsOn(log, 'Sign-in throttled', 'ip'), true);
495
+ expect(ips).toHaveLength(13);
496
+ expect(new Set(ips.slice(0, 10)).size).toBe(1);
497
+ expect(ips[10]).not.toBe(ips[0]);
498
+ expect(ips[12]).toBe(ips[0]);
499
+ text = plain(log.text).toLowerCase();
500
+ for (_i = 0, _a = ['throttle.privacy.person', 'throttle.privacy.other', 'throttle.privacy', '198.51.103.']; _i < _a.length; _i++) {
501
+ fragment = _a[_i];
502
+ expect(text).not.toContain(fragment);
503
+ }
504
+ return [2 /*return*/];
505
+ }
506
+ });
507
+ }); });
508
+ it('thirty wrong passwords for one account fired at once from thirty addresses: at most ten are judged, the rest are throttled', function () { return __awaiter(void 0, void 0, void 0, function () {
509
+ var answers, judged, throttled, _a;
510
+ return __generator(this, function (_b) {
511
+ switch (_b.label) {
512
+ case 0: return [4 /*yield*/, createAccount('throttle-burst@test.local')];
513
+ case 1:
514
+ _b.sent();
515
+ return [4 /*yield*/, Promise.all(Array.from({ length: 30 }, function (_, i) { return attempt("198.51.104.".concat(i + 1), 'throttle-burst@test.local', 'wrong guess'); }))];
516
+ case 2:
517
+ answers = _b.sent();
518
+ judged = answers.filter(function (answer) { var _a; return ((_a = answer.sent) === null || _a === void 0 ? void 0 : _a.error) === WRONG; }).length;
519
+ throttled = answers.filter(function (answer) { var _a; return ((_a = answer.sent) === null || _a === void 0 ? void 0 : _a.error) === THROTTLED; }).length;
520
+ expect(judged).toBeLessThanOrEqual(10);
521
+ expect(judged + throttled).toBe(30);
522
+ _a = expect;
523
+ return [4 /*yield*/, attempt('198.51.104.50', 'throttle-burst@test.local', RIGHT_PASSWORD)];
524
+ case 3:
525
+ _a.apply(void 0, [(_b.sent()).sent]).toEqual({
526
+ error: THROTTLED,
527
+ });
528
+ return [2 /*return*/];
529
+ }
530
+ });
531
+ }); });
532
+ it('a refusal for an account still in the legacy sha256 format takes as long as one in the current format', function () { return __awaiter(void 0, void 0, void 0, function () {
533
+ var legacy, current, legacyRow, _loop_2, i, ratio;
534
+ return __generator(this, function (_a) {
535
+ switch (_a.label) {
536
+ case 0: return [4 /*yield*/, createAccount('throttle-timing-current@test.local')];
537
+ case 1:
538
+ _a.sent();
539
+ return [4 /*yield*/, testEnv.createUser({ name: 'Throttle User', email: 'throttle-timing-legacy@test.local' })];
540
+ case 2:
541
+ legacy = _a.sent();
542
+ return [4 /*yield*/, (0, db_1.getDbAsSystem)().update(user_1.tables.User, {
543
+ id: legacy.id,
544
+ password: (0, crypto_1.createHash)('sha256').update(RIGHT_PASSWORD).digest('hex'),
545
+ })];
546
+ case 3:
547
+ _a.sent();
548
+ current = [];
549
+ legacyRow = [];
550
+ _loop_2 = function (i) {
551
+ var _b, _c, _d, _e;
552
+ return __generator(this, function (_f) {
553
+ switch (_f.label) {
554
+ case 0:
555
+ _c = (_b = current).push;
556
+ return [4 /*yield*/, elapsedMs(function () { return attempt("100.64.4.".concat(i + 1), 'throttle-timing-current@test.local', 'wrong guess'); })];
557
+ case 1:
558
+ _c.apply(_b, [_f.sent()]);
559
+ _e = (_d = legacyRow).push;
560
+ return [4 /*yield*/, elapsedMs(function () { return attempt("100.64.5.".concat(i + 1), 'throttle-timing-legacy@test.local', 'wrong guess'); })];
561
+ case 2:
562
+ _e.apply(_d, [_f.sent()]);
563
+ return [2 /*return*/];
564
+ }
565
+ });
566
+ };
567
+ i = 0;
568
+ _a.label = 4;
569
+ case 4:
570
+ if (!(i < 7)) return [3 /*break*/, 7];
571
+ return [5 /*yield**/, _loop_2(i)];
572
+ case 5:
573
+ _a.sent();
574
+ _a.label = 6;
575
+ case 6:
576
+ i++;
577
+ return [3 /*break*/, 4];
578
+ case 7:
579
+ ratio = median(legacyRow) / median(current);
580
+ expect(ratio).toBeGreaterThan(0.6);
581
+ expect(ratio).toBeLessThan(1.6);
582
+ return [2 /*return*/];
583
+ }
584
+ });
585
+ }); });
586
+ it('a field that is not text is a blank one: the door answers and never throws', function () { return __awaiter(void 0, void 0, void 0, function () {
587
+ var sent, response, request;
588
+ var _a;
589
+ return __generator(this, function (_b) {
590
+ switch (_b.label) {
591
+ case 0:
592
+ response = {
593
+ send: function (body) {
594
+ sent = body;
595
+ },
596
+ status: function () { return response; },
597
+ };
598
+ return [4 /*yield*/, (0, passportSessionHarness_1.createPassportRequest)({
599
+ body: { email: 123, password: { not: 'text' } },
600
+ headers: {},
601
+ socket: { remoteAddress: '198.51.105.1' },
602
+ app: { get: function () { return false; } },
603
+ })];
604
+ case 1:
605
+ request = (_b.sent()).request;
606
+ return [4 /*yield*/, login_1.login.onRequest(request, response)];
607
+ case 2:
608
+ _b.sent();
609
+ expect(sent).toEqual({ error: BLANK });
610
+ expect((_a = request.session.passport) === null || _a === void 0 ? void 0 : _a.user).toBeUndefined();
611
+ return [2 /*return*/];
612
+ }
613
+ });
614
+ }); });
615
+ });
616
+ //# sourceMappingURL=LoginThrottle.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoginThrottle.integration.test.js","sourceRoot":"","sources":["../../test/LoginThrottle.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The `token` field of a request that does not carry a well-formed reset token: every type a
3
+ * parsed body or query string can deliver, and every near-miss of the token's shape. The
4
+ * near-misses are cut from a LIVE token, so a shape check that loosens (a lost anchor, a wider
5
+ * length, a case-insensitive class, a missing type check) would be looking up something derived
6
+ * from a real credential — and the suites that use this table assert that no lookup is built.
7
+ */
8
+ export declare class MalformedResetTokens {
9
+ static readonly CASES: [label: string, tokenField: (liveToken: string) => Record<string, unknown>][];
10
+ }
11
+ //# sourceMappingURL=MalformedResetTokens.d.ts.map