@capybara-hq/kernel 0.1.0-rc.5 → 0.1.0-rc.7
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/bootstrap.json +27 -3
- package/dist/admin/admin.controller.d.ts +21 -74
- package/dist/admin/admin.controller.js +50 -50
- package/dist/admin/admin.schemas.d.ts +57 -0
- package/dist/admin/admin.schemas.js +50 -0
- package/dist/admin/extensions.controller.d.ts +10 -0
- package/dist/admin/extensions.controller.js +18 -0
- package/dist/admin/extensions.schemas.d.ts +7 -0
- package/dist/admin/extensions.schemas.js +10 -0
- package/dist/admin/limit-defaults.d.ts +20 -0
- package/dist/admin/limit-defaults.js +10 -0
- package/dist/agents/agent-profile.service.d.ts +7 -5
- package/dist/agents/agent-profile.service.js +14 -9
- package/dist/agents/agents.controller.d.ts +7 -287
- package/dist/agents/agents.controller.js +7 -67
- package/dist/agents/agents.schemas.d.ts +389 -0
- package/dist/agents/agents.schemas.js +126 -0
- package/dist/agents/agents.service.d.ts +16 -6
- package/dist/agents/agents.service.js +75 -19
- package/dist/agents/definition.d.ts +47 -19
- package/dist/agents/definition.js +119 -38
- package/dist/agents/from-template.d.ts +2 -2
- package/dist/agents/from-template.js +76 -45
- package/dist/agents/from-template.service.d.ts +12 -0
- package/dist/agents/from-template.service.js +23 -6
- package/dist/agents/models.controller.d.ts +33 -5
- package/dist/agents/models.controller.js +50 -6
- package/dist/agents/org-templates.d.ts +13 -3
- package/dist/agents/org-templates.js +69 -28
- package/dist/agents/pending-connector-requests.d.ts +2 -0
- package/dist/agents/pending-connector-requests.js +1 -1
- package/dist/agents/pending-connectors.controller.d.ts +1 -1
- package/dist/agents/pending-connectors.controller.js +2 -2
- package/dist/agents/pending-connectors.service.d.ts +2 -2
- package/dist/agents/pending-connectors.service.js +19 -19
- package/dist/agents/profile.d.ts +18 -0
- package/dist/agents/profile.js +5 -1
- package/dist/agents/readiness.controller.d.ts +5 -5
- package/dist/agents/readiness.controller.js +6 -6
- package/dist/agents/templates.controller.d.ts +8 -17
- package/dist/agents/templates.controller.js +13 -31
- package/dist/agents/templates.schemas.d.ts +20 -0
- package/dist/agents/templates.schemas.js +45 -0
- package/dist/background/background.controller.js +3 -2
- package/dist/background/background.schemas.d.ts +10 -0
- package/dist/background/background.schemas.js +16 -0
- package/dist/background/tasks.service.d.ts +1 -1
- package/dist/background/tasks.service.js +7 -2
- package/dist/catalog/admin-catalog.controller.d.ts +4 -57
- package/dist/catalog/admin-catalog.controller.js +8 -45
- package/dist/catalog/admin-catalog.schemas.d.ts +72 -0
- package/dist/catalog/admin-catalog.schemas.js +92 -0
- package/dist/catalog/catalog-content.d.ts +12 -2
- package/dist/catalog/catalog-scope.service.js +8 -2
- package/dist/catalog/catalog.service.d.ts +2 -0
- package/dist/catalog/catalog.service.js +3 -0
- package/dist/catalog/component-scope.controller.d.ts +3 -65
- package/dist/catalog/component-scope.controller.js +3 -56
- package/dist/catalog/component-scope.schemas.d.ts +114 -0
- package/dist/catalog/component-scope.schemas.js +97 -0
- package/dist/catalog/component-scope.service.d.ts +28 -4
- package/dist/catalog/component-scope.service.js +55 -3
- package/dist/catalog/component-state.d.ts +9 -2
- package/dist/catalog/component-state.js +22 -13
- package/dist/catalog/marketplaces.controller.d.ts +5 -35
- package/dist/catalog/marketplaces.controller.js +6 -34
- package/dist/catalog/marketplaces.schemas.d.ts +48 -0
- package/dist/catalog/marketplaces.schemas.js +53 -0
- package/dist/catalog/marketplaces.service.d.ts +15 -1
- package/dist/catalog/marketplaces.service.js +22 -1
- package/dist/catalog/org-catalog.controller.d.ts +6 -62
- package/dist/catalog/org-catalog.controller.js +12 -66
- package/dist/catalog/org-catalog.schemas.d.ts +79 -0
- package/dist/catalog/org-catalog.schemas.js +82 -0
- package/dist/catalog/org-catalog.service.d.ts +9 -2
- package/dist/catalog/org-catalog.service.js +38 -5
- package/dist/catalog/org-extension.controller.d.ts +1 -12
- package/dist/catalog/org-extension.controller.js +1 -10
- package/dist/catalog/org-extension.schemas.d.ts +15 -0
- package/dist/catalog/org-extension.schemas.js +22 -0
- package/dist/catalog/org-plugin-uploads.controller.d.ts +2 -19
- package/dist/catalog/org-plugin-uploads.controller.js +15 -28
- package/dist/catalog/org-plugin-uploads.schemas.d.ts +20 -0
- package/dist/catalog/org-plugin-uploads.schemas.js +32 -0
- package/dist/catalog/owned-items.d.ts +6 -2
- package/dist/catalog/owned-items.js +16 -4
- package/dist/catalog/platform-components.d.ts +2 -0
- package/dist/catalog/platform-components.js +2 -0
- package/dist/catalog/plugin-import.js +1 -0
- package/dist/catalog/plugin-install.js +1 -1
- package/dist/catalog/requests.service.d.ts +2 -1
- package/dist/catalog/requests.service.js +6 -2
- package/dist/channels/channels.schemas.d.ts +33 -0
- package/dist/channels/channels.schemas.js +34 -0
- package/dist/channels/connections.controller.d.ts +2 -29
- package/dist/channels/connections.controller.js +1 -23
- package/dist/channels/connections.service.d.ts +8 -2
- package/dist/channels/connections.service.js +23 -5
- package/dist/channels/inbound.js +4 -0
- package/dist/config/schema.d.ts +4 -0
- package/dist/config/schema.js +24 -0
- package/dist/conversations/conversations.controller.d.ts +16 -37
- package/dist/conversations/conversations.controller.js +16 -56
- package/dist/conversations/conversations.schemas.d.ts +52 -0
- package/dist/conversations/conversations.schemas.js +79 -0
- package/dist/conversations/conversations.service.d.ts +13 -4
- package/dist/conversations/conversations.service.js +32 -26
- package/dist/conversations/events.d.ts +80 -6
- package/dist/conversations/events.js +60 -5
- package/dist/conversations/message-context.d.ts +28 -0
- package/dist/conversations/message-context.js +56 -0
- package/dist/conversations/queue.d.ts +2 -1
- package/dist/conversations/queue.js +11 -2
- package/dist/ctx/create-ctx.d.ts +15 -1
- package/dist/ctx/create-ctx.js +23 -2
- package/dist/db/kernel-schema.d.ts +44 -0
- package/dist/environments/environments.schemas.d.ts +3 -0
- package/dist/environments/environments.schemas.js +14 -0
- package/dist/environments/environments.service.d.ts +16 -4
- package/dist/environments/environments.service.js +58 -13
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +6 -0
- package/dist/evals/evals.schemas.d.ts +110 -0
- package/dist/evals/evals.schemas.js +107 -0
- package/dist/evals/reconstruct.js +18 -11
- package/dist/evals/recorded-tools.d.ts +2 -1
- package/dist/evals/recorded-tools.js +11 -3
- package/dist/evals/run-replay.d.ts +8 -1
- package/dist/evals/run-replay.js +17 -2
- package/dist/evals/runs.controller.d.ts +2 -57
- package/dist/evals/runs.controller.js +1 -42
- package/dist/evals/runs.service.d.ts +8 -7
- package/dist/evals/runs.service.js +45 -30
- package/dist/evals/sets.controller.d.ts +2 -28
- package/dist/evals/sets.controller.js +1 -31
- package/dist/evals/sets.service.d.ts +7 -7
- package/dist/evals/sets.service.js +23 -17
- package/dist/evals/snapshot.d.ts +3 -2
- package/dist/evals/snapshot.js +17 -4
- package/dist/evals/step-replay.d.ts +2 -1
- package/dist/evals/step-replay.js +3 -2
- package/dist/extensions/admin-ops.d.ts +5 -3
- package/dist/extensions/admin-ops.js +17 -12
- package/dist/extensions/config-hash.d.ts +10 -0
- package/dist/extensions/config-hash.js +38 -0
- package/dist/extensions/deployment-config.d.ts +16 -1
- package/dist/extensions/deployment-config.js +83 -0
- package/dist/extensions/extensions.module.js +9 -12
- package/dist/extensions/host.d.ts +39 -12
- package/dist/extensions/host.js +129 -51
- package/dist/extensions/installs.d.ts +5 -0
- package/dist/extensions/installs.js +12 -0
- package/dist/extensions/org-config.d.ts +17 -2
- package/dist/extensions/org-config.js +23 -4
- package/dist/extensions/point-defaults.controller.d.ts +2 -8
- package/dist/extensions/point-defaults.controller.js +1 -3
- package/dist/extensions/point-defaults.d.ts +3 -1
- package/dist/extensions/point-defaults.js +4 -2
- package/dist/extensions/point-defaults.schemas.d.ts +9 -0
- package/dist/extensions/point-defaults.schemas.js +14 -0
- package/dist/extensions/state.module.d.ts +9 -0
- package/dist/extensions/state.module.js +38 -0
- package/dist/extensions/unavailable.d.ts +49 -0
- package/dist/extensions/unavailable.js +113 -0
- package/dist/files/previewers.controller.js +2 -3
- package/dist/files/previewers.d.ts +1 -1
- package/dist/files/previewers.js +4 -4
- package/dist/files/previewers.schemas.d.ts +10 -0
- package/dist/files/previewers.schemas.js +9 -0
- package/dist/http/api.module.js +4 -0
- package/dist/http/plugin-dispatch.d.ts +4 -1
- package/dist/http/plugin-dispatch.js +14 -2
- package/dist/identity/accounts.d.ts +43 -4
- package/dist/identity/accounts.js +74 -6
- package/dist/identity/auth.guard.js +10 -1
- package/dist/identity/cookies.d.ts +6 -0
- package/dist/identity/cookies.js +14 -0
- package/dist/identity/identity.module.js +3 -0
- package/dist/identity/initial-passwords.controller.d.ts +22 -0
- package/dist/identity/initial-passwords.controller.js +49 -0
- package/dist/identity/initial-passwords.d.ts +61 -0
- package/dist/identity/initial-passwords.job.d.ts +16 -0
- package/dist/identity/initial-passwords.job.js +46 -0
- package/dist/identity/initial-passwords.js +159 -0
- package/dist/identity/me.controller.d.ts +14 -0
- package/dist/identity/me.controller.js +39 -1
- package/dist/identity/principal.d.ts +8 -0
- package/dist/identity/principal.js +8 -0
- package/dist/identity/settings.d.ts +3 -1
- package/dist/identity/settings.js +6 -4
- package/dist/inbox/inbox.schemas.d.ts +8 -0
- package/dist/inbox/inbox.schemas.js +11 -0
- package/dist/inbox/platform-inbox.controller.d.ts +1 -1
- package/dist/inbox/platform-inbox.controller.js +2 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +6 -0
- package/dist/infra/config/kernel-config.service.js +3 -0
- package/dist/infra/events/kernel-events.d.ts +8 -0
- package/dist/lifecycle/kernel-lifecycle.js +4 -0
- package/dist/models/embeddings.d.ts +82 -0
- package/dist/models/embeddings.js +326 -0
- package/dist/models/enablement.controller.d.ts +40 -0
- package/dist/models/enablement.controller.js +74 -0
- package/dist/models/enablement.d.ts +101 -0
- package/dist/models/enablement.js +264 -0
- package/dist/models/models.module.d.ts +5 -1
- package/dist/models/models.module.js +16 -4
- package/dist/models/org-models.schemas.d.ts +8 -0
- package/dist/models/org-models.schemas.js +22 -0
- package/dist/models/prices.d.ts +3 -1
- package/dist/models/prices.js +7 -5
- package/dist/models/purposes.d.ts +30 -6
- package/dist/models/purposes.js +68 -17
- package/dist/orgs/orgs.controller.d.ts +2 -5
- package/dist/orgs/orgs.controller.js +3 -6
- package/dist/orgs/orgs.schemas.d.ts +8 -0
- package/dist/orgs/orgs.schemas.js +16 -0
- package/dist/orgs/orgs.service.d.ts +3 -1
- package/dist/orgs/orgs.service.js +6 -4
- package/dist/orgs/settings.service.d.ts +9 -1
- package/dist/orgs/settings.service.js +20 -5
- package/dist/overrides.d.ts +4 -0
- package/dist/overrides.js +2 -0
- package/dist/platform/errors.d.ts +21 -4
- package/dist/platform/errors.js +45 -6
- package/dist/platform/exclusions.d.ts +2 -3
- package/dist/platform/exclusions.js +68 -831
- package/dist/platform/method.js +1 -1
- package/dist/platform/operation.d.ts +82 -5
- package/dist/platform/operation.js +62 -7
- package/dist/platform/ops/accounts.ops.d.ts +32 -0
- package/dist/platform/ops/accounts.ops.js +291 -0
- package/dist/platform/ops/admin.ops.d.ts +36 -0
- package/dist/platform/ops/admin.ops.js +389 -0
- package/dist/platform/ops/agent-skills.ops.d.ts +24 -0
- package/dist/platform/ops/agent-skills.ops.js +226 -0
- package/dist/platform/ops/agent-templates.ops.d.ts +4 -1
- package/dist/platform/ops/agent-templates.ops.js +194 -14
- package/dist/platform/ops/agents.ops.d.ts +19 -1
- package/dist/platform/ops/agents.ops.js +481 -58
- package/dist/platform/ops/approvals.ops.d.ts +30 -0
- package/dist/platform/ops/approvals.ops.js +116 -0
- package/dist/platform/ops/background.ops.d.ts +14 -0
- package/dist/platform/ops/background.ops.js +134 -0
- package/dist/platform/ops/catalog-admin.ops.d.ts +74 -0
- package/dist/platform/ops/catalog-admin.ops.js +587 -0
- package/dist/platform/ops/channels.ops.d.ts +16 -0
- package/dist/platform/ops/channels.ops.js +195 -0
- package/dist/platform/ops/components.ops.d.ts +46 -0
- package/dist/platform/ops/components.ops.js +853 -0
- package/dist/platform/ops/connectors.ops.d.ts +4 -2
- package/dist/platform/ops/connectors.ops.js +68 -6
- package/dist/platform/ops/conversations.ops.d.ts +30 -0
- package/dist/platform/ops/conversations.ops.js +470 -0
- package/dist/platform/ops/environments.ops.d.ts +26 -0
- package/dist/platform/ops/environments.ops.js +289 -0
- package/dist/platform/ops/errors.d.ts +10 -5
- package/dist/platform/ops/errors.js +19 -11
- package/dist/platform/ops/evals.ops.d.ts +28 -0
- package/dist/platform/ops/evals.ops.js +783 -0
- package/dist/platform/ops/extensions-admin.ops.d.ts +25 -0
- package/dist/platform/ops/extensions-admin.ops.js +344 -0
- package/dist/platform/ops/extensions.ops.d.ts +7 -1
- package/dist/platform/ops/extensions.ops.js +248 -17
- package/dist/platform/ops/inbox.ops.d.ts +25 -0
- package/dist/platform/ops/inbox.ops.js +378 -0
- package/dist/platform/ops/marketplaces.ops.d.ts +7 -1
- package/dist/platform/ops/marketplaces.ops.js +326 -17
- package/dist/platform/ops/models.ops.d.ts +25 -0
- package/dist/platform/ops/models.ops.js +232 -0
- package/dist/platform/ops/org-plugins.ops.d.ts +29 -0
- package/dist/platform/ops/org-plugins.ops.js +329 -0
- package/dist/platform/ops/org-settings.ops.d.ts +16 -0
- package/dist/platform/ops/org-settings.ops.js +102 -0
- package/dist/platform/ops/orgs.ops.d.ts +28 -0
- package/dist/platform/ops/orgs.ops.js +295 -0
- package/dist/platform/ops/other-orgs.d.ts +20 -0
- package/dist/platform/ops/other-orgs.js +72 -0
- package/dist/platform/ops/platform.ops.d.ts +4 -4
- package/dist/platform/ops/platform.ops.js +23 -24
- package/dist/platform/ops/plugins.ops.d.ts +10 -8
- package/dist/platform/ops/plugins.ops.js +176 -77
- package/dist/platform/ops/previewers.ops.d.ts +14 -0
- package/dist/platform/ops/previewers.ops.js +109 -0
- package/dist/platform/ops/requests.ops.js +57 -19
- package/dist/platform/ops/skills.ops.d.ts +5 -1
- package/dist/platform/ops/skills.ops.js +129 -11
- package/dist/platform/ops/unavailable.d.ts +23 -0
- package/dist/platform/ops/unavailable.js +111 -0
- package/dist/platform/parity.d.ts +33 -0
- package/dist/platform/parity.js +272 -0
- package/dist/platform/platform-ops.module.d.ts +32 -0
- package/dist/platform/platform-ops.module.js +78 -11
- package/dist/platform/route-schemas.d.ts +18 -0
- package/dist/platform/route-schemas.js +60 -0
- package/dist/roles/worker.module.js +2 -0
- package/dist/runtime/context/build.d.ts +2 -0
- package/dist/runtime/context/build.js +28 -2
- package/dist/runtime/context/compaction.js +10 -1
- package/dist/runtime/context/run-context.d.ts +65 -0
- package/dist/runtime/context/run-context.js +215 -0
- package/dist/runtime/hook-calls.d.ts +8 -1
- package/dist/runtime/hook-calls.js +40 -9
- package/dist/runtime/model-call.d.ts +8 -3
- package/dist/runtime/model-call.js +30 -6
- package/dist/runtime/providers.d.ts +146 -32
- package/dist/runtime/providers.js +328 -67
- package/dist/runtime/run-context.service.d.ts +65 -0
- package/dist/runtime/run-context.service.js +220 -0
- package/dist/runtime/run-worker.d.ts +6 -1
- package/dist/runtime/run-worker.js +35 -10
- package/dist/runtime/runtime.module.js +2 -0
- package/dist/runtime/subagents/definition.d.ts +15 -15
- package/dist/runtime/subagents/definition.js +49 -118
- package/dist/runtime/usage-report-jobs.d.ts +88 -0
- package/dist/runtime/usage-report-jobs.js +158 -0
- package/dist/runtime/usage-report.d.ts +33 -38
- package/dist/runtime/usage-report.js +152 -84
- package/dist/skills/changes.controller.js +2 -1
- package/dist/skills/changes.service.d.ts +1 -1
- package/dist/skills/changes.service.js +4 -4
- package/dist/skills/invocable.controller.d.ts +1 -1
- package/dist/skills/invocable.controller.js +2 -2
- package/dist/skills/invoke.d.ts +2 -2
- package/dist/skills/invoke.js +8 -1
- package/dist/skills/skills.controller.d.ts +4 -13
- package/dist/skills/skills.controller.js +8 -24
- package/dist/skills/skills.schemas.d.ts +48 -0
- package/dist/skills/skills.schemas.js +61 -0
- package/dist/skills/skills.service.d.ts +11 -1
- package/dist/skills/skills.service.js +37 -14
- package/dist/time-zone.d.ts +5 -0
- package/dist/time-zone.js +19 -0
- package/dist/tools/approvals.controller.js +2 -3
- package/dist/tools/approvals.schemas.d.ts +21 -0
- package/dist/tools/approvals.schemas.js +15 -0
- package/dist/tools/builtin-names.d.ts +10 -8
- package/dist/tools/builtin-names.js +16 -11
- package/dist/tools/builtins/builtin-tools.d.ts +3 -1
- package/dist/tools/builtins/builtin-tools.js +15 -3
- package/dist/tools/builtins/current-time.d.ts +26 -0
- package/dist/tools/builtins/current-time.js +99 -0
- package/dist/tools/builtins/platform.d.ts +19 -2
- package/dist/tools/builtins/platform.js +105 -16
- package/dist/tools/connectors.controller.d.ts +1 -2
- package/dist/tools/connectors.controller.js +1 -4
- package/dist/tools/connectors.schemas.d.ts +12 -0
- package/dist/tools/connectors.schemas.js +19 -0
- package/dist/tools/connectors.service.d.ts +5 -2
- package/dist/tools/connectors.service.js +7 -5
- package/dist/tools/org-tool-switches.d.ts +16 -2
- package/dist/tools/org-tool-switches.js +26 -9
- package/dist/tools/pipeline.js +9 -1
- package/dist/tools/registry.d.ts +48 -51
- package/dist/tools/registry.js +222 -233
- package/package.json +3 -3
- package/src/migrations/0089_model_kinds_usage.sql +38 -0
- package/src/migrations/0090_initial_passwords.sql +27 -0
- package/src/migrations/0091_account_time_zone.sql +4 -0
- package/src/migrations/0092_tools_default_on.sql +27 -0
- package/dist/platform/redact-orgs.d.ts +0 -7
- package/dist/platform/redact-orgs.js +0 -52
package/dist/identity/cookies.js
CHANGED
|
@@ -68,3 +68,17 @@ export function refreshCookieValues(header) {
|
|
|
68
68
|
}
|
|
69
69
|
return out;
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* The startup warning for an http trial that cannot sign in: session cookies are Secure but the
|
|
73
|
+
* configured public URL is plain http, so browsers drop them. Null when cookies are not Secure,
|
|
74
|
+
* or the public URL is https or unset (an unset URL says nothing about how people reach the app).
|
|
75
|
+
*/
|
|
76
|
+
export function insecurePublicUrlWarning(cfg) {
|
|
77
|
+
const url = cfg.http.publicUrl;
|
|
78
|
+
if (!cfg.auth.cookieSecure || url === undefined || !url.startsWith("http://"))
|
|
79
|
+
return null;
|
|
80
|
+
const host = new URL(url).hostname;
|
|
81
|
+
if (host === "localhost" || host.endsWith(".localhost") || host === "127.0.0.1")
|
|
82
|
+
return null;
|
|
83
|
+
return `http.publicUrl is ${url} (plain http) while auth.cookieSecure is true: browsers drop the Secure session cookies, so sign-in will not stick. Serve the app over HTTPS, or for a short http trial set auth.cookieSecure=false (CAPYBARA_AUTH__COOKIE_SECURE=false; CAPYBARA_COOKIE_SECURE=false in the compose .env)`;
|
|
84
|
+
}
|
|
@@ -13,6 +13,7 @@ import { ApiTokenService } from "./api-tokens.js";
|
|
|
13
13
|
import { IdentityBinding } from "./binding.js";
|
|
14
14
|
import { ExternalIdentities } from "./external.js";
|
|
15
15
|
import { ExternalIdentityLock } from "./external-identity-lock.js";
|
|
16
|
+
import { InitialPasswords } from "./initial-passwords.js";
|
|
16
17
|
import { SessionService } from "./sessions.js";
|
|
17
18
|
import { SettingsService } from "./settings.js";
|
|
18
19
|
import { SsoFlow } from "./sso.js";
|
|
@@ -40,6 +41,7 @@ IdentityModule = __decorate([
|
|
|
40
41
|
ExternalIdentities,
|
|
41
42
|
IdentityBinding,
|
|
42
43
|
SsoFlow,
|
|
44
|
+
InitialPasswords,
|
|
43
45
|
],
|
|
44
46
|
exports: [
|
|
45
47
|
AccountsModule,
|
|
@@ -50,6 +52,7 @@ IdentityModule = __decorate([
|
|
|
50
52
|
ExternalIdentities,
|
|
51
53
|
IdentityBinding,
|
|
52
54
|
SsoFlow,
|
|
55
|
+
InitialPasswords,
|
|
53
56
|
],
|
|
54
57
|
})
|
|
55
58
|
], IdentityModule);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type OrgContext } from "../orgs/org.guard.js";
|
|
3
|
+
import { InitialPasswords } from "./initial-passwords.js";
|
|
4
|
+
import { type Principal } from "./principal.js";
|
|
5
|
+
declare const ApprovalParams: z.ZodObject<{
|
|
6
|
+
approvalId: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
/**
|
|
9
|
+
* The generated initial password of an account the super admin's agent created (Platform tool
|
|
10
|
+
* spec §14.5 item 2): shown once, on the web, to the person who approved the `accounts.create`
|
|
11
|
+
* call. A POST because reading consumes it.
|
|
12
|
+
*/
|
|
13
|
+
export declare class InitialPasswordsController {
|
|
14
|
+
private readonly passwords;
|
|
15
|
+
constructor(passwords: InitialPasswords);
|
|
16
|
+
reveal(principal: Principal, org: OrgContext, params: z.infer<typeof ApprovalParams>): Promise<{
|
|
17
|
+
accountId: string;
|
|
18
|
+
login: string | null;
|
|
19
|
+
password: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Controller, HttpCode, Inject, Post } from "@nestjs/common";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
13
|
+
import { ZParam } from "../infra/validation/zod-params.js";
|
|
14
|
+
import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
|
|
15
|
+
import { InitialPasswords } from "./initial-passwords.js";
|
|
16
|
+
import { CurrentPrincipal, requireUser, SessionOnly, SuperAdmin, } from "./principal.js";
|
|
17
|
+
const ApprovalParams = z.object({ approvalId: z.string().min(1).max(100) });
|
|
18
|
+
class ApprovalParamsDto extends createZodDto(ApprovalParams, "InitialPasswordParams") {
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The generated initial password of an account the super admin's agent created (Platform tool
|
|
22
|
+
* spec §14.5 item 2): shown once, on the web, to the person who approved the `accounts.create`
|
|
23
|
+
* call. A POST because reading consumes it.
|
|
24
|
+
*/
|
|
25
|
+
let InitialPasswordsController = class InitialPasswordsController {
|
|
26
|
+
passwords;
|
|
27
|
+
constructor(passwords) {
|
|
28
|
+
this.passwords = passwords;
|
|
29
|
+
}
|
|
30
|
+
async reveal(principal, org, params) {
|
|
31
|
+
const p = requireUser(principal);
|
|
32
|
+
return this.passwords.reveal(org.orgId, params.approvalId, p.account.id);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
__decorate([
|
|
36
|
+
Post(),
|
|
37
|
+
HttpCode(200),
|
|
38
|
+
OrgAction("org.read"),
|
|
39
|
+
SuperAdmin(),
|
|
40
|
+
SessionOnly(),
|
|
41
|
+
__param(0, CurrentPrincipal()),
|
|
42
|
+
__param(1, CurrentOrg()),
|
|
43
|
+
__param(2, ZParam(ApprovalParamsDto))
|
|
44
|
+
], InitialPasswordsController.prototype, "reveal", null);
|
|
45
|
+
InitialPasswordsController = __decorate([
|
|
46
|
+
Controller("api/v1/orgs/:orgId/approvals/:approvalId/initial-password"),
|
|
47
|
+
__param(0, Inject(InitialPasswords))
|
|
48
|
+
], InitialPasswordsController);
|
|
49
|
+
export { InitialPasswordsController };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Keyring } from "../ctx/secrets.js";
|
|
2
|
+
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
3
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
4
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
5
|
+
import { type Account, AccountsService } from "./accounts.js";
|
|
6
|
+
/**
|
|
7
|
+
* How long a generated password waits for its reader. The approving person reads it right after
|
|
8
|
+
* the call runs; one that is never read expires (the account can still be disabled and recreated).
|
|
9
|
+
*/
|
|
10
|
+
export declare const INITIAL_PASSWORD_TTL_MS: number;
|
|
11
|
+
/** The tool key of the approval a generated password belongs to. */
|
|
12
|
+
export declare const CREATE_ACCOUNT_TOOL_KEY = "Platform:accounts.create";
|
|
13
|
+
/** A one-time initial password, cryptographically random. */
|
|
14
|
+
export declare function generateInitialPassword(): string;
|
|
15
|
+
/** Where a generated password is delivered: the approved tool call and the person who approved. */
|
|
16
|
+
export interface InitialPasswordDelivery {
|
|
17
|
+
conversationId: string;
|
|
18
|
+
/** The run of the call: a call id is unique only within its run. */
|
|
19
|
+
runId: string;
|
|
20
|
+
callId: string;
|
|
21
|
+
/** The account that may read it: the actor who confirmed the call. */
|
|
22
|
+
recipientAccountId: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Accounts created with a kernel-generated one-time password (Platform tool spec §14.5 item 2).
|
|
26
|
+
* The password never leaves the kernel except through {@link reveal}: it is not returned to the
|
|
27
|
+
* caller, not written to the audit, the event log or the logs. It is sealed with the master keyring
|
|
28
|
+
* in the creation's transaction and read once, on the web, by the person who approved the call.
|
|
29
|
+
*/
|
|
30
|
+
export declare class InitialPasswords {
|
|
31
|
+
private readonly db;
|
|
32
|
+
readonly txHost: TransactionHost;
|
|
33
|
+
private readonly keyring;
|
|
34
|
+
private readonly accounts;
|
|
35
|
+
constructor(db: KernelDb, txHost: TransactionHost, keyring: Keyring, accounts: AccountsService);
|
|
36
|
+
/**
|
|
37
|
+
* Creates a local account (never a super admin) with a generated password it must change at
|
|
38
|
+
* first sign-in, and seals the password for `to`. Returns the account only.
|
|
39
|
+
*/
|
|
40
|
+
createAccount(input: {
|
|
41
|
+
login: string;
|
|
42
|
+
displayName: string;
|
|
43
|
+
email?: string;
|
|
44
|
+
}, actorAccountId: string, to: InitialPasswordDelivery, auditDetail?: Record<string, unknown>): Promise<Account>;
|
|
45
|
+
/** Stores the sealed password in the creation's transaction (the hourly job drops expired ones). */
|
|
46
|
+
private seal;
|
|
47
|
+
/**
|
|
48
|
+
* The password created by an approved `accounts.create` call, read once by the person who
|
|
49
|
+
* approved it (`approvalId` in `orgId`, decided by `accountId`), then deleted. Anything else (not
|
|
50
|
+
* that person, not approved, not run yet, read already, expired) is
|
|
51
|
+
* `account.initial_password_unavailable`, saying nothing about which. Audits the read (without
|
|
52
|
+
* the password).
|
|
53
|
+
*/
|
|
54
|
+
reveal(orgId: string, approvalId: string, accountId: string): Promise<{
|
|
55
|
+
accountId: string;
|
|
56
|
+
login: string | null;
|
|
57
|
+
password: string;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
/** Deletes the sealed passwords past `expires_at`; returns how many. */
|
|
61
|
+
export declare function deleteExpiredInitialPasswords(db: KernelSchemaDb): Promise<number>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
2
|
+
import { LockService } from "../infra/lock/lock.service.js";
|
|
3
|
+
import type { KernelLogger } from "../log.js";
|
|
4
|
+
/** The hourly cleanup of expired sealed initial passwords (`@LockedCron`). */
|
|
5
|
+
export declare const INITIAL_PASSWORD_CLEANUP_JOB = "initial-password-cleanup";
|
|
6
|
+
/**
|
|
7
|
+
* Deletes generated initial passwords nobody read before they expired (Platform tool spec §14.5
|
|
8
|
+
* item 2), once per tick across replicas; the worker role's.
|
|
9
|
+
*/
|
|
10
|
+
export declare class InitialPasswordCleanupJob {
|
|
11
|
+
private readonly db;
|
|
12
|
+
readonly lockService: LockService;
|
|
13
|
+
readonly log: KernelLogger;
|
|
14
|
+
constructor(db: KernelDb, lockService: LockService, log: KernelLogger);
|
|
15
|
+
cleanup(): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
11
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
12
|
+
import { LockService } from "../infra/lock/lock.service.js";
|
|
13
|
+
import { LockedCron } from "../infra/schedule/locked-cron.decorator.js";
|
|
14
|
+
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
15
|
+
import { deleteExpiredInitialPasswords } from "./initial-passwords.js";
|
|
16
|
+
/** The hourly cleanup of expired sealed initial passwords (`@LockedCron`). */
|
|
17
|
+
export const INITIAL_PASSWORD_CLEANUP_JOB = "initial-password-cleanup";
|
|
18
|
+
/**
|
|
19
|
+
* Deletes generated initial passwords nobody read before they expired (Platform tool spec §14.5
|
|
20
|
+
* item 2), once per tick across replicas; the worker role's.
|
|
21
|
+
*/
|
|
22
|
+
let InitialPasswordCleanupJob = class InitialPasswordCleanupJob {
|
|
23
|
+
db;
|
|
24
|
+
lockService;
|
|
25
|
+
log;
|
|
26
|
+
constructor(db, lockService, log) {
|
|
27
|
+
this.db = db;
|
|
28
|
+
this.lockService = lockService;
|
|
29
|
+
this.log = log;
|
|
30
|
+
}
|
|
31
|
+
async cleanup() {
|
|
32
|
+
const n = await deleteExpiredInitialPasswords(this.db.db);
|
|
33
|
+
if (n > 0)
|
|
34
|
+
this.log.info("expired initial passwords deleted", { count: n });
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
__decorate([
|
|
38
|
+
LockedCron("20 * * * *", { name: INITIAL_PASSWORD_CLEANUP_JOB })
|
|
39
|
+
], InitialPasswordCleanupJob.prototype, "cleanup", null);
|
|
40
|
+
InitialPasswordCleanupJob = __decorate([
|
|
41
|
+
Injectable(),
|
|
42
|
+
__param(0, Inject(KernelDb)),
|
|
43
|
+
__param(1, Inject(LockService)),
|
|
44
|
+
__param(2, Inject(KERNEL_LOGGER))
|
|
45
|
+
], InitialPasswordCleanupJob);
|
|
46
|
+
export { InitialPasswordCleanupJob };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { randomInt } from "node:crypto";
|
|
11
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
12
|
+
import { sql } from "kysely";
|
|
13
|
+
import { ApiError } from "../errors.js";
|
|
14
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
15
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
16
|
+
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
17
|
+
import { KEYRING } from "../infra/tokens.js";
|
|
18
|
+
import { AccountsService } from "./accounts.js";
|
|
19
|
+
import { audit } from "./audit.js";
|
|
20
|
+
/** Letters and digits without the look-alikes (0 O 1 l I): read off a screen and typed by hand. */
|
|
21
|
+
const ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
|
|
22
|
+
/** 20 characters of 56: about 116 bits. */
|
|
23
|
+
const LENGTH = 20;
|
|
24
|
+
/**
|
|
25
|
+
* How long a generated password waits for its reader. The approving person reads it right after
|
|
26
|
+
* the call runs; one that is never read expires (the account can still be disabled and recreated).
|
|
27
|
+
*/
|
|
28
|
+
export const INITIAL_PASSWORD_TTL_MS = 24 * 60 * 60 * 1000;
|
|
29
|
+
/** The tool key of the approval a generated password belongs to. */
|
|
30
|
+
export const CREATE_ACCOUNT_TOOL_KEY = "Platform:accounts.create";
|
|
31
|
+
/** A one-time initial password, cryptographically random. */
|
|
32
|
+
export function generateInitialPassword() {
|
|
33
|
+
let out = "";
|
|
34
|
+
for (let i = 0; i < LENGTH; i++)
|
|
35
|
+
out += ALPHABET[randomInt(ALPHABET.length)];
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/** The AAD binding a sealed password to its account (a row moved to another account fails). */
|
|
39
|
+
const aadOf = (accountId) => `capybara:initial-password:${accountId}`;
|
|
40
|
+
/**
|
|
41
|
+
* Accounts created with a kernel-generated one-time password (Platform tool spec §14.5 item 2).
|
|
42
|
+
* The password never leaves the kernel except through {@link reveal}: it is not returned to the
|
|
43
|
+
* caller, not written to the audit, the event log or the logs. It is sealed with the master keyring
|
|
44
|
+
* in the creation's transaction and read once, on the web, by the person who approved the call.
|
|
45
|
+
*/
|
|
46
|
+
let InitialPasswords = class InitialPasswords {
|
|
47
|
+
db;
|
|
48
|
+
txHost;
|
|
49
|
+
keyring;
|
|
50
|
+
accounts;
|
|
51
|
+
constructor(db, txHost, keyring, accounts) {
|
|
52
|
+
this.db = db;
|
|
53
|
+
this.txHost = txHost;
|
|
54
|
+
this.keyring = keyring;
|
|
55
|
+
this.accounts = accounts;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Creates a local account (never a super admin) with a generated password it must change at
|
|
59
|
+
* first sign-in, and seals the password for `to`. Returns the account only.
|
|
60
|
+
*/
|
|
61
|
+
async createAccount(input, actorAccountId, to, auditDetail) {
|
|
62
|
+
const password = generateInitialPassword();
|
|
63
|
+
return this.accounts.createByAdmin({ ...input, password, superAdmin: false, mustChangePassword: true }, actorAccountId, undefined, {
|
|
64
|
+
...(auditDetail !== undefined && { auditDetail }),
|
|
65
|
+
inTransaction: (account) => this.seal(account.id, password, to),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Stores the sealed password in the creation's transaction (the hourly job drops expired ones). */
|
|
69
|
+
async seal(accountId, password, to) {
|
|
70
|
+
const { data, masterKeyId } = this.keyring.wrap(Buffer.from(password, "utf8"), aadOf(accountId));
|
|
71
|
+
await this.db
|
|
72
|
+
.insertInto("account_initial_passwords")
|
|
73
|
+
.values({
|
|
74
|
+
account_id: accountId,
|
|
75
|
+
recipient_account_id: to.recipientAccountId,
|
|
76
|
+
conversation_id: to.conversationId,
|
|
77
|
+
run_id: to.runId,
|
|
78
|
+
call_id: to.callId,
|
|
79
|
+
master_key_id: masterKeyId,
|
|
80
|
+
ciphertext: data,
|
|
81
|
+
expires_at: new Date(Date.now() + INITIAL_PASSWORD_TTL_MS),
|
|
82
|
+
})
|
|
83
|
+
.execute();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The password created by an approved `accounts.create` call, read once by the person who
|
|
87
|
+
* approved it (`approvalId` in `orgId`, decided by `accountId`), then deleted. Anything else (not
|
|
88
|
+
* that person, not approved, not run yet, read already, expired) is
|
|
89
|
+
* `account.initial_password_unavailable`, saying nothing about which. Audits the read (without
|
|
90
|
+
* the password).
|
|
91
|
+
*/
|
|
92
|
+
async reveal(orgId, approvalId, accountId) {
|
|
93
|
+
const unavailable = () => new ApiError("account.initial_password_unavailable", "No initial password to show: it was shown already, has expired, or the account was not created by a call you approved");
|
|
94
|
+
const approval = await this.db
|
|
95
|
+
.selectFrom("approvals")
|
|
96
|
+
.select(["conversation_id", "run_id", "call_id", "tool_key", "status", "decided_by"])
|
|
97
|
+
.where("id", "=", approvalId)
|
|
98
|
+
.where("org_id", "=", orgId)
|
|
99
|
+
.executeTakeFirst();
|
|
100
|
+
if (approval === undefined ||
|
|
101
|
+
approval.tool_key !== CREATE_ACCOUNT_TOOL_KEY ||
|
|
102
|
+
approval.status !== "approved" ||
|
|
103
|
+
approval.decided_by !== accountId) {
|
|
104
|
+
throw unavailable();
|
|
105
|
+
}
|
|
106
|
+
// exactly the row of this approval's call: locked, then deleted by its key
|
|
107
|
+
const found = await this.db
|
|
108
|
+
.selectFrom("account_initial_passwords")
|
|
109
|
+
.select("account_id")
|
|
110
|
+
.where("conversation_id", "=", approval.conversation_id)
|
|
111
|
+
.where("run_id", "=", approval.run_id)
|
|
112
|
+
.where("call_id", "=", approval.call_id)
|
|
113
|
+
.where("recipient_account_id", "=", accountId)
|
|
114
|
+
.where("expires_at", ">", sql `now()`)
|
|
115
|
+
.limit(1)
|
|
116
|
+
.forUpdate()
|
|
117
|
+
.executeTakeFirst();
|
|
118
|
+
if (found === undefined)
|
|
119
|
+
throw unavailable();
|
|
120
|
+
const row = await this.db
|
|
121
|
+
.deleteFrom("account_initial_passwords")
|
|
122
|
+
.where("account_id", "=", found.account_id)
|
|
123
|
+
.returning(["account_id", "master_key_id", "ciphertext"])
|
|
124
|
+
.executeTakeFirst();
|
|
125
|
+
if (row === undefined)
|
|
126
|
+
throw unavailable();
|
|
127
|
+
const password = this.keyring
|
|
128
|
+
.unwrap(row.master_key_id, row.ciphertext, aadOf(row.account_id))
|
|
129
|
+
.toString("utf8");
|
|
130
|
+
const login = (await this.accounts.localLogins([row.account_id])).get(row.account_id) ?? null;
|
|
131
|
+
await audit(this.db.db, {
|
|
132
|
+
actorAccountId: accountId,
|
|
133
|
+
orgId,
|
|
134
|
+
action: "account.initial_password_shown",
|
|
135
|
+
target: row.account_id,
|
|
136
|
+
detail: { approvalId },
|
|
137
|
+
});
|
|
138
|
+
return { accountId: row.account_id, login, password };
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
__decorate([
|
|
142
|
+
Transactional()
|
|
143
|
+
], InitialPasswords.prototype, "reveal", null);
|
|
144
|
+
InitialPasswords = __decorate([
|
|
145
|
+
Injectable(),
|
|
146
|
+
__param(0, Inject(KernelDb)),
|
|
147
|
+
__param(1, Inject(TransactionHost)),
|
|
148
|
+
__param(2, Inject(KEYRING)),
|
|
149
|
+
__param(3, Inject(AccountsService))
|
|
150
|
+
], InitialPasswords);
|
|
151
|
+
export { InitialPasswords };
|
|
152
|
+
/** Deletes the sealed passwords past `expires_at`; returns how many. */
|
|
153
|
+
export async function deleteExpiredInitialPasswords(db) {
|
|
154
|
+
const r = await db
|
|
155
|
+
.deleteFrom("account_initial_passwords")
|
|
156
|
+
.where("expires_at", "<=", sql `now()`)
|
|
157
|
+
.executeTakeFirst();
|
|
158
|
+
return Number(r.numDeletedRows);
|
|
159
|
+
}
|
|
@@ -17,6 +17,9 @@ declare const TokenSchema: z.ZodObject<{
|
|
|
17
17
|
name: z.ZodString;
|
|
18
18
|
expiresAt: z.ZodOptional<z.ZodPipe<z.ZodISODateTime, z.ZodTransform<Date, string>>>;
|
|
19
19
|
}, z.core.$strip>;
|
|
20
|
+
declare const PreferencesSchema: z.ZodObject<{
|
|
21
|
+
timeZone: z.ZodNullable<z.ZodString>;
|
|
22
|
+
}, z.core.$strict>;
|
|
20
23
|
declare const CurrentOrgSchema: z.ZodObject<{
|
|
21
24
|
orgId: z.ZodNullable<z.ZodString>;
|
|
22
25
|
}, z.core.$strip>;
|
|
@@ -44,6 +47,17 @@ export declare class MeController {
|
|
|
44
47
|
/** Whether `POST /api/v1/orgs` would accept this account (the `orgCreation` setting). */
|
|
45
48
|
canCreateOrg: boolean;
|
|
46
49
|
}>;
|
|
50
|
+
/**
|
|
51
|
+
* The person's preferences (run context spec §3.4): `timeZone` null = follow the browser's time
|
|
52
|
+
* zone sent with each message; a set zone overrides it for the messages sent afterwards.
|
|
53
|
+
*/
|
|
54
|
+
preferences(principal: Principal): Promise<{
|
|
55
|
+
timeZone: string | null;
|
|
56
|
+
}>;
|
|
57
|
+
/** Replaces the person's preferences; an unknown time zone → 400 `validation_failed`. */
|
|
58
|
+
setPreferences(principal: Principal, body: z.infer<typeof PreferencesSchema>): Promise<{
|
|
59
|
+
timeZone: string | null;
|
|
60
|
+
}>;
|
|
47
61
|
/** 切换当前组织(仅 Web 会话);`null` 清空。非成员或已软删除的组织 → `org.not_found`。 */
|
|
48
62
|
setCurrentOrg(principal: Principal, body: z.infer<typeof CurrentOrgSchema>): Promise<void>;
|
|
49
63
|
/**
|
|
@@ -15,10 +15,11 @@ import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
|
15
15
|
import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
16
16
|
import { ZBody } from "../infra/validation/zod-params.js";
|
|
17
17
|
import { OrgsService } from "../orgs/orgs.service.js";
|
|
18
|
+
import { IanaTimeZone } from "../time-zone.js";
|
|
18
19
|
import { AccountsService } from "./accounts.js";
|
|
19
20
|
import { ApiTokenService, FutureIsoDate } from "./api-tokens.js";
|
|
20
21
|
import { MAX_PASSWORD_LENGTH } from "./login.js";
|
|
21
|
-
import { CurrentPrincipal, requireUser, SessionOnly } from "./principal.js";
|
|
22
|
+
import { AllowPendingPasswordChange, CurrentPrincipal, requireUser, SessionOnly, } from "./principal.js";
|
|
22
23
|
import { SessionService } from "./sessions.js";
|
|
23
24
|
import { SettingsService } from "./settings.js";
|
|
24
25
|
/** The credential throttlers of a password change (per account, per client IP). */
|
|
@@ -35,6 +36,14 @@ const TokenSchema = z.object({
|
|
|
35
36
|
});
|
|
36
37
|
class PersonalTokenBody extends createZodDto(TokenSchema, "PersonalTokenBody") {
|
|
37
38
|
}
|
|
39
|
+
const PreferencesSchema = z
|
|
40
|
+
.object({
|
|
41
|
+
/** The person's time zone (IANA); null = follow the browser (run context spec §3.4). */
|
|
42
|
+
timeZone: IanaTimeZone.nullable(),
|
|
43
|
+
})
|
|
44
|
+
.strict();
|
|
45
|
+
class PreferencesBody extends createZodDto(PreferencesSchema, "PreferencesBody") {
|
|
46
|
+
}
|
|
38
47
|
const CurrentOrgSchema = z.object({ orgId: z.string().min(1).nullable() });
|
|
39
48
|
class CurrentOrgBody extends createZodDto(CurrentOrgSchema, "CurrentOrgBody") {
|
|
40
49
|
}
|
|
@@ -72,6 +81,19 @@ let MeController = class MeController {
|
|
|
72
81
|
const canCreateOrg = orgCreation === "anyone" || p.account.isSuperAdmin;
|
|
73
82
|
return { account: p.account, via: p.via, currentOrgId: current, memberships, canCreateOrg };
|
|
74
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* The person's preferences (run context spec §3.4): `timeZone` null = follow the browser's time
|
|
86
|
+
* zone sent with each message; a set zone overrides it for the messages sent afterwards.
|
|
87
|
+
*/
|
|
88
|
+
async preferences(principal) {
|
|
89
|
+
return this.accounts.preferences(requireUser(principal).account.id);
|
|
90
|
+
}
|
|
91
|
+
/** Replaces the person's preferences; an unknown time zone → 400 `validation_failed`. */
|
|
92
|
+
async setPreferences(principal, body) {
|
|
93
|
+
return this.accounts.setPreferences(requireUser(principal).account.id, {
|
|
94
|
+
timeZone: body.timeZone,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
75
97
|
/** 切换当前组织(仅 Web 会话);`null` 清空。非成员或已软删除的组织 → `org.not_found`。 */
|
|
76
98
|
async setCurrentOrg(principal, body) {
|
|
77
99
|
const p = requireUser(principal);
|
|
@@ -97,6 +119,11 @@ let MeController = class MeController {
|
|
|
97
119
|
throw new ApiError("auth.invalid_credentials", "Current password is incorrect");
|
|
98
120
|
}
|
|
99
121
|
await this.throttler.succeeded(CHANGE_PASSWORD_THROTTLERS, req);
|
|
122
|
+
if (p.account.mustChangePassword && body.newPassword === body.currentPassword) {
|
|
123
|
+
throw new ApiError("validation_failed", "Choose a password other than the initial one", [
|
|
124
|
+
{ path: "newPassword", message: "must differ from the initial password" },
|
|
125
|
+
]);
|
|
126
|
+
}
|
|
100
127
|
// 新密码、吊销其他会话(PG revoked_at)与个人令牌在同一个 PG 事务里完成
|
|
101
128
|
const revoked = await this.accounts.changePassword(p.account.id, body.newPassword, p.sessionId);
|
|
102
129
|
try {
|
|
@@ -125,8 +152,18 @@ let MeController = class MeController {
|
|
|
125
152
|
};
|
|
126
153
|
__decorate([
|
|
127
154
|
Get(),
|
|
155
|
+
AllowPendingPasswordChange(),
|
|
128
156
|
__param(0, CurrentPrincipal())
|
|
129
157
|
], MeController.prototype, "me", null);
|
|
158
|
+
__decorate([
|
|
159
|
+
Get("preferences"),
|
|
160
|
+
__param(0, CurrentPrincipal())
|
|
161
|
+
], MeController.prototype, "preferences", null);
|
|
162
|
+
__decorate([
|
|
163
|
+
Put("preferences"),
|
|
164
|
+
__param(0, CurrentPrincipal()),
|
|
165
|
+
__param(1, ZBody(PreferencesBody))
|
|
166
|
+
], MeController.prototype, "setPreferences", null);
|
|
130
167
|
__decorate([
|
|
131
168
|
Put("current-org"),
|
|
132
169
|
SessionOnly(),
|
|
@@ -137,6 +174,7 @@ __decorate([
|
|
|
137
174
|
__decorate([
|
|
138
175
|
Put("password"),
|
|
139
176
|
SessionOnly(),
|
|
177
|
+
AllowPendingPasswordChange(),
|
|
140
178
|
HttpCode(204),
|
|
141
179
|
__param(0, CurrentPrincipal()),
|
|
142
180
|
__param(1, ZBody(ChangePasswordBody)),
|
|
@@ -30,6 +30,7 @@ export declare const PUBLIC_KEY = "capybara:auth:public";
|
|
|
30
30
|
export declare const SESSION_ONLY_KEY = "capybara:auth:session-only";
|
|
31
31
|
export declare const SUPER_ADMIN_KEY = "capybara:auth:super-admin";
|
|
32
32
|
export declare const ALLOW_SERVICE_KEY = "capybara:auth:allow-service";
|
|
33
|
+
export declare const PASSWORD_CHANGE_KEY = "capybara:auth:password-change";
|
|
33
34
|
/**
|
|
34
35
|
* 不要求凭据:无凭据时放行(principal 为 undefined);带了有效凭据仍解析,无效凭据按无凭据处理。
|
|
35
36
|
* 非安全方法照样要求 `X-Capybara-Csrf: 1`(防登录 CSRF)。新增公开路由必须同时更新 public-routes 元测试的清单。
|
|
@@ -39,6 +40,13 @@ export declare const Public: () => MethodDecorator & ClassDecorator;
|
|
|
39
40
|
export declare const SessionOnly: () => MethodDecorator;
|
|
40
41
|
/** 仅超级管理员(user principal 且 `isSuperAdmin`);否则 `forbidden`。 */
|
|
41
42
|
export declare const SuperAdmin: () => MethodDecorator & ClassDecorator;
|
|
43
|
+
/**
|
|
44
|
+
* Reachable by an account that must change its generated initial password first
|
|
45
|
+
* (`Account.mustChangePassword`): the guard refuses every other route with
|
|
46
|
+
* `auth.password_change_required`. Only `GET /me` and `PUT /me/password` carry it (public routes
|
|
47
|
+
* such as logout are reachable anyway).
|
|
48
|
+
*/
|
|
49
|
+
export declare const AllowPendingPasswordChange: () => MethodDecorator;
|
|
42
50
|
/**
|
|
43
51
|
* 允许服务令牌(service principal)访问。默认拒绝:未标注的路由只接受 user principal,service → `forbidden`。
|
|
44
52
|
* 组织级路由由 OrgGuard 再核对令牌所属组织与角色。
|
|
@@ -4,6 +4,7 @@ export const PUBLIC_KEY = "capybara:auth:public";
|
|
|
4
4
|
export const SESSION_ONLY_KEY = "capybara:auth:session-only";
|
|
5
5
|
export const SUPER_ADMIN_KEY = "capybara:auth:super-admin";
|
|
6
6
|
export const ALLOW_SERVICE_KEY = "capybara:auth:allow-service";
|
|
7
|
+
export const PASSWORD_CHANGE_KEY = "capybara:auth:password-change";
|
|
7
8
|
/**
|
|
8
9
|
* 不要求凭据:无凭据时放行(principal 为 undefined);带了有效凭据仍解析,无效凭据按无凭据处理。
|
|
9
10
|
* 非安全方法照样要求 `X-Capybara-Csrf: 1`(防登录 CSRF)。新增公开路由必须同时更新 public-routes 元测试的清单。
|
|
@@ -13,6 +14,13 @@ export const Public = () => SetMetadata(PUBLIC_KEY, true);
|
|
|
13
14
|
export const SessionOnly = () => SetMetadata(SESSION_ONLY_KEY, true);
|
|
14
15
|
/** 仅超级管理员(user principal 且 `isSuperAdmin`);否则 `forbidden`。 */
|
|
15
16
|
export const SuperAdmin = () => SetMetadata(SUPER_ADMIN_KEY, true);
|
|
17
|
+
/**
|
|
18
|
+
* Reachable by an account that must change its generated initial password first
|
|
19
|
+
* (`Account.mustChangePassword`): the guard refuses every other route with
|
|
20
|
+
* `auth.password_change_required`. Only `GET /me` and `PUT /me/password` carry it (public routes
|
|
21
|
+
* such as logout are reachable anyway).
|
|
22
|
+
*/
|
|
23
|
+
export const AllowPendingPasswordChange = () => SetMetadata(PASSWORD_CHANGE_KEY, true);
|
|
16
24
|
/**
|
|
17
25
|
* 允许服务令牌(service principal)访问。默认拒绝:未标注的路由只接受 user principal,service → `forbidden`。
|
|
18
26
|
* 组织级路由由 OrgGuard 再核对令牌所属组织与角色。
|
|
@@ -133,6 +133,8 @@ export declare class SettingsService {
|
|
|
133
133
|
*/
|
|
134
134
|
get(): Promise<DeploymentSettings>;
|
|
135
135
|
/** Updates settings under the super admin lock, re-checking the actor (else `forbidden`). */
|
|
136
|
-
update(patch: DeploymentSettingsPatch, actorAccountId: string, actorTokenId?: string
|
|
136
|
+
update(patch: DeploymentSettingsPatch, actorAccountId: string, actorTokenId?: string,
|
|
137
|
+
/** Merged into the audit detail (the Platform tool's `via: "agent"`). */
|
|
138
|
+
auditDetail?: Record<string, unknown>): Promise<DeploymentSettings>;
|
|
137
139
|
private write;
|
|
138
140
|
}
|
|
@@ -241,15 +241,17 @@ let SettingsService = class SettingsService {
|
|
|
241
241
|
return out;
|
|
242
242
|
}
|
|
243
243
|
/** Updates settings under the super admin lock, re-checking the actor (else `forbidden`). */
|
|
244
|
-
async update(patch, actorAccountId, actorTokenId
|
|
244
|
+
async update(patch, actorAccountId, actorTokenId,
|
|
245
|
+
/** Merged into the audit detail (the Platform tool's `via: "agent"`). */
|
|
246
|
+
auditDetail) {
|
|
245
247
|
const check = DEPLOYMENT_SETTINGS_PATCH.safeParse(patch);
|
|
246
248
|
if (!check.success) {
|
|
247
249
|
throw new ApiError("validation_failed", "Invalid deployment settings", check.error.issues.map((i) => ({ path: i.path.join("."), message: i.message })));
|
|
248
250
|
}
|
|
249
|
-
await this.write(check.data, actorAccountId, actorTokenId);
|
|
251
|
+
await this.write(check.data, actorAccountId, actorTokenId, auditDetail);
|
|
250
252
|
return this.get();
|
|
251
253
|
}
|
|
252
|
-
async write(patch, actorAccountId, actorTokenId) {
|
|
254
|
+
async write(patch, actorAccountId, actorTokenId, auditDetail) {
|
|
253
255
|
await this.adminLock.lockAndAuthorize(actorAccountId);
|
|
254
256
|
// The super admin lock serializes every settings write: the current overrides are read
|
|
255
257
|
// and merged under it, so no concurrent change is lost
|
|
@@ -294,7 +296,7 @@ let SettingsService = class SettingsService {
|
|
|
294
296
|
actorAccountId,
|
|
295
297
|
...(actorTokenId !== undefined && { actorTokenId }),
|
|
296
298
|
action: "deployment.settings.updated",
|
|
297
|
-
detail: patch,
|
|
299
|
+
detail: { ...patch, ...auditDetail },
|
|
298
300
|
});
|
|
299
301
|
}
|
|
300
302
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { RouteSchemas } from "../platform/route-schemas.js";
|
|
3
|
+
/** `:id` of a notice dismissal (the org's and the platform's inbox). */
|
|
4
|
+
export declare const InboxNoticeParams: z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
/** The inbox routes (the org's and the super admin's) the Platform inbox operations mirror. */
|
|
8
|
+
export declare const INBOX_ROUTES: readonly RouteSchemas[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** `:id` of a notice dismissal (the org's and the platform's inbox). */
|
|
3
|
+
export const InboxNoticeParams = z.object({ id: z.string().min(1).max(100) });
|
|
4
|
+
/** The inbox routes (the org's and the super admin's) the Platform inbox operations mirror. */
|
|
5
|
+
export const INBOX_ROUTES = [
|
|
6
|
+
{ route: "GET /api/v1/orgs/:orgId/inbox" },
|
|
7
|
+
{ route: "POST /api/v1/orgs/:orgId/inbox/notices/:id/dismiss", params: InboxNoticeParams },
|
|
8
|
+
{ route: "GET /api/v1/admin/inbox" },
|
|
9
|
+
{ route: "GET /api/v1/admin/inbox/count" },
|
|
10
|
+
{ route: "POST /api/v1/admin/inbox/notices/:id/dismiss", params: InboxNoticeParams },
|
|
11
|
+
];
|
|
@@ -8,12 +8,12 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
8
8
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
9
|
};
|
|
10
10
|
import { Controller, Get, HttpCode, Inject, Post } from "@nestjs/common";
|
|
11
|
-
import { z } from "zod";
|
|
12
11
|
import { CurrentPrincipal, requireUser, SuperAdmin, } from "../identity/principal.js";
|
|
13
12
|
import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
14
13
|
import { ZParam } from "../infra/validation/zod-params.js";
|
|
14
|
+
import { InboxNoticeParams } from "./inbox.schemas.js";
|
|
15
15
|
import { PlatformInboxService } from "./platform-inbox.service.js";
|
|
16
|
-
const NoticeParamsSchema =
|
|
16
|
+
const NoticeParamsSchema = InboxNoticeParams;
|
|
17
17
|
class NoticeParams extends createZodDto(NoticeParamsSchema, "PlatformInboxNoticeParams") {
|
|
18
18
|
}
|
|
19
19
|
/**
|