@cosmicdrift/kumiko-bundled-features 0.155.0 → 0.156.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/agent-tools/__tests__/tool-catalog.test.ts +179 -0
- package/src/agent-tools/__tests__/tool-dispatch.integration.test.ts +100 -0
- package/src/agent-tools/__tests__/tool-dispatch.test.ts +126 -0
- package/src/agent-tools/index.ts +9 -0
- package/src/agent-tools/tool-catalog.ts +130 -0
- package/src/agent-tools/tool-dispatch.ts +82 -0
- package/src/agent-tools/types.ts +38 -0
- package/src/auth-email-password/web/__tests__/signup-complete-screen.test.tsx +5 -1
- package/src/auth-email-password/web/__tests__/signup-screen.test.tsx +5 -1
- package/src/auth-email-password/web/auth-gate.tsx +14 -4
- package/src/auth-mfa/__tests__/enable-flow.integration.test.ts +89 -0
- package/src/auth-mfa/__tests__/totp.test.ts +2 -2
- package/src/auth-mfa/__tests__/verify.integration.test.ts +29 -4
- package/src/auth-mfa/constants.ts +4 -0
- package/src/auth-mfa/handlers/disable.write.ts +2 -1
- package/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
- package/src/auth-mfa/handlers/regenerate-recovery.write.ts +4 -3
- package/src/auth-mfa/handlers/verify.write.ts +22 -12
- package/src/auth-mfa/recovery-codes.ts +2 -2
- package/src/auth-mfa/schema/user-mfa.ts +10 -0
- package/src/auth-mfa/totp.ts +18 -6
- package/src/auth-mfa/verify-factor.ts +30 -2
- package/src/auth-mfa/web/i18n.ts +2 -0
- package/src/auth-mfa/web/mfa-enable-screen.tsx +7 -29
- package/src/auth-mfa/web/mfa-error-keys.ts +2 -0
- package/src/auth-mfa/web/qrcode-browser.d.ts +5 -0
- package/src/config/__tests__/pii-encrypted.integration.test.ts +158 -0
- package/src/config/__tests__/write-helpers.test.ts +23 -0
- package/src/config/handlers/set.write.ts +47 -1
- package/src/config/resolver.ts +28 -0
- package/src/config/write-helpers.ts +22 -0
- package/src/custom-fields/__tests__/audit-integration.integration.test.ts +1 -1
- package/src/delivery/feature.ts +1 -1
- package/src/file-foundation/__tests__/feature.test.ts +1 -1
- package/src/files-provider-s3/__tests__/s3-provider.integration.test.ts +3 -1
- package/src/inbound-mail-foundation/__tests__/feature.test.ts +1 -1
- package/src/inbound-mail-foundation/feature.ts +3 -3
- package/src/inbound-provider-imap/__tests__/imap-foundation.integration.test.ts +7 -11
- package/src/jobs/feature.ts +1 -1
- package/src/legal-pages/feature.ts +1 -1
- package/src/mail-foundation/__tests__/feature.test.ts +1 -1
- package/src/page-render/branding.ts +4 -3
- package/src/personal-access-tokens/feature.ts +1 -1
- package/src/sessions/__tests__/sessions.integration.test.ts +42 -0
- package/src/sessions/feature.ts +2 -2
- package/src/user-data-rights/handlers/download-by-job.query.ts +14 -7
- package/src/user-data-rights/handlers/download-by-token.query.ts +14 -7
- package/src/user-data-rights/lib/storage-provider-resolver.ts +6 -5
- package/src/user-data-rights/lib/tenant-file-provider.ts +0 -62
|
@@ -25,12 +25,16 @@
|
|
|
25
25
|
|
|
26
26
|
import { requestContext } from "@cosmicdrift/kumiko-framework/api";
|
|
27
27
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
defineQueryHandler,
|
|
30
|
+
SYSTEM_USER_ID,
|
|
31
|
+
type TenantId,
|
|
32
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
29
33
|
import { NotFoundError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
|
|
30
34
|
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
31
35
|
import { z } from "zod";
|
|
32
36
|
import { recordDownloadUse, recordInvalidAttempt } from "../audit-download";
|
|
33
|
-
import {
|
|
37
|
+
import { makeTenantStorageProviderResolver } from "../lib/storage-provider-resolver";
|
|
34
38
|
import { exportDownloadTokensTable } from "../schema/download-token";
|
|
35
39
|
import { EXPORT_JOB_STATUS, exportJobsTable } from "../schema/export-job";
|
|
36
40
|
|
|
@@ -130,11 +134,14 @@ export const downloadByJobQuery = defineQueryHandler({
|
|
|
130
134
|
// Provider bound explicitly to the job's tenant — NOT the ambient
|
|
131
135
|
// session tenant (cross-tenant-same-user: job.requestedFromTenantId
|
|
132
136
|
// can differ from query.user.tenantId).
|
|
133
|
-
const provider = await
|
|
134
|
-
ctx,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
const provider = await makeTenantStorageProviderResolver({
|
|
138
|
+
registry: ctx.registry,
|
|
139
|
+
configResolver: ctx.configResolver,
|
|
140
|
+
secrets: ctx.secrets,
|
|
141
|
+
db: ctx.db.raw,
|
|
142
|
+
userId: SYSTEM_USER_ID,
|
|
143
|
+
handlerName: "user-data-rights:query:download-by-job",
|
|
144
|
+
})(jobRow.requestedFromTenantId as TenantId); // @cast-boundary engine-payload: TenantId brand
|
|
138
145
|
if (!provider.getSignedUrl) {
|
|
139
146
|
await recordInvalidAttempt({
|
|
140
147
|
db: ctx.db.raw,
|
|
@@ -27,12 +27,16 @@
|
|
|
27
27
|
// startet. Dieser query-handler liefert nur das JSON.
|
|
28
28
|
|
|
29
29
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
defineQueryHandler,
|
|
32
|
+
SYSTEM_USER_ID,
|
|
33
|
+
type TenantId,
|
|
34
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
31
35
|
import { NotFoundError, UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
|
|
32
36
|
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
33
37
|
import { z } from "zod";
|
|
34
38
|
import { recordDownloadUse, recordInvalidAttempt } from "../audit-download";
|
|
35
|
-
import {
|
|
39
|
+
import { makeTenantStorageProviderResolver } from "../lib/storage-provider-resolver";
|
|
36
40
|
import { exportDownloadTokensTable } from "../schema/download-token";
|
|
37
41
|
import { EXPORT_JOB_STATUS, exportJobsTable } from "../schema/export-job";
|
|
38
42
|
import { hashDownloadToken } from "../token-helpers";
|
|
@@ -184,11 +188,14 @@ export const downloadByTokenQuery = defineQueryHandler({
|
|
|
184
188
|
// Step 5: signed-URL via provider, explicitly bound to the job's
|
|
185
189
|
// tenant — NOT the ambient request tenant (anonymous magic-link path
|
|
186
190
|
// has none under resolverTrust: "authoritative").
|
|
187
|
-
const provider = await
|
|
188
|
-
ctx,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
const provider = await makeTenantStorageProviderResolver({
|
|
192
|
+
registry: ctx.registry,
|
|
193
|
+
configResolver: ctx.configResolver,
|
|
194
|
+
secrets: ctx.secrets,
|
|
195
|
+
db: ctx.db.raw,
|
|
196
|
+
userId: SYSTEM_USER_ID,
|
|
197
|
+
handlerName: "user-data-rights:query:download-by-token",
|
|
198
|
+
})(jobRow.requestedFromTenantId as TenantId); // @cast-boundary engine-payload: TenantId brand
|
|
192
199
|
if (!provider.getSignedUrl) {
|
|
193
200
|
await recordInvalidAttempt({
|
|
194
201
|
db: ctx.db.raw,
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
// construction). Extracted from the export cron so both crons + the manual
|
|
5
5
|
// forget handler share one construction site instead of inlining it three times.
|
|
6
6
|
|
|
7
|
-
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
7
|
+
import type { DbConnection, TenantDb } from "@cosmicdrift/kumiko-framework/db";
|
|
8
8
|
import type { ConfigResolver, Registry, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
9
|
+
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
9
10
|
import type { FileStorageProvider } from "@cosmicdrift/kumiko-framework/files";
|
|
10
11
|
import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
|
|
11
12
|
import { createConfigAccessor } from "../../config";
|
|
@@ -18,7 +19,7 @@ export interface TenantStorageResolverCtx {
|
|
|
18
19
|
// Undefined → the returned resolver throws (callers decide fail-loud vs skip).
|
|
19
20
|
readonly configResolver: ConfigResolver | undefined;
|
|
20
21
|
readonly secrets: SecretsContext | undefined;
|
|
21
|
-
readonly db: DbConnection;
|
|
22
|
+
readonly db: DbConnection | TenantDb;
|
|
22
23
|
readonly userId: string;
|
|
23
24
|
readonly handlerName: string;
|
|
24
25
|
}
|
|
@@ -28,9 +29,9 @@ export function makeTenantStorageProviderResolver(
|
|
|
28
29
|
): (tenantId: TenantId) => Promise<FileStorageProvider> {
|
|
29
30
|
return async (tenantId) => {
|
|
30
31
|
if (!ctx.configResolver) {
|
|
31
|
-
throw new
|
|
32
|
-
|
|
33
|
-
);
|
|
32
|
+
throw new InternalError({
|
|
33
|
+
message: `[${ctx.handlerName}] ctx.configResolver missing — cannot resolve the file provider for tenant ${tenantId}`,
|
|
34
|
+
});
|
|
34
35
|
}
|
|
35
36
|
const config = createConfigAccessor(
|
|
36
37
|
ctx.registry,
|
|
@@ -1,62 +0,0 @@
|
|
|
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
|
-
}
|