@proteinjs/user-server 1.21.0 → 1.21.1
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.
- package/CHANGELOG.md +11 -0
- package/dist/generated/index.js +1 -1
- package/dist/generated/index.js.map +1 -1
- package/dist/src/authentication/PasswordResetToken.d.ts +45 -0
- package/dist/src/authentication/PasswordResetToken.d.ts.map +1 -0
- package/dist/src/authentication/PasswordResetToken.js +138 -0
- package/dist/src/authentication/PasswordResetToken.js.map +1 -0
- package/dist/src/routes/executePasswordReset.d.ts +4 -4
- package/dist/src/routes/executePasswordReset.d.ts.map +1 -1
- package/dist/src/routes/executePasswordReset.js +27 -26
- package/dist/src/routes/executePasswordReset.js.map +1 -1
- package/dist/src/routes/initiatePasswordReset.js +2 -2
- package/dist/src/routes/initiatePasswordReset.js.map +1 -1
- package/dist/src/routes/validateResetPasswordToken.d.ts.map +1 -1
- package/dist/src/routes/validateResetPasswordToken.js +13 -16
- package/dist/src/routes/validateResetPasswordToken.js.map +1 -1
- package/dist/test/ExecutePasswordReset.test.d.ts +2 -0
- package/dist/test/ExecutePasswordReset.test.d.ts.map +1 -0
- package/dist/test/ExecutePasswordReset.test.js +394 -0
- package/dist/test/ExecutePasswordReset.test.js.map +1 -0
- package/dist/test/ValidateResetToken.test.js +30 -7
- package/dist/test/ValidateResetToken.test.js.map +1 -1
- package/generated/index.ts +1 -1
- package/package.json +2 -2
- package/src/authentication/PasswordResetToken.ts +96 -0
- package/src/routes/executePasswordReset.ts +25 -24
- package/src/routes/initiatePasswordReset.ts +2 -2
- package/src/routes/validateResetPasswordToken.ts +12 -15
- package/test/ExecutePasswordReset.test.ts +224 -0
- package/test/ValidateResetToken.test.ts +24 -6
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
50
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
|
+
};
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
var moment_1 = __importDefault(require("moment"));
|
|
54
|
+
var db_1 = require("@proteinjs/db");
|
|
55
|
+
var logger_1 = require("@proteinjs/logger");
|
|
56
|
+
var user_1 = require("@proteinjs/user");
|
|
57
|
+
var executePasswordReset_1 = require("../src/routes/executePasswordReset");
|
|
58
|
+
var PasswordHasher_1 = require("../src/authentication/PasswordHasher");
|
|
59
|
+
var PasswordResetToken_1 = require("../src/authentication/PasswordResetToken");
|
|
60
|
+
var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
|
|
61
|
+
var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
|
|
62
|
+
var invokeExecute = function (body) { return __awaiter(void 0, void 0, void 0, function () {
|
|
63
|
+
var outcome, response;
|
|
64
|
+
return __generator(this, function (_a) {
|
|
65
|
+
switch (_a.label) {
|
|
66
|
+
case 0:
|
|
67
|
+
outcome = { status: 200 };
|
|
68
|
+
response = {
|
|
69
|
+
status: function (code) {
|
|
70
|
+
outcome.status = code;
|
|
71
|
+
return this;
|
|
72
|
+
},
|
|
73
|
+
send: function (body) {
|
|
74
|
+
outcome.body = body;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
return [4 /*yield*/, executePasswordReset_1.executePasswordReset.onRequest({ body: body }, response)];
|
|
78
|
+
case 1:
|
|
79
|
+
_a.sent();
|
|
80
|
+
return [2 /*return*/, outcome];
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}); };
|
|
84
|
+
var mintToken = function () { return new PasswordResetToken_1.PasswordResetToken().mint(); };
|
|
85
|
+
var armResetToken = function (email, token, expiration) { return __awaiter(void 0, void 0, void 0, function () {
|
|
86
|
+
var user;
|
|
87
|
+
return __generator(this, function (_a) {
|
|
88
|
+
switch (_a.label) {
|
|
89
|
+
case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Reset User', email: email })];
|
|
90
|
+
case 1:
|
|
91
|
+
user = _a.sent();
|
|
92
|
+
return [4 /*yield*/, (0, db_1.getDbAsSystem)().update(user_1.tables.User, {
|
|
93
|
+
id: user.id,
|
|
94
|
+
passwordResetToken: token,
|
|
95
|
+
passwordResetTokenExpiration: expiration,
|
|
96
|
+
})];
|
|
97
|
+
case 2:
|
|
98
|
+
_a.sent();
|
|
99
|
+
return [2 /*return*/, user];
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}); };
|
|
103
|
+
var userRow = function (id) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
104
|
+
switch (_a.label) {
|
|
105
|
+
case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { id: id })];
|
|
106
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
107
|
+
}
|
|
108
|
+
}); }); };
|
|
109
|
+
/** Every password in the table, by email — the whole-table outcome a refused request must leave untouched. */
|
|
110
|
+
var passwordsByEmail = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
111
|
+
var byEmail, _i, _a, user;
|
|
112
|
+
return __generator(this, function (_b) {
|
|
113
|
+
switch (_b.label) {
|
|
114
|
+
case 0:
|
|
115
|
+
byEmail = {};
|
|
116
|
+
_i = 0;
|
|
117
|
+
return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.User, {})];
|
|
118
|
+
case 1:
|
|
119
|
+
_a = _b.sent();
|
|
120
|
+
_b.label = 2;
|
|
121
|
+
case 2:
|
|
122
|
+
if (!(_i < _a.length)) return [3 /*break*/, 4];
|
|
123
|
+
user = _a[_i];
|
|
124
|
+
byEmail[user.email] = user.password;
|
|
125
|
+
_b.label = 3;
|
|
126
|
+
case 3:
|
|
127
|
+
_i++;
|
|
128
|
+
return [3 /*break*/, 2];
|
|
129
|
+
case 4: return [2 /*return*/, byEmail];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}); };
|
|
133
|
+
describe('executePasswordReset route', function () {
|
|
134
|
+
beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
135
|
+
return __generator(this, function (_a) {
|
|
136
|
+
switch (_a.label) {
|
|
137
|
+
case 0: return [4 /*yield*/, testEnv.beforeAll()];
|
|
138
|
+
case 1:
|
|
139
|
+
_a.sent();
|
|
140
|
+
// No pending reset — the account a `null` token's `IS NULL` filter would match.
|
|
141
|
+
return [4 /*yield*/, testEnv.createUser({ name: 'Idle User', email: 'reset-idle@test.local' })];
|
|
142
|
+
case 2:
|
|
143
|
+
// No pending reset — the account a `null` token's `IS NULL` filter would match.
|
|
144
|
+
_a.sent();
|
|
145
|
+
// An emptied token column — the account an empty token would match.
|
|
146
|
+
return [4 /*yield*/, armResetToken('reset-emptied@test.local', '', (0, moment_1.default)().add(1, 'hour'))];
|
|
147
|
+
case 3:
|
|
148
|
+
// An emptied token column — the account an empty token would match.
|
|
149
|
+
_a.sent();
|
|
150
|
+
return [2 /*return*/];
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}); });
|
|
154
|
+
afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
155
|
+
return __generator(this, function (_a) {
|
|
156
|
+
switch (_a.label) {
|
|
157
|
+
case 0: return [4 /*yield*/, testEnv.afterAll()];
|
|
158
|
+
case 1:
|
|
159
|
+
_a.sent();
|
|
160
|
+
return [2 /*return*/];
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}); });
|
|
164
|
+
describe('a request without a well-formed token is refused before any lookup', function () {
|
|
165
|
+
it.each([
|
|
166
|
+
['absent', {}],
|
|
167
|
+
['null', { token: null }],
|
|
168
|
+
['empty', { token: '' }],
|
|
169
|
+
['not a token string', { token: 'tok-valid-1' }],
|
|
170
|
+
['a number', { token: 123 }],
|
|
171
|
+
['an array', { token: ['a', 'b'] }],
|
|
172
|
+
['an object', { token: { passwordResetToken: null } }],
|
|
173
|
+
])('%s: 400, and no password in the table changes', function (_label, tokenField) { return __awaiter(void 0, void 0, void 0, function () {
|
|
174
|
+
var before, outcome, _a;
|
|
175
|
+
return __generator(this, function (_b) {
|
|
176
|
+
switch (_b.label) {
|
|
177
|
+
case 0: return [4 /*yield*/, passwordsByEmail()];
|
|
178
|
+
case 1:
|
|
179
|
+
before = _b.sent();
|
|
180
|
+
return [4 /*yield*/, invokeExecute(__assign(__assign({}, tokenField), { newPassword: 'hijacked' }))];
|
|
181
|
+
case 2:
|
|
182
|
+
outcome = _b.sent();
|
|
183
|
+
expect(outcome.status).toBe(400);
|
|
184
|
+
expect(outcome.body).toEqual({ error: 'Invalid or expired reset token' });
|
|
185
|
+
_a = expect;
|
|
186
|
+
return [4 /*yield*/, passwordsByEmail()];
|
|
187
|
+
case 3:
|
|
188
|
+
_a.apply(void 0, [_b.sent()]).toEqual(before);
|
|
189
|
+
return [2 /*return*/];
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}); });
|
|
193
|
+
});
|
|
194
|
+
it('a live token resets the password once: the row verifies it, the token clears, a re-presentation is refused', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
195
|
+
var token, user, first, afterFirst, second, _a;
|
|
196
|
+
return __generator(this, function (_b) {
|
|
197
|
+
switch (_b.label) {
|
|
198
|
+
case 0:
|
|
199
|
+
token = mintToken();
|
|
200
|
+
return [4 /*yield*/, armResetToken('reset-live@test.local', token, (0, moment_1.default)().add(1, 'hour'))];
|
|
201
|
+
case 1:
|
|
202
|
+
user = _b.sent();
|
|
203
|
+
return [4 /*yield*/, invokeExecute({ token: token, newPassword: 'first new password' })];
|
|
204
|
+
case 2:
|
|
205
|
+
first = _b.sent();
|
|
206
|
+
expect(first.status).toBe(200);
|
|
207
|
+
expect(first.body).toEqual({ message: 'Password has been successfully reset' });
|
|
208
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
209
|
+
case 3:
|
|
210
|
+
afterFirst = _b.sent();
|
|
211
|
+
return [4 /*yield*/, expect(new PasswordHasher_1.PasswordHasher().verify(afterFirst.password, 'first new password')).resolves.toBe(true)];
|
|
212
|
+
case 4:
|
|
213
|
+
_b.sent();
|
|
214
|
+
expect(afterFirst.passwordResetToken).toBeNull();
|
|
215
|
+
expect(afterFirst.passwordResetTokenExpiration).toBeNull();
|
|
216
|
+
return [4 /*yield*/, invokeExecute({ token: token, newPassword: 'second new password' })];
|
|
217
|
+
case 5:
|
|
218
|
+
second = _b.sent();
|
|
219
|
+
expect(second.status).toBe(400);
|
|
220
|
+
_a = expect;
|
|
221
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
222
|
+
case 6:
|
|
223
|
+
_a.apply(void 0, [(_b.sent()).password]).toBe(afterFirst.password);
|
|
224
|
+
return [2 /*return*/];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}); });
|
|
228
|
+
it('an expired token is refused and changes nothing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
229
|
+
var token, user, before, outcome, row;
|
|
230
|
+
return __generator(this, function (_a) {
|
|
231
|
+
switch (_a.label) {
|
|
232
|
+
case 0:
|
|
233
|
+
token = mintToken();
|
|
234
|
+
return [4 /*yield*/, armResetToken('reset-expired@test.local', token, (0, moment_1.default)().subtract(1, 'minute'))];
|
|
235
|
+
case 1:
|
|
236
|
+
user = _a.sent();
|
|
237
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
238
|
+
case 2:
|
|
239
|
+
before = (_a.sent()).password;
|
|
240
|
+
return [4 /*yield*/, invokeExecute({ token: token, newPassword: 'hijacked' })];
|
|
241
|
+
case 3:
|
|
242
|
+
outcome = _a.sent();
|
|
243
|
+
expect(outcome.status).toBe(400);
|
|
244
|
+
expect(outcome.body).toEqual({ error: 'Reset token has expired' });
|
|
245
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
246
|
+
case 4:
|
|
247
|
+
row = _a.sent();
|
|
248
|
+
expect(row.password).toBe(before);
|
|
249
|
+
expect(row.passwordResetToken).toBe(token);
|
|
250
|
+
return [2 /*return*/];
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}); });
|
|
254
|
+
it('a token whose row carries no expiry is refused — never live by omission', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
255
|
+
var token, user, before, outcome, _a;
|
|
256
|
+
return __generator(this, function (_b) {
|
|
257
|
+
switch (_b.label) {
|
|
258
|
+
case 0:
|
|
259
|
+
token = mintToken();
|
|
260
|
+
return [4 /*yield*/, armResetToken('reset-no-expiry@test.local', token, null)];
|
|
261
|
+
case 1:
|
|
262
|
+
user = _b.sent();
|
|
263
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
264
|
+
case 2:
|
|
265
|
+
before = (_b.sent()).password;
|
|
266
|
+
return [4 /*yield*/, invokeExecute({ token: token, newPassword: 'hijacked' })];
|
|
267
|
+
case 3:
|
|
268
|
+
outcome = _b.sent();
|
|
269
|
+
expect(outcome.status).toBe(400);
|
|
270
|
+
_a = expect;
|
|
271
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
272
|
+
case 4:
|
|
273
|
+
_a.apply(void 0, [(_b.sent()).password]).toBe(before);
|
|
274
|
+
return [2 /*return*/];
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}); });
|
|
278
|
+
it('a blank new password is refused without consuming the token', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
279
|
+
var token, user, before, _i, _a, newPassword, outcome, row;
|
|
280
|
+
return __generator(this, function (_b) {
|
|
281
|
+
switch (_b.label) {
|
|
282
|
+
case 0:
|
|
283
|
+
token = mintToken();
|
|
284
|
+
return [4 /*yield*/, armResetToken('reset-blank@test.local', token, (0, moment_1.default)().add(1, 'hour'))];
|
|
285
|
+
case 1:
|
|
286
|
+
user = _b.sent();
|
|
287
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
288
|
+
case 2:
|
|
289
|
+
before = (_b.sent()).password;
|
|
290
|
+
_i = 0, _a = ['', undefined, 42];
|
|
291
|
+
_b.label = 3;
|
|
292
|
+
case 3:
|
|
293
|
+
if (!(_i < _a.length)) return [3 /*break*/, 6];
|
|
294
|
+
newPassword = _a[_i];
|
|
295
|
+
return [4 /*yield*/, invokeExecute({ token: token, newPassword: newPassword })];
|
|
296
|
+
case 4:
|
|
297
|
+
outcome = _b.sent();
|
|
298
|
+
expect(outcome.status).toBe(400);
|
|
299
|
+
_b.label = 5;
|
|
300
|
+
case 5:
|
|
301
|
+
_i++;
|
|
302
|
+
return [3 /*break*/, 3];
|
|
303
|
+
case 6: return [4 /*yield*/, userRow(user.id)];
|
|
304
|
+
case 7:
|
|
305
|
+
row = _b.sent();
|
|
306
|
+
expect(row.password).toBe(before);
|
|
307
|
+
expect(row.passwordResetToken).toBe(token);
|
|
308
|
+
return [2 /*return*/];
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}); });
|
|
312
|
+
it('the presented token never reaches the log', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
313
|
+
var token, info, _i, _a, entry;
|
|
314
|
+
return __generator(this, function (_b) {
|
|
315
|
+
switch (_b.label) {
|
|
316
|
+
case 0:
|
|
317
|
+
token = mintToken();
|
|
318
|
+
info = jest.spyOn(logger_1.Logger.prototype, 'info');
|
|
319
|
+
_b.label = 1;
|
|
320
|
+
case 1:
|
|
321
|
+
_b.trys.push([1, , 3, 4]);
|
|
322
|
+
return [4 /*yield*/, invokeExecute({ token: token, newPassword: 'hijacked' })];
|
|
323
|
+
case 2:
|
|
324
|
+
_b.sent();
|
|
325
|
+
expect(info).toHaveBeenCalled();
|
|
326
|
+
for (_i = 0, _a = info.mock.calls; _i < _a.length; _i++) {
|
|
327
|
+
entry = _a[_i][0];
|
|
328
|
+
expect(JSON.stringify(entry)).not.toContain(token);
|
|
329
|
+
}
|
|
330
|
+
return [3 /*break*/, 4];
|
|
331
|
+
case 3:
|
|
332
|
+
info.mockRestore();
|
|
333
|
+
return [7 /*endfinally*/];
|
|
334
|
+
case 4: return [2 /*return*/];
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}); });
|
|
338
|
+
describe('PasswordResetToken', function () {
|
|
339
|
+
var internals = new PasswordResetToken_1.PasswordResetToken();
|
|
340
|
+
it('mints 64 lowercase hex characters, fresh each time', function () {
|
|
341
|
+
var token = mintToken();
|
|
342
|
+
expect(token).toMatch(/^[0-9a-f]{64}$/);
|
|
343
|
+
expect(mintToken()).not.toBe(token);
|
|
344
|
+
});
|
|
345
|
+
it('a stored token matches only the same string — never an absent or emptied one', function () {
|
|
346
|
+
var token = mintToken();
|
|
347
|
+
expect(internals.matches(token, token)).toBe(true);
|
|
348
|
+
expect(internals.matches(mintToken(), token)).toBe(false);
|
|
349
|
+
expect(internals.matches(null, token)).toBe(false);
|
|
350
|
+
expect(internals.matches(undefined, token)).toBe(false);
|
|
351
|
+
expect(internals.matches('', token)).toBe(false);
|
|
352
|
+
});
|
|
353
|
+
it('an expiry is live only as a valid timestamp in the future', function () {
|
|
354
|
+
expect(internals.isLive((0, moment_1.default)().add(1, 'minute'))).toBe(true);
|
|
355
|
+
expect(internals.isLive((0, moment_1.default)().subtract(1, 'minute'))).toBe(false);
|
|
356
|
+
expect(internals.isLive(null)).toBe(false);
|
|
357
|
+
expect(internals.isLive(undefined)).toBe(false);
|
|
358
|
+
expect(internals.isLive(moment_1.default.invalid())).toBe(false);
|
|
359
|
+
});
|
|
360
|
+
it('redeem writes only while the row still carries the token', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
361
|
+
var live, user, before, _a, row;
|
|
362
|
+
return __generator(this, function (_b) {
|
|
363
|
+
switch (_b.label) {
|
|
364
|
+
case 0:
|
|
365
|
+
live = mintToken();
|
|
366
|
+
return [4 /*yield*/, armResetToken('reset-redeem@test.local', live, (0, moment_1.default)().add(1, 'hour'))];
|
|
367
|
+
case 1:
|
|
368
|
+
user = _b.sent();
|
|
369
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
370
|
+
case 2:
|
|
371
|
+
before = (_b.sent()).password;
|
|
372
|
+
return [4 /*yield*/, expect(new PasswordResetToken_1.PasswordResetToken().redeem(user, mintToken(), 'other-hash')).resolves.toBe(false)];
|
|
373
|
+
case 3:
|
|
374
|
+
_b.sent();
|
|
375
|
+
_a = expect;
|
|
376
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
377
|
+
case 4:
|
|
378
|
+
_a.apply(void 0, [(_b.sent()).password]).toBe(before);
|
|
379
|
+
return [4 /*yield*/, expect(new PasswordResetToken_1.PasswordResetToken().redeem(user, live, 'new-hash')).resolves.toBe(true)];
|
|
380
|
+
case 5:
|
|
381
|
+
_b.sent();
|
|
382
|
+
return [4 /*yield*/, userRow(user.id)];
|
|
383
|
+
case 6:
|
|
384
|
+
row = _b.sent();
|
|
385
|
+
expect(row.password).toBe('new-hash');
|
|
386
|
+
expect(row.passwordResetToken).toBeNull();
|
|
387
|
+
expect(row.passwordResetTokenExpiration).toBeNull();
|
|
388
|
+
return [2 /*return*/];
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
}); });
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
//# sourceMappingURL=ExecutePasswordReset.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecutePasswordReset.test.js","sourceRoot":"","sources":["../../test/ExecutePasswordReset.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,6 +43,7 @@ var moment_1 = __importDefault(require("moment"));
|
|
|
43
43
|
var db_1 = require("@proteinjs/db");
|
|
44
44
|
var user_1 = require("@proteinjs/user");
|
|
45
45
|
var validateResetPasswordToken_1 = require("../src/routes/validateResetPasswordToken");
|
|
46
|
+
var PasswordResetToken_1 = require("../src/authentication/PasswordResetToken");
|
|
46
47
|
var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
|
|
47
48
|
var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
|
|
48
49
|
var invokeValidate = function (query) { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -67,6 +68,7 @@ var invokeValidate = function (query) { return __awaiter(void 0, void 0, void 0,
|
|
|
67
68
|
}
|
|
68
69
|
});
|
|
69
70
|
}); };
|
|
71
|
+
var mintToken = function () { return new PasswordResetToken_1.PasswordResetToken().mint(); };
|
|
70
72
|
var armResetToken = function (email, token, expiration) { return __awaiter(void 0, void 0, void 0, function () {
|
|
71
73
|
var user;
|
|
72
74
|
return __generator(this, function (_a) {
|
|
@@ -107,13 +109,15 @@ describe('validateResetPasswordToken route', function () {
|
|
|
107
109
|
});
|
|
108
110
|
}); });
|
|
109
111
|
it('a valid token resolves isValid WITH the account email (the reset form identifier)', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
110
|
-
var outcome;
|
|
112
|
+
var token, outcome;
|
|
111
113
|
return __generator(this, function (_a) {
|
|
112
114
|
switch (_a.label) {
|
|
113
|
-
case 0:
|
|
115
|
+
case 0:
|
|
116
|
+
token = mintToken();
|
|
117
|
+
return [4 /*yield*/, armResetToken('reset-valid@test.local', token, (0, moment_1.default)().add(1, 'hour'))];
|
|
114
118
|
case 1:
|
|
115
119
|
_a.sent();
|
|
116
|
-
return [4 /*yield*/, invokeValidate({ token:
|
|
120
|
+
return [4 /*yield*/, invokeValidate({ token: token })];
|
|
117
121
|
case 2:
|
|
118
122
|
outcome = _a.sent();
|
|
119
123
|
expect(outcome.status).toBe(200);
|
|
@@ -123,13 +127,15 @@ describe('validateResetPasswordToken route', function () {
|
|
|
123
127
|
});
|
|
124
128
|
}); });
|
|
125
129
|
it('an expired token resolves invalid and leaks no email', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
126
|
-
var outcome;
|
|
130
|
+
var token, outcome;
|
|
127
131
|
return __generator(this, function (_a) {
|
|
128
132
|
switch (_a.label) {
|
|
129
|
-
case 0:
|
|
133
|
+
case 0:
|
|
134
|
+
token = mintToken();
|
|
135
|
+
return [4 /*yield*/, armResetToken('reset-expired@test.local', token, (0, moment_1.default)().subtract(1, 'minute'))];
|
|
130
136
|
case 1:
|
|
131
137
|
_a.sent();
|
|
132
|
-
return [4 /*yield*/, invokeValidate({ token:
|
|
138
|
+
return [4 /*yield*/, invokeValidate({ token: token })];
|
|
133
139
|
case 2:
|
|
134
140
|
outcome = _a.sent();
|
|
135
141
|
expect(outcome.status).toBe(200);
|
|
@@ -143,7 +149,7 @@ describe('validateResetPasswordToken route', function () {
|
|
|
143
149
|
var outcome;
|
|
144
150
|
return __generator(this, function (_a) {
|
|
145
151
|
switch (_a.label) {
|
|
146
|
-
case 0: return [4 /*yield*/, invokeValidate({ token:
|
|
152
|
+
case 0: return [4 /*yield*/, invokeValidate({ token: mintToken() })];
|
|
147
153
|
case 1:
|
|
148
154
|
outcome = _a.sent();
|
|
149
155
|
expect(outcome.status).toBe(200);
|
|
@@ -153,6 +159,23 @@ describe('validateResetPasswordToken route', function () {
|
|
|
153
159
|
}
|
|
154
160
|
});
|
|
155
161
|
}); });
|
|
162
|
+
it.each([
|
|
163
|
+
['a string of another shape', 'tok-never-issued'],
|
|
164
|
+
['a parsed array', ['a', 'b']],
|
|
165
|
+
['a parsed object', { passwordResetToken: null }],
|
|
166
|
+
])('%s resolves invalid without a lookup and leaks no email', function (_label, token) { return __awaiter(void 0, void 0, void 0, function () {
|
|
167
|
+
var outcome;
|
|
168
|
+
return __generator(this, function (_a) {
|
|
169
|
+
switch (_a.label) {
|
|
170
|
+
case 0: return [4 /*yield*/, invokeValidate({ token: token })];
|
|
171
|
+
case 1:
|
|
172
|
+
outcome = _a.sent();
|
|
173
|
+
expect(outcome.status).toBe(200);
|
|
174
|
+
expect(outcome.body).toEqual({ isValid: false, message: 'Invalid token' });
|
|
175
|
+
return [2 /*return*/];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}); });
|
|
156
179
|
it('a missing token is a 400', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
157
180
|
var outcome;
|
|
158
181
|
return __generator(this, function (_a) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidateResetToken.test.js","sourceRoot":"","sources":["../../test/ValidateResetToken.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAC5B,oCAA8C;AAC9C,wCAAyC;AACzC,uFAAsF;AACtF,yEAAwE;AAExE,IAAM,OAAO,GAAG,IAAI,qDAAyB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ValidateResetToken.test.js","sourceRoot":"","sources":["../../test/ValidateResetToken.test.ts"],"names":[],"mappings":"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"}
|