@cosmicdrift/kumiko-bundled-features 0.149.1 → 0.150.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 +7 -6
- package/src/admin-shell/__tests__/admin-shell-security.integration.test.ts +1 -1
- package/src/audit/__tests__/audit-security.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/account-lockout.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/auth-claims.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/auth.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/email-verification.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/invite-flow-kms.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/invite-flow.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/multi-roles.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/password-reset.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/seed-admin.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/session-callbacks.integration.test.ts +1 -1
- package/src/auth-email-password/handlers/change-password.write.ts +1 -1
- package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -2
- package/src/auth-email-password/handlers/login.write.ts +1 -1
- package/src/auth-email-password/handlers/reset-password.write.ts +1 -1
- package/src/auth-email-password/i18n.ts +4 -0
- package/src/auth-email-password/index.ts +6 -1
- package/src/auth-email-password/seeding.ts +1 -1
- package/src/auth-email-password/web/auth-gate.tsx +2 -0
- package/src/auth-email-password/web/login-screen.tsx +2 -0
- package/src/auth-mfa/__tests__/base32.test.ts +28 -0
- package/src/auth-mfa/__tests__/disable-and-regenerate.integration.test.ts +16 -0
- package/src/auth-mfa/__tests__/enable-flow.integration.test.ts +60 -0
- package/src/auth-mfa/__tests__/pii-subject-encryption.integration.test.ts +2 -0
- package/src/auth-mfa/__tests__/reencrypt-job.integration.test.ts +2 -0
- package/src/auth-mfa/__tests__/session-auto-revoke.integration.test.ts +2 -1
- package/src/auth-mfa/__tests__/totp.test.ts +11 -2
- package/src/auth-mfa/__tests__/verify.integration.test.ts +67 -1
- package/src/auth-mfa/base32.ts +7 -1
- package/src/auth-mfa/constants.ts +14 -0
- package/src/auth-mfa/errors.ts +9 -16
- package/src/auth-mfa/feature.ts +4 -0
- package/src/auth-mfa/handlers/enable-confirm.write.ts +20 -1
- package/src/auth-mfa/handlers/verify.write.ts +26 -3
- package/src/auth-mfa/index.ts +0 -1
- package/src/auth-mfa/recovery-codes.ts +12 -2
- package/src/auth-mfa/schema/user-mfa.ts +3 -0
- package/src/auth-mfa/testing.ts +5 -0
- package/src/auth-mfa/web/__tests__/mfa-error-keys.test.ts +20 -0
- package/src/auth-mfa/web/i18n.ts +2 -0
- package/src/auth-mfa/web/mfa-enable-screen.tsx +37 -28
- package/src/auth-mfa/web/mfa-error-keys.ts +7 -5
- package/src/auth-mfa/web/mfa-verify-screen.tsx +11 -0
- package/src/auth-mfa/web/qrcode-browser.d.ts +7 -0
- package/src/auth-mfa-user-data/__tests__/hooks.integration.test.ts +2 -0
- package/src/config/handlers/cascade.query.ts +2 -1
- package/src/config/handlers/values.query.ts +2 -1
- package/src/inbound-mail-foundation/handlers/ingest-message.write.ts +15 -2
- package/src/legal-pages/feature.ts +2 -1
- package/src/managed-pages/feature.ts +1 -6
- package/src/seo/feature.ts +1 -6
- package/src/sessions/__tests__/sessions-screens.boot.test.ts +51 -0
- package/src/sessions/__tests__/sessions.integration.test.ts +44 -0
- package/src/sessions/__tests__/test-helpers.ts +1 -1
- package/src/sessions/constants.ts +5 -0
- package/src/sessions/feature.ts +67 -1
- package/src/sessions/handlers/detail.query.ts +36 -0
- package/src/sessions/i18n.ts +23 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/system-query.ts +5 -0
- package/src/tenant/__tests__/tenant-security.integration.test.ts +1 -1
- package/src/user-data-rights/__tests__/download-by-token-resolver-trust.integration.test.ts +163 -0
- package/src/user-data-rights/__tests__/download.integration.test.ts +39 -0
- package/src/user-data-rights/__tests__/read-users-rebuild-survives-lifecycle.integration.test.ts +1 -1
- package/src/user-data-rights/__tests__/restriction-flow.integration.test.ts +1 -1
- package/src/user-data-rights/handlers/download-by-job.query.ts +5 -2
- package/src/user-data-rights/handlers/download-by-token.query.ts +5 -4
- package/src/user-data-rights/lib/tenant-file-provider.ts +62 -0
- package/src/user-profile/__tests__/change-email.integration.test.ts +1 -1
- package/src/user-profile/handlers/change-email.write.ts +2 -2
- package/src/auth-email-password/password-hashing.ts +0 -4
|
@@ -31,8 +31,8 @@ import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
|
31
31
|
import { NotFoundError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
|
|
32
32
|
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
33
33
|
import { z } from "zod";
|
|
34
|
-
import { createFileProviderForTenant } from "../../file-foundation";
|
|
35
34
|
import { recordDownloadUse, recordInvalidAttempt } from "../audit-download";
|
|
35
|
+
import { resolveTenantFileProvider } from "../lib/tenant-file-provider";
|
|
36
36
|
import { exportDownloadTokensTable } from "../schema/download-token";
|
|
37
37
|
import { EXPORT_JOB_STATUS, exportJobsTable } from "../schema/export-job";
|
|
38
38
|
import { hashDownloadToken } from "../token-helpers";
|
|
@@ -181,9 +181,10 @@ export const downloadByTokenQuery = defineQueryHandler({
|
|
|
181
181
|
});
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
// Step 5: signed-URL via provider
|
|
185
|
-
//
|
|
186
|
-
|
|
184
|
+
// Step 5: signed-URL via provider, explicitly bound to the job's
|
|
185
|
+
// tenant — NOT the ambient request tenant (anonymous magic-link path
|
|
186
|
+
// has none under resolverTrust: "authoritative").
|
|
187
|
+
const provider = await resolveTenantFileProvider(
|
|
187
188
|
ctx,
|
|
188
189
|
jobRow.requestedFromTenantId,
|
|
189
190
|
"user-data-rights:query:download-by-token",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Resolves the GDPR-download file-storage provider explicitly for
|
|
2
|
+
// `jobRow.requestedFromTenantId` instead of the ambient request tenant.
|
|
3
|
+
//
|
|
4
|
+
// Both download handlers (by-token, by-job) used to call
|
|
5
|
+
// `createFileProviderForTenant(ctx, jobRow.requestedFromTenantId, ...)`,
|
|
6
|
+
// which reads the PROVIDER SELECTION from `ctx.config` — bound to the
|
|
7
|
+
// caller's own ambient tenant, not the job's tenant:
|
|
8
|
+
// - by-token (anonymous magic-link, httpRoute): under
|
|
9
|
+
// `resolverTrust: "authoritative"` without `defaultTenantId` there is
|
|
10
|
+
// no ambient tenant at all — `ctx.config` throws, 500s the whole
|
|
11
|
+
// GDPR download flow.
|
|
12
|
+
// - by-job (session-authed): a user can own jobs across tenants
|
|
13
|
+
// (cross-tenant-same-user); the ambient session tenant silently
|
|
14
|
+
// picks the WRONG tenant's provider config for a job requested from
|
|
15
|
+
// a different tenant.
|
|
16
|
+
//
|
|
17
|
+
// Fix: build a fresh config accessor bound explicitly to the given
|
|
18
|
+
// tenantId (same construction as `makeTenantStorageProviderResolver`,
|
|
19
|
+
// which the export/forget crons already use), instead of the ambient
|
|
20
|
+
// `ctx.config`. Deliberately NOT `ctx._fileProviderResolver` — that
|
|
21
|
+
// resolver is boot-built and per-tenant-cached for the process lifetime,
|
|
22
|
+
// so an operator switching `file-foundation:config:provider` mid-session
|
|
23
|
+
// wouldn't take effect until the cache evicts.
|
|
24
|
+
import type { DbConnection, TenantDb } from "@cosmicdrift/kumiko-framework/db";
|
|
25
|
+
import type { ConfigResolver, Registry, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
26
|
+
import { SYSTEM_USER_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
27
|
+
import type { FileStorageProvider } from "@cosmicdrift/kumiko-framework/files";
|
|
28
|
+
import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
|
|
29
|
+
import { createConfigAccessor } from "../../config";
|
|
30
|
+
import { createFileProviderForTenant } from "../../file-foundation";
|
|
31
|
+
|
|
32
|
+
export interface TenantFileProviderCtx {
|
|
33
|
+
readonly registry?: Registry;
|
|
34
|
+
readonly configResolver?: ConfigResolver;
|
|
35
|
+
readonly secrets?: SecretsContext;
|
|
36
|
+
readonly db: { readonly raw: DbConnection | TenantDb };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function resolveTenantFileProvider(
|
|
40
|
+
ctx: TenantFileProviderCtx,
|
|
41
|
+
tenantId: string,
|
|
42
|
+
handlerName: string,
|
|
43
|
+
): Promise<FileStorageProvider> {
|
|
44
|
+
if (!ctx.registry || !ctx.configResolver) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`${handlerName}: ctx.registry/ctx.configResolver missing — cannot resolve the file provider for tenant ${tenantId}`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const config = createConfigAccessor(
|
|
50
|
+
ctx.registry,
|
|
51
|
+
ctx.configResolver,
|
|
52
|
+
tenantId as TenantId, // @cast-boundary engine-payload: TenantId brand
|
|
53
|
+
SYSTEM_USER_ID,
|
|
54
|
+
ctx.db.raw,
|
|
55
|
+
ctx.secrets,
|
|
56
|
+
);
|
|
57
|
+
return createFileProviderForTenant(
|
|
58
|
+
{ config, registry: ctx.registry, secrets: ctx.secrets, _userId: SYSTEM_USER_ID },
|
|
59
|
+
tenantId,
|
|
60
|
+
handlerName,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
import { expectErrorIncludes, resetTestTables } from "@cosmicdrift/kumiko-framework/testing";
|
|
19
19
|
import { AuthErrors, AuthHandlers } from "../../auth-email-password/constants";
|
|
20
20
|
import { createAuthEmailPasswordFeature } from "../../auth-email-password/feature";
|
|
21
|
-
import { hashPassword } from "../../auth-email-password/password-hashing";
|
|
22
21
|
import {
|
|
23
22
|
createComplianceProfilesFeature,
|
|
24
23
|
tenantComplianceProfileEntity,
|
|
@@ -28,6 +27,7 @@ import { createConfigFeature } from "../../config";
|
|
|
28
27
|
import { configValuesTable } from "../../config/table";
|
|
29
28
|
import { createDataRetentionFeature } from "../../data-retention";
|
|
30
29
|
import { createSessionsFeature } from "../../sessions";
|
|
30
|
+
import { hashPassword } from "../../shared";
|
|
31
31
|
import { createTenantFeature } from "../../tenant";
|
|
32
32
|
import { tenantMembershipsTable } from "../../tenant/membership-table";
|
|
33
33
|
import { tenantEntity } from "../../tenant/schema/tenant";
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
7
7
|
import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
8
8
|
import { z } from "zod";
|
|
9
|
-
import { AuthErrors
|
|
10
|
-
import { decryptStoredPii } from "../../shared";
|
|
9
|
+
import { AuthErrors } from "../../auth-email-password";
|
|
10
|
+
import { decryptStoredPii, verifyPassword } from "../../shared";
|
|
11
11
|
import { UserErrors, UserHandlers, UserQueries } from "../../user";
|
|
12
12
|
import { UserProfileErrors } from "../constants";
|
|
13
13
|
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
// Moved to shared/ — reused across admin-shell, audit, sessions, tenant,
|
|
2
|
-
// user-data-rights, user-profile, and now auth-mfa. Re-exported here for the
|
|
3
|
-
// existing call sites within this feature that import via "./password-hashing".
|
|
4
|
-
export { hashPassword, verifyDummyPassword, verifyPassword } from "../shared/password-hashing";
|