@proteinjs/user-server 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/generated/index.js +11 -1
- package/dist/generated/index.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/src/authentication/DbSessionStore.d.ts +3 -2
- package/dist/src/authentication/DbSessionStore.d.ts.map +1 -1
- package/dist/src/authentication/DbSessionStore.js +3 -2
- package/dist/src/authentication/DbSessionStore.js.map +1 -1
- package/dist/src/authentication/PasswordHasher.d.ts +45 -0
- package/dist/src/authentication/PasswordHasher.d.ts.map +1 -0
- package/dist/src/authentication/PasswordHasher.js +152 -0
- package/dist/src/authentication/PasswordHasher.js.map +1 -0
- package/dist/src/authentication/UserStatusTableWatcher.d.ts +19 -0
- package/dist/src/authentication/UserStatusTableWatcher.d.ts.map +1 -0
- package/dist/src/authentication/UserStatusTableWatcher.js +115 -0
- package/dist/src/authentication/UserStatusTableWatcher.js.map +1 -0
- package/dist/src/authentication/authenticate.d.ts.map +1 -1
- package/dist/src/authentication/authenticate.js +41 -13
- package/dist/src/authentication/authenticate.js.map +1 -1
- package/dist/src/authentication/establishSession.d.ts +30 -0
- package/dist/src/authentication/establishSession.d.ts.map +1 -0
- package/dist/src/authentication/establishSession.js +83 -0
- package/dist/src/authentication/establishSession.js.map +1 -0
- package/dist/src/authorization/userCache.d.ts.map +1 -1
- package/dist/src/authorization/userCache.js +10 -1
- package/dist/src/authorization/userCache.js.map +1 -1
- package/dist/src/emails/AccountDeletionEmailConfigs.d.ts +35 -0
- package/dist/src/emails/AccountDeletionEmailConfigs.d.ts.map +1 -0
- package/dist/src/emails/AccountDeletionEmailConfigs.js +36 -0
- package/dist/src/emails/AccountDeletionEmailConfigs.js.map +1 -0
- package/dist/src/emails/AccountDeletionEmails.d.ts +13 -0
- package/dist/src/emails/AccountDeletionEmails.d.ts.map +1 -0
- package/dist/src/emails/AccountDeletionEmails.js +98 -0
- package/dist/src/emails/AccountDeletionEmails.js.map +1 -0
- package/dist/src/routes/devLogin.d.ts.map +1 -1
- package/dist/src/routes/devLogin.js +6 -12
- package/dist/src/routes/devLogin.js.map +1 -1
- package/dist/src/routes/executePasswordReset.js +5 -3
- package/dist/src/routes/executePasswordReset.js.map +1 -1
- package/dist/src/routes/login.d.ts.map +1 -1
- package/dist/src/routes/login.js +27 -4
- package/dist/src/routes/login.js.map +1 -1
- package/dist/src/routes/logout.d.ts +10 -0
- package/dist/src/routes/logout.d.ts.map +1 -1
- package/dist/src/routes/logout.js +13 -32
- package/dist/src/routes/logout.js.map +1 -1
- package/dist/src/routes/signup.d.ts +19 -0
- package/dist/src/routes/signup.d.ts.map +1 -0
- package/dist/src/routes/signup.js +102 -0
- package/dist/src/routes/signup.js.map +1 -0
- package/dist/src/routes/validateResetPasswordToken.d.ts.map +1 -1
- package/dist/src/routes/validateResetPasswordToken.js +5 -1
- package/dist/src/routes/validateResetPasswordToken.js.map +1 -1
- package/dist/src/services/AccountDeletion.d.ts +52 -0
- package/dist/src/services/AccountDeletion.d.ts.map +1 -0
- package/dist/src/services/AccountDeletion.js +426 -0
- package/dist/src/services/AccountDeletion.js.map +1 -0
- package/dist/src/services/MachineCredentials.d.ts +21 -0
- package/dist/src/services/MachineCredentials.d.ts.map +1 -0
- package/dist/src/services/MachineCredentials.js +164 -0
- package/dist/src/services/MachineCredentials.js.map +1 -0
- package/dist/src/services/Roles.d.ts.map +1 -1
- package/dist/src/services/Roles.js +7 -0
- package/dist/src/services/Roles.js.map +1 -1
- package/dist/src/services/SetUserStatus.d.ts +18 -0
- package/dist/src/services/SetUserStatus.d.ts.map +1 -0
- package/dist/src/services/SetUserStatus.js +118 -0
- package/dist/src/services/SetUserStatus.js.map +1 -0
- package/dist/src/services/Signup.d.ts +20 -3
- package/dist/src/services/Signup.d.ts.map +1 -1
- package/dist/src/services/Signup.js +30 -19
- package/dist/src/services/Signup.js.map +1 -1
- package/dist/src/services/UpdateUserInfo.d.ts.map +1 -1
- package/dist/src/services/UpdateUserInfo.js +20 -17
- package/dist/src/services/UpdateUserInfo.js.map +1 -1
- package/dist/test/AccountDeletion.integration.test.d.ts +2 -0
- package/dist/test/AccountDeletion.integration.test.d.ts.map +1 -0
- package/dist/test/AccountDeletion.integration.test.js +718 -0
- package/dist/test/AccountDeletion.integration.test.js.map +1 -0
- package/dist/test/DevLogin.test.js +27 -31
- package/dist/test/DevLogin.test.js.map +1 -1
- package/dist/test/LogoutRoute.test.d.ts +2 -0
- package/dist/test/LogoutRoute.test.d.ts.map +1 -0
- package/dist/test/LogoutRoute.test.js +81 -0
- package/dist/test/LogoutRoute.test.js.map +1 -0
- package/dist/test/MachineAccounts.integration.test.d.ts +2 -0
- package/dist/test/MachineAccounts.integration.test.d.ts.map +1 -0
- package/dist/test/MachineAccounts.integration.test.js +597 -0
- package/dist/test/MachineAccounts.integration.test.js.map +1 -0
- package/dist/test/PasswordMigration.integration.test.d.ts +2 -0
- package/dist/test/PasswordMigration.integration.test.d.ts.map +1 -0
- package/dist/test/PasswordMigration.integration.test.js +332 -0
- package/dist/test/PasswordMigration.integration.test.js.map +1 -0
- package/dist/test/SetUserStatus.integration.test.d.ts +2 -0
- package/dist/test/SetUserStatus.integration.test.d.ts.map +1 -0
- package/dist/test/SetUserStatus.integration.test.js +266 -0
- package/dist/test/SetUserStatus.integration.test.js.map +1 -0
- package/dist/test/Signup.test.js +4 -2
- package/dist/test/Signup.test.js.map +1 -1
- package/dist/test/SignupRoute.test.d.ts +2 -0
- package/dist/test/SignupRoute.test.d.ts.map +1 -0
- package/dist/test/SignupRoute.test.js +338 -0
- package/dist/test/SignupRoute.test.js.map +1 -0
- package/dist/test/UserStatusGate.integration.test.d.ts +2 -0
- package/dist/test/UserStatusGate.integration.test.d.ts.map +1 -0
- package/dist/test/UserStatusGate.integration.test.js +162 -0
- package/dist/test/UserStatusGate.integration.test.js.map +1 -0
- package/dist/test/ValidateResetToken.test.d.ts +2 -0
- package/dist/test/ValidateResetToken.test.d.ts.map +1 -0
- package/dist/test/ValidateResetToken.test.js +170 -0
- package/dist/test/ValidateResetToken.test.js.map +1 -0
- package/dist/test/passportSessionHarness.d.ts +31 -0
- package/dist/test/passportSessionHarness.d.ts.map +1 -0
- package/dist/test/passportSessionHarness.js +107 -0
- package/dist/test/passportSessionHarness.js.map +1 -0
- package/generated/index.ts +11 -1
- package/index.ts +3 -0
- package/package.json +11 -7
- package/src/authentication/DbSessionStore.ts +3 -2
- package/src/authentication/PasswordHasher.ts +87 -0
- package/src/authentication/UserStatusTableWatcher.ts +56 -0
- package/src/authentication/authenticate.ts +31 -6
- package/src/authentication/establishSession.ts +33 -0
- package/src/authorization/userCache.ts +9 -1
- package/src/emails/AccountDeletionEmailConfigs.ts +79 -0
- package/src/emails/AccountDeletionEmails.ts +39 -0
- package/src/routes/devLogin.ts +4 -6
- package/src/routes/executePasswordReset.ts +2 -2
- package/src/routes/login.ts +25 -3
- package/src/routes/logout.ts +13 -18
- package/src/routes/signup.ts +55 -0
- package/src/routes/validateResetPasswordToken.ts +5 -1
- package/src/services/AccountDeletion.ts +291 -0
- package/src/services/MachineCredentials.ts +94 -0
- package/src/services/Roles.ts +10 -0
- package/src/services/SetUserStatus.ts +56 -0
- package/src/services/Signup.ts +25 -6
- package/src/services/UpdateUserInfo.ts +4 -5
- package/test/AccountDeletion.integration.test.ts +395 -0
- package/test/DevLogin.test.ts +16 -18
- package/test/LogoutRoute.test.ts +33 -0
- package/test/MachineAccounts.integration.test.ts +312 -0
- package/test/PasswordMigration.integration.test.ts +132 -0
- package/test/SetUserStatus.integration.test.ts +120 -0
- package/test/Signup.test.ts +4 -2
- package/test/SignupRoute.test.ts +219 -0
- package/test/UserStatusGate.integration.test.ts +68 -0
- package/test/ValidateResetToken.test.ts +86 -0
- package/test/passportSessionHarness.ts +58 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
var moment_1 = __importDefault(require("moment"));
|
|
43
|
+
var db_1 = require("@proteinjs/db");
|
|
44
|
+
var user_1 = require("@proteinjs/user");
|
|
45
|
+
var validateResetPasswordToken_1 = require("../src/routes/validateResetPasswordToken");
|
|
46
|
+
var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
|
|
47
|
+
var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
|
|
48
|
+
var invokeValidate = function (query) { return __awaiter(void 0, void 0, void 0, function () {
|
|
49
|
+
var outcome, response;
|
|
50
|
+
return __generator(this, function (_a) {
|
|
51
|
+
switch (_a.label) {
|
|
52
|
+
case 0:
|
|
53
|
+
outcome = {};
|
|
54
|
+
response = {
|
|
55
|
+
status: function (code) {
|
|
56
|
+
outcome.status = code;
|
|
57
|
+
return this;
|
|
58
|
+
},
|
|
59
|
+
send: function (body) {
|
|
60
|
+
outcome.body = body;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
return [4 /*yield*/, validateResetPasswordToken_1.validateResetPasswordToken.onRequest({ query: query }, response)];
|
|
64
|
+
case 1:
|
|
65
|
+
_a.sent();
|
|
66
|
+
return [2 /*return*/, outcome];
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}); };
|
|
70
|
+
var armResetToken = function (email, token, expiration) { return __awaiter(void 0, void 0, void 0, function () {
|
|
71
|
+
var user;
|
|
72
|
+
return __generator(this, function (_a) {
|
|
73
|
+
switch (_a.label) {
|
|
74
|
+
case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Reset User', email: email })];
|
|
75
|
+
case 1:
|
|
76
|
+
user = _a.sent();
|
|
77
|
+
return [4 /*yield*/, (0, db_1.getDbAsSystem)().update(user_1.tables.User, {
|
|
78
|
+
id: user.id,
|
|
79
|
+
passwordResetToken: token,
|
|
80
|
+
passwordResetTokenExpiration: expiration,
|
|
81
|
+
})];
|
|
82
|
+
case 2:
|
|
83
|
+
_a.sent();
|
|
84
|
+
return [2 /*return*/];
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}); };
|
|
88
|
+
describe('validateResetPasswordToken route', function () {
|
|
89
|
+
beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
90
|
+
return __generator(this, function (_a) {
|
|
91
|
+
switch (_a.label) {
|
|
92
|
+
case 0: return [4 /*yield*/, testEnv.beforeAll()];
|
|
93
|
+
case 1:
|
|
94
|
+
_a.sent();
|
|
95
|
+
return [2 /*return*/];
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}); });
|
|
99
|
+
afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
100
|
+
return __generator(this, function (_a) {
|
|
101
|
+
switch (_a.label) {
|
|
102
|
+
case 0: return [4 /*yield*/, testEnv.afterAll()];
|
|
103
|
+
case 1:
|
|
104
|
+
_a.sent();
|
|
105
|
+
return [2 /*return*/];
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}); });
|
|
109
|
+
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;
|
|
111
|
+
return __generator(this, function (_a) {
|
|
112
|
+
switch (_a.label) {
|
|
113
|
+
case 0: return [4 /*yield*/, armResetToken('reset-valid@test.local', 'tok-valid-1', (0, moment_1.default)().add(1, 'hour'))];
|
|
114
|
+
case 1:
|
|
115
|
+
_a.sent();
|
|
116
|
+
return [4 /*yield*/, invokeValidate({ token: 'tok-valid-1' })];
|
|
117
|
+
case 2:
|
|
118
|
+
outcome = _a.sent();
|
|
119
|
+
expect(outcome.status).toBe(200);
|
|
120
|
+
expect(outcome.body).toEqual({ isValid: true, email: 'reset-valid@test.local' });
|
|
121
|
+
return [2 /*return*/];
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}); });
|
|
125
|
+
it('an expired token resolves invalid and leaks no email', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
126
|
+
var outcome;
|
|
127
|
+
return __generator(this, function (_a) {
|
|
128
|
+
switch (_a.label) {
|
|
129
|
+
case 0: return [4 /*yield*/, armResetToken('reset-expired@test.local', 'tok-expired-1', (0, moment_1.default)().subtract(1, 'minute'))];
|
|
130
|
+
case 1:
|
|
131
|
+
_a.sent();
|
|
132
|
+
return [4 /*yield*/, invokeValidate({ token: 'tok-expired-1' })];
|
|
133
|
+
case 2:
|
|
134
|
+
outcome = _a.sent();
|
|
135
|
+
expect(outcome.status).toBe(200);
|
|
136
|
+
expect(outcome.body.isValid).toBe(false);
|
|
137
|
+
expect(outcome.body.email).toBeUndefined();
|
|
138
|
+
return [2 /*return*/];
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}); });
|
|
142
|
+
it('an unknown token resolves invalid and leaks no email', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
143
|
+
var outcome;
|
|
144
|
+
return __generator(this, function (_a) {
|
|
145
|
+
switch (_a.label) {
|
|
146
|
+
case 0: return [4 /*yield*/, invokeValidate({ token: 'tok-never-issued' })];
|
|
147
|
+
case 1:
|
|
148
|
+
outcome = _a.sent();
|
|
149
|
+
expect(outcome.status).toBe(200);
|
|
150
|
+
expect(outcome.body.isValid).toBe(false);
|
|
151
|
+
expect(outcome.body.email).toBeUndefined();
|
|
152
|
+
return [2 /*return*/];
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}); });
|
|
156
|
+
it('a missing token is a 400', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
157
|
+
var outcome;
|
|
158
|
+
return __generator(this, function (_a) {
|
|
159
|
+
switch (_a.label) {
|
|
160
|
+
case 0: return [4 /*yield*/, invokeValidate({})];
|
|
161
|
+
case 1:
|
|
162
|
+
outcome = _a.sent();
|
|
163
|
+
expect(outcome.status).toBe(400);
|
|
164
|
+
expect(outcome.body.isValid).toBe(false);
|
|
165
|
+
return [2 /*return*/];
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}); });
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=ValidateResetToken.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ValidateResetToken.test.js","sourceRoot":"","sources":["../../test/ValidateResetToken.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Session-lifecycle events in call order — the session-establishment contract under test. */
|
|
2
|
+
export type SessionEvent = 'regenerate' | 'login' | 'save';
|
|
3
|
+
export type PassportRequest = {
|
|
4
|
+
/** Express-shaped request whose `login`/`logout` are REAL passport machinery. */
|
|
5
|
+
request: any;
|
|
6
|
+
/**
|
|
7
|
+
* 'regenerate' / 'login' / 'save' in call order. The full contract of session establishment:
|
|
8
|
+
* regenerate FIRST (a fresh session id on privilege change — session fixation), then the bind
|
|
9
|
+
* of the account onto the fresh session, then save (the row must commit before the response).
|
|
10
|
+
*/
|
|
11
|
+
events: SessionEvent[];
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Builds a request whose `request.login` / `request.logout` are the GENUINE passport 0.6
|
|
15
|
+
* machinery, wired through `authenticator.initialize()` — the same middleware the server runs —
|
|
16
|
+
* over an express-session-shaped session mock.
|
|
17
|
+
*
|
|
18
|
+
* Why real passport and not a hand-mocked `login`: since passport 0.6 (the CVE-2022-25896
|
|
19
|
+
* session-fixation fix), the regenerate and the commit-before-response save live INSIDE
|
|
20
|
+
* `request.login` (SessionManager.logIn: regenerate → serializeUser → bind → save). A mocked
|
|
21
|
+
* `login` would assert nothing about either — the door suites must drive the real owner to
|
|
22
|
+
* prove the doors inherit the contract.
|
|
23
|
+
*
|
|
24
|
+
* serializeUser mirrors @proteinjs/server's identity pass-through (the session stores the
|
|
25
|
+
* account email directly), instrumented to record the bind ('login') between 'regenerate' and
|
|
26
|
+
* 'save'. The session mock replicates the one express-session behavior passport depends on:
|
|
27
|
+
* `regenerate` REPLACES `request.session` with a fresh session (new id, no passport state), so
|
|
28
|
+
* the bind provably lands on the post-regeneration session.
|
|
29
|
+
*/
|
|
30
|
+
export declare const createPassportRequest: (extra?: Record<string, unknown>) => Promise<PassportRequest>;
|
|
31
|
+
//# sourceMappingURL=passportSessionHarness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passportSessionHarness.d.ts","sourceRoot":"","sources":["../../test/passportSessionHarness.ts"],"names":[],"mappings":"AAEA,8FAA8F;AAC9F,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG;IAC5B,iFAAiF;IACjF,OAAO,EAAE,GAAG,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,qBAAqB,WAAiB,OAAO,MAAM,EAAE,OAAO,CAAC,KAAQ,QAAQ,eAAe,CAwBxG,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
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
|
+
exports.createPassportRequest = void 0;
|
|
54
|
+
var passport_1 = __importDefault(require("passport"));
|
|
55
|
+
/**
|
|
56
|
+
* Builds a request whose `request.login` / `request.logout` are the GENUINE passport 0.6
|
|
57
|
+
* machinery, wired through `authenticator.initialize()` — the same middleware the server runs —
|
|
58
|
+
* over an express-session-shaped session mock.
|
|
59
|
+
*
|
|
60
|
+
* Why real passport and not a hand-mocked `login`: since passport 0.6 (the CVE-2022-25896
|
|
61
|
+
* session-fixation fix), the regenerate and the commit-before-response save live INSIDE
|
|
62
|
+
* `request.login` (SessionManager.logIn: regenerate → serializeUser → bind → save). A mocked
|
|
63
|
+
* `login` would assert nothing about either — the door suites must drive the real owner to
|
|
64
|
+
* prove the doors inherit the contract.
|
|
65
|
+
*
|
|
66
|
+
* serializeUser mirrors @proteinjs/server's identity pass-through (the session stores the
|
|
67
|
+
* account email directly), instrumented to record the bind ('login') between 'regenerate' and
|
|
68
|
+
* 'save'. The session mock replicates the one express-session behavior passport depends on:
|
|
69
|
+
* `regenerate` REPLACES `request.session` with a fresh session (new id, no passport state), so
|
|
70
|
+
* the bind provably lands on the post-regeneration session.
|
|
71
|
+
*/
|
|
72
|
+
var createPassportRequest = function (extra) {
|
|
73
|
+
if (extra === void 0) { extra = {}; }
|
|
74
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
|
75
|
+
var events, authenticator, request, makeSession;
|
|
76
|
+
return __generator(this, function (_a) {
|
|
77
|
+
switch (_a.label) {
|
|
78
|
+
case 0:
|
|
79
|
+
events = [];
|
|
80
|
+
authenticator = new passport_1.default.Passport();
|
|
81
|
+
authenticator.serializeUser(function (user, done) {
|
|
82
|
+
events.push('login');
|
|
83
|
+
done(null, user);
|
|
84
|
+
});
|
|
85
|
+
request = __assign({}, extra);
|
|
86
|
+
makeSession = function () { return ({
|
|
87
|
+
regenerate: function (done) {
|
|
88
|
+
events.push('regenerate');
|
|
89
|
+
request.session = makeSession();
|
|
90
|
+
done();
|
|
91
|
+
},
|
|
92
|
+
save: function (done) {
|
|
93
|
+
events.push('save');
|
|
94
|
+
done();
|
|
95
|
+
},
|
|
96
|
+
}); };
|
|
97
|
+
request.session = makeSession();
|
|
98
|
+
return [4 /*yield*/, new Promise(function (resolve) { return authenticator.initialize()(request, {}, function () { return resolve(); }); })];
|
|
99
|
+
case 1:
|
|
100
|
+
_a.sent();
|
|
101
|
+
return [2 /*return*/, { request: request, events: events }];
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
exports.createPassportRequest = createPassportRequest;
|
|
107
|
+
//# sourceMappingURL=passportSessionHarness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passportSessionHarness.js","sourceRoot":"","sources":["../../test/passportSessionHarness.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sDAAgC;AAgBhC;;;;;;;;;;;;;;;;GAgBG;AACI,IAAM,qBAAqB,GAAG,UAAO,KAAmC;IAAnC,sBAAA,EAAA,UAAmC;;;;;;oBACvE,MAAM,GAAmB,EAAE,CAAC;oBAC5B,aAAa,GAAG,IAAI,kBAAQ,CAAC,QAAQ,EAAE,CAAC;oBAC9C,aAAa,CAAC,aAAa,CAAC,UAAC,IAAa,EAAE,IAA0C;wBACpF,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;wBACrB,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBACnB,CAAC,CAAC,CAAC;oBAEG,OAAO,gBAAa,KAAK,CAAE,CAAC;oBAC5B,WAAW,GAAG,cAAW,OAAA,CAAC;wBAC9B,UAAU,EAAE,UAAC,IAA6B;4BACxC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;4BAC1B,OAAO,CAAC,OAAO,GAAG,WAAW,EAAE,CAAC;4BAChC,IAAI,EAAE,CAAC;wBACT,CAAC;wBACD,IAAI,EAAE,UAAC,IAA6B;4BAClC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;4BACpB,IAAI,EAAE,CAAC;wBACT,CAAC;qBACF,CAAC,EAV6B,CAU7B,CAAC;oBACH,OAAO,CAAC,OAAO,GAAG,WAAW,EAAE,CAAC;oBAEhC,qBAAM,IAAI,OAAO,CAAO,UAAC,OAAO,IAAK,OAAA,aAAa,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,EAAW,EAAE,cAAM,OAAA,OAAO,EAAE,EAAT,CAAS,CAAC,EAAjE,CAAiE,CAAC,EAAA;;oBAAvG,SAAuG,CAAC;oBACxG,sBAAO,EAAE,OAAO,SAAA,EAAE,MAAM,QAAA,EAAE,EAAC;;;;CAC5B,CAAC;AAxBW,QAAA,qBAAqB,yBAwBhC"}
|