@proteinjs/user-server 1.17.0 → 1.19.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 +22 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/generated/index.js +3 -1
- package/dist/generated/index.js.map +1 -1
- package/dist/src/authorization/UserActivityStamp.d.ts +17 -15
- package/dist/src/authorization/UserActivityStamp.d.ts.map +1 -1
- package/dist/src/authorization/UserActivityStamp.js +21 -19
- package/dist/src/authorization/UserActivityStamp.js.map +1 -1
- package/dist/src/authorization/userCache.d.ts +9 -0
- package/dist/src/authorization/userCache.d.ts.map +1 -1
- package/dist/src/authorization/userCache.js +9 -9
- package/dist/src/authorization/userCache.js.map +1 -1
- package/dist/src/routes/devLogin.d.ts +10 -0
- package/dist/src/routes/devLogin.d.ts.map +1 -1
- package/dist/src/routes/devLogin.js +28 -9
- package/dist/src/routes/devLogin.js.map +1 -1
- package/dist/src/services/Roles.d.ts +20 -1
- package/dist/src/services/Roles.d.ts.map +1 -1
- package/dist/src/services/Roles.js +79 -3
- package/dist/src/services/Roles.js.map +1 -1
- package/dist/src/services/UserPresence.d.ts +16 -0
- package/dist/src/services/UserPresence.d.ts.map +1 -0
- package/dist/src/services/UserPresence.js +75 -0
- package/dist/src/services/UserPresence.js.map +1 -0
- package/dist/test/DevLogin.test.js +13 -41
- package/dist/test/DevLogin.test.js.map +1 -1
- package/dist/test/DevLoginBootstrapAdmin.test.d.ts +2 -0
- package/dist/test/DevLoginBootstrapAdmin.test.d.ts.map +1 -0
- package/dist/test/DevLoginBootstrapAdmin.test.js +384 -0
- package/dist/test/DevLoginBootstrapAdmin.test.js.map +1 -0
- package/dist/test/UserActivityStamp.integration.test.js +57 -90
- package/dist/test/UserActivityStamp.integration.test.js.map +1 -1
- package/dist/test/UserCacheDoesNotStampPresence.integration.test.d.ts +2 -0
- package/dist/test/UserCacheDoesNotStampPresence.integration.test.d.ts.map +1 -0
- package/dist/test/UserCacheDoesNotStampPresence.integration.test.js +117 -0
- package/dist/test/UserCacheDoesNotStampPresence.integration.test.js.map +1 -0
- package/dist/test/devLoginHarness.d.ts +16 -0
- package/dist/test/devLoginHarness.d.ts.map +1 -0
- package/dist/test/devLoginHarness.js +79 -0
- package/dist/test/devLoginHarness.js.map +1 -0
- package/generated/index.ts +3 -1
- package/package.json +3 -3
- package/src/authorization/UserActivityStamp.ts +22 -20
- package/src/authorization/userCache.ts +9 -9
- package/src/routes/devLogin.ts +17 -0
- package/src/services/Roles.ts +49 -4
- package/src/services/UserPresence.ts +26 -0
- package/test/DevLogin.test.ts +5 -36
- package/test/DevLoginBootstrapAdmin.test.ts +175 -0
- package/test/UserActivityStamp.integration.test.ts +38 -50
- package/test/UserCacheDoesNotStampPresence.integration.test.ts +44 -0
- package/test/devLoginHarness.ts +39 -0
|
@@ -39,8 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
var db_1 = require("@proteinjs/db");
|
|
40
40
|
var user_1 = require("@proteinjs/user");
|
|
41
41
|
var PasswordHasher_1 = require("../src/authentication/PasswordHasher");
|
|
42
|
-
var
|
|
43
|
-
var passportSessionHarness_1 = require("./passportSessionHarness");
|
|
42
|
+
var devLoginHarness_1 = require("./devLoginHarness");
|
|
44
43
|
var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
|
|
45
44
|
var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
|
|
46
45
|
/**
|
|
@@ -51,39 +50,10 @@ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
|
|
|
51
50
|
* - Double gate: `DEVELOPMENT` AND `DEV_AUTO_LOGIN_EMAIL` both present, else 404 (unchanged).
|
|
52
51
|
* - Domain rail: a `?email=` param must share `DEV_AUTO_LOGIN_EMAIL`'s domain — even a dev server
|
|
53
52
|
* must not mint sessions (much less accounts) for arbitrary domains. Others 400.
|
|
53
|
+
* The first-admin door (`DEV_BOOTSTRAP_ADMIN_EMAIL`) has its own suite, DevLoginBootstrapAdmin.test.ts;
|
|
54
|
+
* here the variable is unset, so every created account is role-less.
|
|
54
55
|
*/
|
|
55
56
|
var ENV_EMAIL = 'dev@test.local';
|
|
56
|
-
var invokeDevLogin = function (query) { return __awaiter(void 0, void 0, void 0, function () {
|
|
57
|
-
var _a, request, events, outcome, response;
|
|
58
|
-
var _b;
|
|
59
|
-
return __generator(this, function (_c) {
|
|
60
|
-
switch (_c.label) {
|
|
61
|
-
case 0: return [4 /*yield*/, (0, passportSessionHarness_1.createPassportRequest)({ query: query })];
|
|
62
|
-
case 1:
|
|
63
|
-
_a = _c.sent(), request = _a.request, events = _a.events;
|
|
64
|
-
outcome = { sessionRegenerated: false, sessionSaved: false };
|
|
65
|
-
response = {
|
|
66
|
-
status: function (code) {
|
|
67
|
-
outcome.status = code;
|
|
68
|
-
return this;
|
|
69
|
-
},
|
|
70
|
-
send: function (body) {
|
|
71
|
-
outcome.body = body;
|
|
72
|
-
},
|
|
73
|
-
redirect: function (path) {
|
|
74
|
-
outcome.redirect = path;
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
return [4 /*yield*/, devLogin_1.devLogin.onRequest(request, response)];
|
|
78
|
-
case 2:
|
|
79
|
-
_c.sent();
|
|
80
|
-
outcome.loggedInAs = (_b = request.session.passport) === null || _b === void 0 ? void 0 : _b.user;
|
|
81
|
-
outcome.sessionRegenerated = events.includes('regenerate');
|
|
82
|
-
outcome.sessionSaved = events.includes('save');
|
|
83
|
-
return [2 /*return*/, outcome];
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
}); };
|
|
87
57
|
var getUserRow = function (email) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
88
58
|
switch (_a.label) {
|
|
89
59
|
case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { email: email })];
|
|
@@ -94,6 +64,7 @@ describe('devLogin route', function () {
|
|
|
94
64
|
var originalEnv = {
|
|
95
65
|
DEVELOPMENT: process.env.DEVELOPMENT,
|
|
96
66
|
DEV_AUTO_LOGIN_EMAIL: process.env.DEV_AUTO_LOGIN_EMAIL,
|
|
67
|
+
DEV_BOOTSTRAP_ADMIN_EMAIL: process.env.DEV_BOOTSTRAP_ADMIN_EMAIL,
|
|
97
68
|
};
|
|
98
69
|
beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
99
70
|
return __generator(this, function (_a) {
|
|
@@ -118,6 +89,7 @@ describe('devLogin route', function () {
|
|
|
118
89
|
beforeEach(function () {
|
|
119
90
|
process.env.DEVELOPMENT = 'true';
|
|
120
91
|
process.env.DEV_AUTO_LOGIN_EMAIL = ENV_EMAIL;
|
|
92
|
+
delete process.env.DEV_BOOTSTRAP_ADMIN_EMAIL;
|
|
121
93
|
});
|
|
122
94
|
afterEach(function () {
|
|
123
95
|
for (var _i = 0, _a = Object.entries(originalEnv); _i < _a.length; _i++) {
|
|
@@ -137,7 +109,7 @@ describe('devLogin route', function () {
|
|
|
137
109
|
case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Dev Default', email: ENV_EMAIL })];
|
|
138
110
|
case 1:
|
|
139
111
|
_a.sent();
|
|
140
|
-
return [4 /*yield*/, invokeDevLogin()];
|
|
112
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)()];
|
|
141
113
|
case 2:
|
|
142
114
|
outcome = _a.sent();
|
|
143
115
|
expect(outcome.loggedInAs).toBe(ENV_EMAIL);
|
|
@@ -156,7 +128,7 @@ describe('devLogin route', function () {
|
|
|
156
128
|
case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Agent Two', email: 'agent2@test.local' })];
|
|
157
129
|
case 1:
|
|
158
130
|
_a.sent();
|
|
159
|
-
return [4 /*yield*/, invokeDevLogin({ email: 'agent2@test.local' })];
|
|
131
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'agent2@test.local' })];
|
|
160
132
|
case 2:
|
|
161
133
|
outcome = _a.sent();
|
|
162
134
|
expect(outcome.loggedInAs).toBe('agent2@test.local');
|
|
@@ -175,7 +147,7 @@ describe('devLogin route', function () {
|
|
|
175
147
|
return [4 /*yield*/, getUserRow('agent3@test.local')];
|
|
176
148
|
case 1:
|
|
177
149
|
_a.apply(void 0, [_c.sent()]).toBeUndefined();
|
|
178
|
-
return [4 /*yield*/, invokeDevLogin({ email: 'agent3@test.local' })];
|
|
150
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'agent3@test.local' })];
|
|
179
151
|
case 2:
|
|
180
152
|
outcome = _c.sent();
|
|
181
153
|
expect(outcome.loggedInAs).toBe('agent3@test.local');
|
|
@@ -200,7 +172,7 @@ describe('devLogin route', function () {
|
|
|
200
172
|
var outcome, _a;
|
|
201
173
|
return __generator(this, function (_b) {
|
|
202
174
|
switch (_b.label) {
|
|
203
|
-
case 0: return [4 /*yield*/, invokeDevLogin({ email: 'intruder@evil.example' })];
|
|
175
|
+
case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'intruder@evil.example' })];
|
|
204
176
|
case 1:
|
|
205
177
|
outcome = _b.sent();
|
|
206
178
|
expect(outcome.status).toBe(400);
|
|
@@ -221,7 +193,7 @@ describe('devLogin route', function () {
|
|
|
221
193
|
switch (_b.label) {
|
|
222
194
|
case 0:
|
|
223
195
|
malformed = 'brent shareproof-a@test.local';
|
|
224
|
-
return [4 /*yield*/, invokeDevLogin({ email: malformed })];
|
|
196
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: malformed })];
|
|
225
197
|
case 1:
|
|
226
198
|
outcome = _b.sent();
|
|
227
199
|
expect(outcome.status).toBe(400);
|
|
@@ -242,7 +214,7 @@ describe('devLogin route', function () {
|
|
|
242
214
|
var outcome, _a;
|
|
243
215
|
return __generator(this, function (_b) {
|
|
244
216
|
switch (_b.label) {
|
|
245
|
-
case 0: return [4 /*yield*/, invokeDevLogin({ email: 'agent6+lane-a@test.local' })];
|
|
217
|
+
case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'agent6+lane-a@test.local' })];
|
|
246
218
|
case 1:
|
|
247
219
|
outcome = _b.sent();
|
|
248
220
|
expect(outcome.loggedInAs).toBe('agent6+lane-a@test.local');
|
|
@@ -262,7 +234,7 @@ describe('devLogin route', function () {
|
|
|
262
234
|
switch (_b.label) {
|
|
263
235
|
case 0:
|
|
264
236
|
delete process.env.DEVELOPMENT;
|
|
265
|
-
return [4 /*yield*/, invokeDevLogin({ email: 'agent4@test.local' })];
|
|
237
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'agent4@test.local' })];
|
|
266
238
|
case 1:
|
|
267
239
|
outcome = _b.sent();
|
|
268
240
|
expect(outcome.status).toBe(404);
|
|
@@ -281,7 +253,7 @@ describe('devLogin route', function () {
|
|
|
281
253
|
switch (_b.label) {
|
|
282
254
|
case 0:
|
|
283
255
|
delete process.env.DEV_AUTO_LOGIN_EMAIL;
|
|
284
|
-
return [4 /*yield*/, invokeDevLogin({ email: 'agent5@test.local' })];
|
|
256
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'agent5@test.local' })];
|
|
285
257
|
case 1:
|
|
286
258
|
outcome = _b.sent();
|
|
287
259
|
expect(outcome.status).toBe(404);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevLogin.test.js","sourceRoot":"","sources":["../../test/DevLogin.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAA8C;AAC9C,wCAAyC;AACzC,uEAAsE;AACtE,
|
|
1
|
+
{"version":3,"file":"DevLogin.test.js","sourceRoot":"","sources":["../../test/DevLogin.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevLoginBootstrapAdmin.test.d.ts","sourceRoot":"","sources":["../../test/DevLoginBootstrapAdmin.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
var db_1 = require("@proteinjs/db");
|
|
40
|
+
var user_1 = require("@proteinjs/user");
|
|
41
|
+
var devLoginHarness_1 = require("./devLoginHarness");
|
|
42
|
+
var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
|
|
43
|
+
var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
|
|
44
|
+
/**
|
|
45
|
+
* `DEV_BOOTSTRAP_ADMIN_EMAIL` — the first-admin door INSIDE `/dev/login` (n3xa plans/DEV_ESTATES.md
|
|
46
|
+
* D3, founder-ruled 2026-09-04). A dev estate on a fresh real database has no privileged account
|
|
47
|
+
* to grant from, and the no-raw-DB rule forbids the emulator-era seed scripts there — so the ONE
|
|
48
|
+
* sanctioned account door mints break-glass, once:
|
|
49
|
+
* - behind the door's existing two gates (DEVELOPMENT AND DEV_AUTO_LOGIN_EMAIL): closed = 404 as
|
|
50
|
+
* before, and the variable changes nothing;
|
|
51
|
+
* - only while NO account carries 'admin' (the same membership test the app's admin checks make);
|
|
52
|
+
* - only for the request whose resolved address equals the variable exactly (case-normalized
|
|
53
|
+
* the way every account email is);
|
|
54
|
+
* - once, audited like any grant (a role_grant_event row; actor = the account itself — the door
|
|
55
|
+
* acts for nobody else); a later call finds an admin and grants nothing.
|
|
56
|
+
* Outcomes are asserted on the rows (roles, audit), never on calls.
|
|
57
|
+
*/
|
|
58
|
+
var ENV_EMAIL = 'dev@test.local';
|
|
59
|
+
var BOOTSTRAP_EMAIL = 'owner@test.local';
|
|
60
|
+
var userRow = function (email) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
61
|
+
switch (_a.label) {
|
|
62
|
+
case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { email: email })];
|
|
63
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
64
|
+
}
|
|
65
|
+
}); }); };
|
|
66
|
+
var auditRows = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
67
|
+
switch (_a.label) {
|
|
68
|
+
case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.RoleGrantEvent, {})];
|
|
69
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
70
|
+
}
|
|
71
|
+
}); }); };
|
|
72
|
+
var adminRows = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
73
|
+
switch (_a.label) {
|
|
74
|
+
case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.User, {})];
|
|
75
|
+
case 1: return [2 /*return*/, (_a.sent()).filter(function (user) { var _a; return ((_a = user.roles) !== null && _a !== void 0 ? _a : []).includes('admin'); })];
|
|
76
|
+
}
|
|
77
|
+
}); }); };
|
|
78
|
+
describe('devLogin — the DEV_BOOTSTRAP_ADMIN_EMAIL first-admin door', function () {
|
|
79
|
+
var originalEnv = {
|
|
80
|
+
DEVELOPMENT: process.env.DEVELOPMENT,
|
|
81
|
+
DEV_AUTO_LOGIN_EMAIL: process.env.DEV_AUTO_LOGIN_EMAIL,
|
|
82
|
+
DEV_BOOTSTRAP_ADMIN_EMAIL: process.env.DEV_BOOTSTRAP_ADMIN_EMAIL,
|
|
83
|
+
};
|
|
84
|
+
beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
85
|
+
return __generator(this, function (_a) {
|
|
86
|
+
switch (_a.label) {
|
|
87
|
+
case 0: return [4 /*yield*/, testEnv.beforeAll()];
|
|
88
|
+
case 1:
|
|
89
|
+
_a.sent();
|
|
90
|
+
return [2 /*return*/];
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}); });
|
|
94
|
+
afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
95
|
+
return __generator(this, function (_a) {
|
|
96
|
+
switch (_a.label) {
|
|
97
|
+
case 0: return [4 /*yield*/, testEnv.afterAll()];
|
|
98
|
+
case 1:
|
|
99
|
+
_a.sent();
|
|
100
|
+
return [2 /*return*/];
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}); });
|
|
104
|
+
beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
105
|
+
var db;
|
|
106
|
+
return __generator(this, function (_a) {
|
|
107
|
+
switch (_a.label) {
|
|
108
|
+
case 0:
|
|
109
|
+
process.env.DEVELOPMENT = 'true';
|
|
110
|
+
process.env.DEV_AUTO_LOGIN_EMAIL = ENV_EMAIL;
|
|
111
|
+
process.env.DEV_BOOTSTRAP_ADMIN_EMAIL = BOOTSTRAP_EMAIL;
|
|
112
|
+
db = (0, db_1.getDbAsSystem)();
|
|
113
|
+
return [4 /*yield*/, db.delete(user_1.tables.RoleGrantEvent, {})];
|
|
114
|
+
case 1:
|
|
115
|
+
_a.sent();
|
|
116
|
+
return [4 /*yield*/, db.delete(user_1.tables.User, {})];
|
|
117
|
+
case 2:
|
|
118
|
+
_a.sent();
|
|
119
|
+
return [2 /*return*/];
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}); });
|
|
123
|
+
afterEach(function () {
|
|
124
|
+
for (var _i = 0, _a = Object.entries(originalEnv); _i < _a.length; _i++) {
|
|
125
|
+
var _b = _a[_i], key = _b[0], value = _b[1];
|
|
126
|
+
if (value === undefined) {
|
|
127
|
+
delete process.env[key];
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
process.env[key] = value;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
it('a fresh database + the matching address: the account is created carrying admin, audited once, and logged in', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
135
|
+
var _a, outcome, owner, events, _b;
|
|
136
|
+
return __generator(this, function (_c) {
|
|
137
|
+
switch (_c.label) {
|
|
138
|
+
case 0:
|
|
139
|
+
_a = expect;
|
|
140
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
141
|
+
case 1:
|
|
142
|
+
_a.apply(void 0, [_c.sent()]).toBeUndefined();
|
|
143
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: BOOTSTRAP_EMAIL })];
|
|
144
|
+
case 2:
|
|
145
|
+
outcome = _c.sent();
|
|
146
|
+
expect(outcome.loggedInAs).toBe(BOOTSTRAP_EMAIL);
|
|
147
|
+
expect(outcome.sessionSaved).toBe(true);
|
|
148
|
+
expect(outcome.redirect).toBe('/');
|
|
149
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
150
|
+
case 3:
|
|
151
|
+
owner = _c.sent();
|
|
152
|
+
expect(owner.roles).toEqual(['admin']);
|
|
153
|
+
return [4 /*yield*/, auditRows()];
|
|
154
|
+
case 4:
|
|
155
|
+
events = _c.sent();
|
|
156
|
+
expect(events).toHaveLength(1);
|
|
157
|
+
expect(events[0]).toMatchObject({ actor: owner.id, target: owner.id, role: 'admin', action: 'grant' });
|
|
158
|
+
_b = expect;
|
|
159
|
+
return [4 /*yield*/, adminRows()];
|
|
160
|
+
case 5:
|
|
161
|
+
_b.apply(void 0, [_c.sent()]).toHaveLength(1);
|
|
162
|
+
return [2 /*return*/];
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}); });
|
|
166
|
+
it('a second call for the same address changes nothing: still exactly one admin, one grant', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
167
|
+
var outcome, _a, _b, _c;
|
|
168
|
+
return __generator(this, function (_d) {
|
|
169
|
+
switch (_d.label) {
|
|
170
|
+
case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: BOOTSTRAP_EMAIL })];
|
|
171
|
+
case 1:
|
|
172
|
+
_d.sent();
|
|
173
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: BOOTSTRAP_EMAIL })];
|
|
174
|
+
case 2:
|
|
175
|
+
outcome = _d.sent();
|
|
176
|
+
expect(outcome.loggedInAs).toBe(BOOTSTRAP_EMAIL);
|
|
177
|
+
_a = expect;
|
|
178
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
179
|
+
case 3:
|
|
180
|
+
_a.apply(void 0, [(_d.sent()).roles]).toEqual(['admin']);
|
|
181
|
+
_b = expect;
|
|
182
|
+
return [4 /*yield*/, auditRows()];
|
|
183
|
+
case 4:
|
|
184
|
+
_b.apply(void 0, [_d.sent()]).toHaveLength(1);
|
|
185
|
+
_c = expect;
|
|
186
|
+
return [4 /*yield*/, adminRows()];
|
|
187
|
+
case 5:
|
|
188
|
+
_c.apply(void 0, [_d.sent()]).toHaveLength(1);
|
|
189
|
+
return [2 /*return*/];
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}); });
|
|
193
|
+
it('an existing role-less account at the matching address is granted admin on its next login — the door serves created and loaded accounts alike', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
194
|
+
var outcome, _a, _b;
|
|
195
|
+
return __generator(this, function (_c) {
|
|
196
|
+
switch (_c.label) {
|
|
197
|
+
case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Owner', email: BOOTSTRAP_EMAIL })];
|
|
198
|
+
case 1:
|
|
199
|
+
_c.sent();
|
|
200
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: BOOTSTRAP_EMAIL })];
|
|
201
|
+
case 2:
|
|
202
|
+
outcome = _c.sent();
|
|
203
|
+
expect(outcome.loggedInAs).toBe(BOOTSTRAP_EMAIL);
|
|
204
|
+
_a = expect;
|
|
205
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
206
|
+
case 3:
|
|
207
|
+
_a.apply(void 0, [(_c.sent()).roles]).toEqual(['admin']);
|
|
208
|
+
_b = expect;
|
|
209
|
+
return [4 /*yield*/, auditRows()];
|
|
210
|
+
case 4:
|
|
211
|
+
_b.apply(void 0, [_c.sent()]).toHaveLength(1);
|
|
212
|
+
return [2 /*return*/];
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}); });
|
|
216
|
+
it('the default path is a request for DEV_AUTO_LOGIN_EMAIL: when that IS the bootstrap address, the default account carries admin', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
217
|
+
var outcome, _a, _b;
|
|
218
|
+
return __generator(this, function (_c) {
|
|
219
|
+
switch (_c.label) {
|
|
220
|
+
case 0:
|
|
221
|
+
process.env.DEV_BOOTSTRAP_ADMIN_EMAIL = ENV_EMAIL;
|
|
222
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)()];
|
|
223
|
+
case 1:
|
|
224
|
+
outcome = _c.sent();
|
|
225
|
+
expect(outcome.loggedInAs).toBe(ENV_EMAIL);
|
|
226
|
+
_a = expect;
|
|
227
|
+
return [4 /*yield*/, userRow(ENV_EMAIL)];
|
|
228
|
+
case 2:
|
|
229
|
+
_a.apply(void 0, [(_c.sent()).roles]).toEqual(['admin']);
|
|
230
|
+
_b = expect;
|
|
231
|
+
return [4 /*yield*/, auditRows()];
|
|
232
|
+
case 3:
|
|
233
|
+
_b.apply(void 0, [_c.sent()]).toHaveLength(1);
|
|
234
|
+
return [2 /*return*/];
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}); });
|
|
238
|
+
it('the match is case-normalized like every account email — never a second account for a differently-cased address', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
239
|
+
var _a, _b;
|
|
240
|
+
return __generator(this, function (_c) {
|
|
241
|
+
switch (_c.label) {
|
|
242
|
+
case 0:
|
|
243
|
+
process.env.DEV_BOOTSTRAP_ADMIN_EMAIL = 'Owner@Test.local';
|
|
244
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'owner@test.local' })];
|
|
245
|
+
case 1:
|
|
246
|
+
_c.sent();
|
|
247
|
+
_a = expect;
|
|
248
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
249
|
+
case 2:
|
|
250
|
+
_a.apply(void 0, [(_c.sent()).roles]).toEqual(['admin']);
|
|
251
|
+
_b = expect;
|
|
252
|
+
return [4 /*yield*/, adminRows()];
|
|
253
|
+
case 3:
|
|
254
|
+
_b.apply(void 0, [_c.sent()]).toHaveLength(1);
|
|
255
|
+
return [2 /*return*/];
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}); });
|
|
259
|
+
it('an admin already exists: the matching address gets an ordinary account — no grant, no audit row', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
260
|
+
var outcome, _a, _b, _c;
|
|
261
|
+
return __generator(this, function (_d) {
|
|
262
|
+
switch (_d.label) {
|
|
263
|
+
case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Standing admin', email: 'standing-admin@test.local', roles: ['admin'] })];
|
|
264
|
+
case 1:
|
|
265
|
+
_d.sent();
|
|
266
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: BOOTSTRAP_EMAIL })];
|
|
267
|
+
case 2:
|
|
268
|
+
outcome = _d.sent();
|
|
269
|
+
expect(outcome.loggedInAs).toBe(BOOTSTRAP_EMAIL);
|
|
270
|
+
_a = expect;
|
|
271
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
272
|
+
case 3:
|
|
273
|
+
_a.apply(void 0, [(_d.sent()).roles]).toEqual([]);
|
|
274
|
+
_b = expect;
|
|
275
|
+
return [4 /*yield*/, auditRows()];
|
|
276
|
+
case 4:
|
|
277
|
+
_b.apply(void 0, [_d.sent()]).toHaveLength(0);
|
|
278
|
+
_c = expect;
|
|
279
|
+
return [4 /*yield*/, adminRows()];
|
|
280
|
+
case 5:
|
|
281
|
+
_c.apply(void 0, [(_d.sent()).map(function (user) { return user.email; })]).toEqual(['standing-admin@test.local']);
|
|
282
|
+
return [2 /*return*/];
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}); });
|
|
286
|
+
it('a different same-domain address: an ordinary account, no grant — and the bootstrap address itself stays uncreated', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
287
|
+
var outcome, _a, _b, _c, _d;
|
|
288
|
+
return __generator(this, function (_e) {
|
|
289
|
+
switch (_e.label) {
|
|
290
|
+
case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'agent@test.local' })];
|
|
291
|
+
case 1:
|
|
292
|
+
outcome = _e.sent();
|
|
293
|
+
expect(outcome.loggedInAs).toBe('agent@test.local');
|
|
294
|
+
_a = expect;
|
|
295
|
+
return [4 /*yield*/, userRow('agent@test.local')];
|
|
296
|
+
case 2:
|
|
297
|
+
_a.apply(void 0, [(_e.sent()).roles]).toEqual([]);
|
|
298
|
+
_b = expect;
|
|
299
|
+
return [4 /*yield*/, auditRows()];
|
|
300
|
+
case 3:
|
|
301
|
+
_b.apply(void 0, [_e.sent()]).toHaveLength(0);
|
|
302
|
+
_c = expect;
|
|
303
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
304
|
+
case 4:
|
|
305
|
+
_c.apply(void 0, [_e.sent()]).toBeUndefined();
|
|
306
|
+
_d = expect;
|
|
307
|
+
return [4 /*yield*/, adminRows()];
|
|
308
|
+
case 5:
|
|
309
|
+
_d.apply(void 0, [_e.sent()]).toHaveLength(0);
|
|
310
|
+
return [2 /*return*/];
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}); });
|
|
314
|
+
it('the address must match exactly — a plus-suffixed variant is a different account and gets nothing', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
315
|
+
var outcome, _a, _b;
|
|
316
|
+
return __generator(this, function (_c) {
|
|
317
|
+
switch (_c.label) {
|
|
318
|
+
case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'owner+lane@test.local' })];
|
|
319
|
+
case 1:
|
|
320
|
+
outcome = _c.sent();
|
|
321
|
+
expect(outcome.loggedInAs).toBe('owner+lane@test.local');
|
|
322
|
+
_a = expect;
|
|
323
|
+
return [4 /*yield*/, userRow('owner+lane@test.local')];
|
|
324
|
+
case 2:
|
|
325
|
+
_a.apply(void 0, [(_c.sent()).roles]).toEqual([]);
|
|
326
|
+
_b = expect;
|
|
327
|
+
return [4 /*yield*/, auditRows()];
|
|
328
|
+
case 3:
|
|
329
|
+
_b.apply(void 0, [_c.sent()]).toHaveLength(0);
|
|
330
|
+
return [2 /*return*/];
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}); });
|
|
334
|
+
it('with the variable unset the matching address is an ordinary account — the omission is the safety (test/prod never set it)', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
335
|
+
var _a, _b;
|
|
336
|
+
return __generator(this, function (_c) {
|
|
337
|
+
switch (_c.label) {
|
|
338
|
+
case 0:
|
|
339
|
+
delete process.env.DEV_BOOTSTRAP_ADMIN_EMAIL;
|
|
340
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: BOOTSTRAP_EMAIL })];
|
|
341
|
+
case 1:
|
|
342
|
+
_c.sent();
|
|
343
|
+
_a = expect;
|
|
344
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
345
|
+
case 2:
|
|
346
|
+
_a.apply(void 0, [(_c.sent()).roles]).toEqual([]);
|
|
347
|
+
_b = expect;
|
|
348
|
+
return [4 /*yield*/, auditRows()];
|
|
349
|
+
case 3:
|
|
350
|
+
_b.apply(void 0, [_c.sent()]).toHaveLength(0);
|
|
351
|
+
return [2 /*return*/];
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}); });
|
|
355
|
+
it.each([['DEVELOPMENT'], ['DEV_AUTO_LOGIN_EMAIL']])('gate closed (%s unset): 404 exactly as before — no session, no account, no admin; the variable changes nothing', function (gate) { return __awaiter(void 0, void 0, void 0, function () {
|
|
356
|
+
var outcome, _a, _b, _c;
|
|
357
|
+
return __generator(this, function (_d) {
|
|
358
|
+
switch (_d.label) {
|
|
359
|
+
case 0:
|
|
360
|
+
delete process.env[gate];
|
|
361
|
+
return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: BOOTSTRAP_EMAIL })];
|
|
362
|
+
case 1:
|
|
363
|
+
outcome = _d.sent();
|
|
364
|
+
expect(outcome.status).toBe(404);
|
|
365
|
+
expect(outcome.loggedInAs).toBeUndefined();
|
|
366
|
+
expect(outcome.sessionSaved).toBe(false);
|
|
367
|
+
_a = expect;
|
|
368
|
+
return [4 /*yield*/, userRow(BOOTSTRAP_EMAIL)];
|
|
369
|
+
case 2:
|
|
370
|
+
_a.apply(void 0, [_d.sent()]).toBeUndefined();
|
|
371
|
+
_b = expect;
|
|
372
|
+
return [4 /*yield*/, auditRows()];
|
|
373
|
+
case 3:
|
|
374
|
+
_b.apply(void 0, [_d.sent()]).toHaveLength(0);
|
|
375
|
+
_c = expect;
|
|
376
|
+
return [4 /*yield*/, adminRows()];
|
|
377
|
+
case 4:
|
|
378
|
+
_c.apply(void 0, [_d.sent()]).toHaveLength(0);
|
|
379
|
+
return [2 /*return*/];
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}); });
|
|
383
|
+
});
|
|
384
|
+
//# sourceMappingURL=DevLoginBootstrapAdmin.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevLoginBootstrapAdmin.test.js","sourceRoot":"","sources":["../../test/DevLoginBootstrapAdmin.test.ts"],"names":[],"mappings":"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"}
|