@cosmicdrift/kumiko-bundled-features 0.153.0 → 0.154.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.154.0",
|
|
4
4
|
"description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -115,11 +115,11 @@
|
|
|
115
115
|
"./step-dispatcher": "./src/step-dispatcher/index.ts"
|
|
116
116
|
},
|
|
117
117
|
"dependencies": {
|
|
118
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
119
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
120
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
121
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
122
|
-
"@cosmicdrift/kumiko-renderer-web": "0.
|
|
118
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.154.0",
|
|
119
|
+
"@cosmicdrift/kumiko-framework": "0.154.0",
|
|
120
|
+
"@cosmicdrift/kumiko-headless": "0.154.0",
|
|
121
|
+
"@cosmicdrift/kumiko-renderer": "0.154.0",
|
|
122
|
+
"@cosmicdrift/kumiko-renderer-web": "0.154.0",
|
|
123
123
|
"@mollie/api-client": "^4.5.0",
|
|
124
124
|
"imapflow": "^1.3.3",
|
|
125
125
|
"mailparser": "^3.9.8",
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
createTestUser,
|
|
5
5
|
setupTestStack,
|
|
6
6
|
type TestStack,
|
|
7
|
+
testTenantId,
|
|
7
8
|
unsafeCreateEntityTable,
|
|
8
9
|
unsafePushTables,
|
|
9
10
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
@@ -18,7 +19,7 @@ import { createTenantFeature } from "../../tenant";
|
|
|
18
19
|
import { createUserFeature } from "../../user/feature";
|
|
19
20
|
import { userEntity } from "../../user/schema/user";
|
|
20
21
|
import { base32Decode } from "../base32";
|
|
21
|
-
import { AuthMfaHandlers } from "../constants";
|
|
22
|
+
import { AuthMfaHandlers, AuthMfaQueries } from "../constants";
|
|
22
23
|
import { createAuthMfaFeature } from "../feature";
|
|
23
24
|
import { userMfaEntity } from "../schema/user-mfa";
|
|
24
25
|
import { currentTotpCode } from "../totp";
|
|
@@ -216,3 +217,49 @@ describe("regenerate-recovery", () => {
|
|
|
216
217
|
expectErrorIncludes(err, "mfa_not_enabled");
|
|
217
218
|
});
|
|
218
219
|
});
|
|
220
|
+
|
|
221
|
+
// pr-review kumiko-framework #1062/4 — the only prior coverage of
|
|
222
|
+
// user-mfa:status was the false → true transition (implicit in
|
|
223
|
+
// enableMfaFor's own setup); the more interesting true → false after
|
|
224
|
+
// disable, and tenant isolation, had no assertion anywhere.
|
|
225
|
+
describe("status query", () => {
|
|
226
|
+
test("true → false after disable", async () => {
|
|
227
|
+
const { user, secret } = await enableMfaFor("status-disable-1");
|
|
228
|
+
|
|
229
|
+
const before = await stack.http.queryOk<{ enabled: boolean }>(AuthMfaQueries.status, {}, user);
|
|
230
|
+
expect(before.enabled).toBe(true);
|
|
231
|
+
|
|
232
|
+
await stack.http.writeOk(AuthMfaHandlers.disable, { code: currentTotpCode(secret) }, user);
|
|
233
|
+
|
|
234
|
+
const after = await stack.http.queryOk<{ enabled: boolean }>(AuthMfaQueries.status, {}, user);
|
|
235
|
+
expect(after.enabled).toBe(false);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test("tenant isolation: same userId enrolled in tenant A stays invisible to the same id in tenant B", async () => {
|
|
239
|
+
// The entity's uniqueness is [userId, tenantId] — a second tenant CAN
|
|
240
|
+
// have a distinct (non-enrolled) row for the identical userId. The
|
|
241
|
+
// query filters only by userId (see status.query.ts's own comment) and
|
|
242
|
+
// relies on ctx.db's tenant scoping to keep them apart; assert that
|
|
243
|
+
// scoping actually holds instead of just trusting it.
|
|
244
|
+
const { user: tenantAUser } = await enableMfaFor("status-tenant-iso-1");
|
|
245
|
+
const tenantBUser = createTestUser({
|
|
246
|
+
id: tenantAUser.id,
|
|
247
|
+
tenantId: testTenantId(2),
|
|
248
|
+
roles: ["User"],
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const tenantAStatus = await stack.http.queryOk<{ enabled: boolean }>(
|
|
252
|
+
AuthMfaQueries.status,
|
|
253
|
+
{},
|
|
254
|
+
tenantAUser,
|
|
255
|
+
);
|
|
256
|
+
expect(tenantAStatus.enabled).toBe(true);
|
|
257
|
+
|
|
258
|
+
const tenantBStatus = await stack.http.queryOk<{ enabled: boolean }>(
|
|
259
|
+
AuthMfaQueries.status,
|
|
260
|
+
{},
|
|
261
|
+
tenantBUser,
|
|
262
|
+
);
|
|
263
|
+
expect(tenantBStatus.enabled).toBe(false);
|
|
264
|
+
});
|
|
265
|
+
});
|