@highstate/backend 0.9.18 → 0.9.20
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/dist/{chunk-OU5OQBLB.js → chunk-I7BWSAN6.js} +3 -28
- package/dist/{chunk-OU5OQBLB.js.map → chunk-I7BWSAN6.js.map} +1 -1
- package/dist/chunk-RC6Q3XQQ.js +1547 -0
- package/dist/chunk-RC6Q3XQQ.js.map +1 -0
- package/dist/chunk-VB4YL327.js +139 -0
- package/dist/chunk-VB4YL327.js.map +1 -0
- package/dist/database/local/prisma.config.js +26 -0
- package/dist/database/local/prisma.config.js.map +1 -0
- package/dist/highstate.manifest.json +2 -1
- package/dist/index.js +7590 -7289
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +1 -1
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/library/worker/main.js +35 -29
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +2 -2
- package/package.json +18 -9
- package/prisma/backend/_schema/layout.prisma +7 -0
- package/prisma/backend/_schema/library.prisma +17 -0
- package/prisma/backend/_schema/project.prisma +101 -0
- package/prisma/backend/_schema/pulumi.prisma +17 -0
- package/prisma/backend/postgresql/main.prisma +17 -0
- package/prisma/backend/sqlite/main.prisma +17 -0
- package/prisma/backend/sqlite/migrations/20250817070609_initiial/migration.sql +34 -0
- package/prisma/backend/sqlite/migrations/20250817104948_add_fields/migration.sql +59 -0
- package/prisma/backend/sqlite/migrations/20250818082732_add_models/migration.sql +41 -0
- package/prisma/backend/sqlite/migrations/20250818083106_a/migration.sql +19 -0
- package/prisma/backend/sqlite/migrations/20250818101945_hi/migration.sql +1 -0
- package/prisma/backend/sqlite/migrations/20250819082315_a/migration.sql +5 -0
- package/prisma/backend/sqlite/migrations/migration_lock.toml +3 -0
- package/prisma/project/api-key.prisma +32 -0
- package/prisma/project/artifact.prisma +52 -0
- package/prisma/project/custom-status.prisma +46 -0
- package/prisma/project/evaluation.prisma +45 -0
- package/prisma/project/instance.prisma +157 -0
- package/prisma/project/layout.prisma +23 -0
- package/prisma/project/lock.prisma +18 -0
- package/prisma/project/main.prisma +17 -0
- package/prisma/project/migrations/20250816081310_initial/migration.sql +300 -0
- package/prisma/project/migrations/20250816082523_test/migration.sql +72 -0
- package/prisma/project/migrations/20250818065643_update/migration.sql +42 -0
- package/prisma/project/migrations/20250818070758_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818070913_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818082720_add_motels/migration.sql +11 -0
- package/prisma/project/migrations/20250818112523_hello/migration.sql +35 -0
- package/prisma/project/migrations/20250819082305_a/migration.sql +14 -0
- package/prisma/project/migrations/20250819165004_add_missing_fields/migration.sql +216 -0
- package/prisma/project/migrations/20250819171309_a/migration.sql +22 -0
- package/prisma/project/migrations/20250820113949_a/migration.sql +66 -0
- package/prisma/project/migrations/20250820144256_b/migration.sql +31 -0
- package/prisma/project/migrations/20250820145547_a/migration.sql +24 -0
- package/prisma/project/migrations/20250820182517_b/migration.sql +2 -0
- package/prisma/project/migrations/20250821172324_a/migration.sql +2 -0
- package/prisma/project/migrations/20250822081339_a/migration.sql +219 -0
- package/prisma/project/migrations/20250822083742_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822105134_boom/migration.sql +1 -0
- package/prisma/project/migrations/20250822141028_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822142342_b/migration.sql +16 -0
- package/prisma/project/migrations/20250824072720_a/migration.sql +1 -0
- package/prisma/project/migrations/20250824093656_b/migration.sql +21 -0
- package/prisma/project/migrations/20250825082518_a/migration.sql +1 -0
- package/prisma/project/migrations/20250825085343_b/migration.sql +1 -0
- package/prisma/project/migrations/20250825091312_a/migration.sql +1 -0
- package/prisma/project/migrations/20250903095431_hi/migration.sql +44 -0
- package/prisma/project/migrations/20250903174255_a/migration.sql +24 -0
- package/prisma/project/migrations/20250908095205_hi/migration.sql +18 -0
- package/prisma/project/migrations/20250909155857_hi/migration.sql +15 -0
- package/prisma/project/migrations/migration_lock.toml +3 -0
- package/prisma/project/model.prisma +37 -0
- package/prisma/project/operation.prisma +148 -0
- package/prisma/project/page.prisma +49 -0
- package/prisma/project/secret.prisma +54 -0
- package/prisma/project/service-account.prisma +42 -0
- package/prisma/project/terminal.prisma +107 -0
- package/prisma/project/trigger.prisma +37 -0
- package/prisma/project/unlock-method.prisma +46 -0
- package/prisma/project/worker.prisma +169 -0
- package/src/artifact/abstractions.ts +13 -13
- package/src/artifact/encryption.ts +30 -54
- package/src/artifact/factory.ts +6 -9
- package/src/artifact/local.ts +33 -46
- package/src/business/api-key.ts +24 -36
- package/src/business/artifact.test.ts +978 -0
- package/src/business/artifact.ts +136 -216
- package/src/business/evaluation.ts +328 -0
- package/src/business/index.ts +5 -2
- package/src/business/instance-lock.test.ts +1060 -0
- package/src/business/instance-lock.ts +387 -78
- package/src/business/instance-state.test.ts +735 -0
- package/src/business/instance-state.ts +582 -337
- package/src/business/operation.test.ts +439 -0
- package/src/business/operation.ts +174 -208
- package/src/business/project-model.ts +258 -0
- package/src/business/project-unlock.ts +168 -126
- package/src/business/project.ts +287 -179
- package/src/business/secret.test.ts +469 -130
- package/src/business/secret.ts +177 -217
- package/src/business/settings.test.ts +695 -0
- package/src/business/settings.ts +855 -0
- package/src/business/terminal-session.ts +90 -0
- package/src/business/unit-extra.test.ts +539 -0
- package/src/business/unit-extra.ts +160 -0
- package/src/business/worker.test.ts +356 -579
- package/src/business/worker.ts +238 -339
- package/src/common/codebase.ts +65 -0
- package/src/common/index.ts +3 -5
- package/src/common/logger.ts +5 -0
- package/src/common/utils.ts +4 -3
- package/src/config.ts +10 -11
- package/src/database/_generated/backend/postgresql/client.ts +72 -0
- package/src/database/_generated/backend/postgresql/commonInputTypes.ts +350 -0
- package/src/database/_generated/backend/postgresql/enums.ts +13 -0
- package/src/database/_generated/backend/postgresql/internal/class.ts +320 -0
- package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +1238 -0
- package/src/database/_generated/backend/postgresql/models/Library.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/Project.ts +2175 -0
- package/src/database/_generated/backend/postgresql/models/ProjectModelStorage.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/ProjectSpace.ts +1602 -0
- package/src/database/_generated/backend/postgresql/models/PulumiBackend.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/UserWorkspaseLayout.ts +1065 -0
- package/src/database/_generated/backend/postgresql/models.ts +16 -0
- package/src/database/_generated/backend/postgresql/pjtg.ts +182 -0
- package/src/database/_generated/backend/sqlite/client.ts +72 -0
- package/src/database/_generated/backend/sqlite/commonInputTypes.ts +331 -0
- package/src/database/_generated/backend/sqlite/enums.ts +13 -0
- package/src/database/_generated/backend/sqlite/internal/class.ts +318 -0
- package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +1207 -0
- package/src/database/_generated/backend/sqlite/models/Library.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/Project.ts +2169 -0
- package/src/database/_generated/backend/sqlite/models/ProjectModelStorage.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/ProjectSpace.ts +1599 -0
- package/src/database/_generated/backend/sqlite/models/PulumiBackend.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/UserWorkspaseLayout.ts +1063 -0
- package/src/database/_generated/backend/sqlite/models.ts +16 -0
- package/src/database/_generated/backend/sqlite/pjtg.ts +182 -0
- package/src/database/_generated/project/client.ts +204 -0
- package/src/database/_generated/project/commonInputTypes.ts +827 -0
- package/src/database/_generated/project/enums.ts +104 -0
- package/src/database/_generated/project/internal/class.ts +479 -0
- package/src/database/_generated/project/internal/prismaNamespace.ts +2974 -0
- package/src/database/_generated/project/models/ApiKey.ts +1506 -0
- package/src/database/_generated/project/models/Artifact.ts +2051 -0
- package/src/database/_generated/project/models/HubModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceCustomStatus.ts +1713 -0
- package/src/database/_generated/project/models/InstanceEvaluationState.ts +1312 -0
- package/src/database/_generated/project/models/InstanceLock.ts +1268 -0
- package/src/database/_generated/project/models/InstanceModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceOperationState.ts +1707 -0
- package/src/database/_generated/project/models/InstanceState.ts +4613 -0
- package/src/database/_generated/project/models/Operation.ts +1647 -0
- package/src/database/_generated/project/models/OperationLog.ts +1455 -0
- package/src/database/_generated/project/models/Page.ts +1838 -0
- package/src/database/_generated/project/models/Secret.ts +1692 -0
- package/src/database/_generated/project/models/ServiceAccount.ts +2165 -0
- package/src/database/_generated/project/models/Terminal.ts +2038 -0
- package/src/database/_generated/project/models/TerminalSession.ts +1454 -0
- package/src/database/_generated/project/models/TerminalSessionLog.ts +1280 -0
- package/src/database/_generated/project/models/Trigger.ts +1430 -0
- package/src/database/_generated/project/models/UnlockMethod.ts +1220 -0
- package/src/database/_generated/project/models/UserCompositeViewport.ts +1280 -0
- package/src/database/_generated/project/models/UserProjectViewport.ts +1059 -0
- package/src/database/_generated/project/models/Worker.ts +1459 -0
- package/src/database/_generated/project/models/WorkerUnitRegistration.ts +1524 -0
- package/src/database/_generated/project/models/WorkerVersion.ts +1974 -0
- package/src/database/_generated/project/models/WorkerVersionLog.ts +1318 -0
- package/src/database/_generated/project/models.ts +35 -0
- package/src/database/_generated/project/pjtg.ts +182 -0
- package/src/database/abstractions.ts +19 -0
- package/src/database/factory.ts +37 -0
- package/src/database/index.ts +6 -0
- package/src/database/local/backend.ts +134 -0
- package/src/database/local/index.ts +3 -0
- package/src/database/local/meta.ts +46 -0
- package/src/database/local/prisma.config.ts +25 -0
- package/src/database/local/project.ts +39 -0
- package/src/database/manager.ts +181 -0
- package/src/database/migrate.ts +35 -0
- package/src/database/prisma.ts +56 -0
- package/src/database/well-known.ts +38 -0
- package/src/index.ts +4 -4
- package/src/library/abstractions.ts +3 -5
- package/src/library/factory.ts +1 -1
- package/src/library/local.ts +81 -26
- package/src/library/package-resolution-worker.ts +1 -1
- package/src/library/worker/evaluator.ts +40 -23
- package/src/library/worker/loader.lite.ts +1 -1
- package/src/library/worker/main.ts +3 -10
- package/src/library/worker/protocol.ts +0 -1
- package/src/lock/index.ts +0 -1
- package/src/lock/manager.ts +0 -10
- package/src/orchestrator/manager.ts +190 -104
- package/src/orchestrator/operation-context.ts +357 -0
- package/src/orchestrator/operation-plan.destroy.test.md +357 -0
- package/src/orchestrator/operation-plan.destroy.test.ts +775 -0
- package/src/orchestrator/operation-plan.fixtures.ts +213 -0
- package/src/orchestrator/operation-plan.md +198 -0
- package/src/orchestrator/operation-plan.refresh.test.md +199 -0
- package/src/orchestrator/operation-plan.refresh.test.ts +367 -0
- package/src/orchestrator/operation-plan.ts +709 -0
- package/src/orchestrator/operation-plan.update.test.md +485 -0
- package/src/orchestrator/operation-plan.update.test.ts +1066 -0
- package/src/orchestrator/operation-workset.ts +233 -578
- package/src/orchestrator/operation.ts +440 -948
- package/src/orchestrator/plan-test-builder.ts +267 -0
- package/src/project-model/abstractions.ts +118 -0
- package/src/project-model/backends/codebase.ts +365 -0
- package/src/project-model/backends/database.ts +440 -0
- package/src/project-model/errors.ts +81 -0
- package/src/project-model/factory.ts +24 -0
- package/src/project-model/index.ts +4 -0
- package/src/project-model/utils.test.ts +544 -0
- package/src/project-model/utils.ts +242 -0
- package/src/pubsub/abstractions.ts +10 -1
- package/src/pubsub/factory.ts +4 -4
- package/src/pubsub/index.ts +1 -0
- package/src/pubsub/manager.ts +29 -13
- package/src/pubsub/memory.ts +31 -0
- package/src/runner/abstractions.ts +40 -41
- package/src/runner/artifact-env.ts +19 -8
- package/src/runner/factory.ts +6 -6
- package/src/runner/force-abort.ts +3 -6
- package/src/runner/local.ts +74 -67
- package/src/runner/pulumi.ts +23 -63
- package/src/services.ts +181 -123
- package/src/shared/models/backend/index.ts +3 -1
- package/src/shared/models/backend/library.ts +9 -1
- package/src/shared/models/backend/project.ts +43 -42
- package/src/shared/models/backend/pulumi.ts +14 -0
- package/src/shared/models/backend/unlock-method.ts +1 -1
- package/src/shared/models/backend/well-known.ts +58 -0
- package/src/shared/models/base.ts +40 -26
- package/src/shared/models/errors.ts +82 -1
- package/src/shared/models/index.ts +3 -2
- package/src/shared/models/prisma.ts +36 -0
- package/src/shared/models/project/api-key.ts +37 -59
- package/src/shared/models/project/artifact.ts +16 -76
- package/src/shared/models/project/custom-status.ts +12 -0
- package/src/shared/models/project/index.ts +8 -7
- package/src/shared/models/project/lock.ts +10 -78
- package/src/shared/models/project/model.ts +19 -1
- package/src/shared/models/project/operation.ts +235 -99
- package/src/shared/models/project/page.ts +37 -48
- package/src/shared/models/project/secret.ts +29 -89
- package/src/shared/models/project/service-account.ts +12 -17
- package/src/shared/models/project/state.ts +100 -407
- package/src/shared/models/project/terminal.ts +75 -88
- package/src/shared/models/project/trigger.ts +13 -49
- package/src/shared/models/project/unlock-method.ts +20 -26
- package/src/shared/models/project/worker.ts +89 -90
- package/src/shared/resolvers/graph-resolver.ts +21 -0
- package/src/shared/resolvers/index.ts +1 -1
- package/src/shared/resolvers/input-hash.ts +24 -14
- package/src/shared/resolvers/input.ts +9 -2
- package/src/shared/resolvers/registry.ts +5 -4
- package/src/shared/resolvers/state.ts +12 -1
- package/src/shared/resolvers/validation.ts +7 -3
- package/src/shared/utils/index.ts +1 -2
- package/src/shared/utils/promise-tracker.ts +30 -3
- package/src/terminal/abstractions.ts +1 -1
- package/src/terminal/docker.ts +3 -3
- package/src/terminal/manager.ts +102 -118
- package/src/test-utils/database.ts +119 -0
- package/src/test-utils/index.ts +2 -0
- package/src/test-utils/services.ts +134 -0
- package/src/unlock/abstractions.ts +5 -23
- package/src/unlock/memory.ts +9 -14
- package/src/worker/abstractions.ts +7 -4
- package/src/worker/docker.ts +14 -19
- package/src/worker/manager.ts +366 -97
- package/dist/chunk-NAAIDR4U.js +0 -8499
- package/dist/chunk-NAAIDR4U.js.map +0 -1
- package/dist/chunk-Y7DXREVO.js +0 -1745
- package/dist/chunk-Y7DXREVO.js.map +0 -1
- package/dist/magic-string.es-5ABAC4JN.js +0 -1292
- package/dist/magic-string.es-5ABAC4JN.js.map +0 -1
- package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +0 -356
- package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +0 -274
- package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +0 -223
- package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +0 -147
- package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +0 -280
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +0 -360
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +0 -215
- package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +0 -427
- package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +0 -217
- package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +0 -132
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +0 -454
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +0 -426
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +0 -372
- package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +0 -383
- package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +0 -245
- package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +0 -174
- package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +0 -432
- package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +0 -220
- package/src/business/backend-unlock.ts +0 -10
- package/src/common/clock.ts +0 -18
- package/src/common/performance.ts +0 -44
- package/src/common/random.ts +0 -68
- package/src/common/test/index.ts +0 -2
- package/src/common/test/render.ts +0 -98
- package/src/common/test/tracer.ts +0 -359
- package/src/hotstate/abstractions.ts +0 -48
- package/src/hotstate/factory.ts +0 -17
- package/src/hotstate/index.ts +0 -3
- package/src/hotstate/manager.ts +0 -192
- package/src/hotstate/memory.ts +0 -100
- package/src/hotstate/validation.ts +0 -100
- package/src/lock/test.ts +0 -108
- package/src/project/abstractions.ts +0 -78
- package/src/project/evaluation.ts +0 -248
- package/src/project/factory.ts +0 -11
- package/src/project/index.ts +0 -3
- package/src/project/local.ts +0 -417
- package/src/pubsub/local.ts +0 -36
- package/src/pubsub/validation.ts +0 -33
- package/src/shared/utils/args.ts +0 -25
- package/src/state/abstractions.ts +0 -289
- package/src/state/encryption.ts +0 -98
- package/src/state/factory.ts +0 -20
- package/src/state/index.ts +0 -7
- package/src/state/local/backend.ts +0 -106
- package/src/state/local/collection.ts +0 -361
- package/src/state/local/index.ts +0 -2
- package/src/state/manager.ts +0 -890
- package/src/state/memory/backend.ts +0 -70
- package/src/state/memory/collection.ts +0 -270
- package/src/state/memory/index.ts +0 -2
- package/src/state/repository/index.ts +0 -2
- package/src/state/repository/repository.index.ts +0 -193
- package/src/state/repository/repository.ts +0 -507
- package/src/state/test.ts +0 -457
- /package/src/{state → database/local}/keyring.ts +0 -0
|
@@ -1,25 +1,38 @@
|
|
|
1
|
-
import type { StateBatch, StateManager } from "../state"
|
|
2
1
|
import type { Logger } from "pino"
|
|
3
|
-
import type {
|
|
2
|
+
import type { DatabaseManager } from "../database"
|
|
4
3
|
import type { PubSubManager } from "../pubsub"
|
|
5
|
-
import type { RandomProvider } from "../common"
|
|
6
4
|
import type { ProjectUnlockBackend } from "../unlock"
|
|
7
5
|
import { randomBytes } from "node:crypto"
|
|
8
6
|
import { armor, Decrypter, Encrypter } from "age-encryption"
|
|
9
|
-
import {
|
|
7
|
+
import { z } from "zod"
|
|
8
|
+
import { createProjectLogger } from "../common"
|
|
9
|
+
import {
|
|
10
|
+
CannotDeleteLastUnlockMethodError,
|
|
11
|
+
ProjectNotFoundError,
|
|
12
|
+
type ProjectUnlockState,
|
|
13
|
+
type ProjectUnlockSuite,
|
|
14
|
+
type UnlockMethodInput,
|
|
15
|
+
} from "../shared"
|
|
10
16
|
|
|
11
17
|
type UnlockTask = {
|
|
12
18
|
name: string
|
|
13
19
|
handler: (projectId: string) => Promise<void> | void
|
|
14
20
|
}
|
|
15
21
|
|
|
22
|
+
export const projectUnlockServiceConfig = z.object({
|
|
23
|
+
HIGHSTATE_ENCRYPTION_ENABLED: z.stringbool().default(true),
|
|
24
|
+
HIGHSTATE_DEV_AUTO_UNLOCK_PROJECT_IDS: z
|
|
25
|
+
.string()
|
|
26
|
+
.transform(val => val?.split(",") ?? [])
|
|
27
|
+
.default([]),
|
|
28
|
+
})
|
|
29
|
+
|
|
16
30
|
export class ProjectUnlockService {
|
|
17
31
|
constructor(
|
|
18
|
-
private readonly
|
|
19
|
-
private readonly hotStateManager: HotStateManager,
|
|
32
|
+
private readonly database: DatabaseManager,
|
|
20
33
|
private readonly pubsubManager: PubSubManager,
|
|
21
34
|
private readonly projectUnlockBackend: ProjectUnlockBackend,
|
|
22
|
-
private readonly
|
|
35
|
+
private readonly config: z.infer<typeof projectUnlockServiceConfig>,
|
|
23
36
|
private readonly logger: Logger,
|
|
24
37
|
) {}
|
|
25
38
|
|
|
@@ -39,51 +52,54 @@ export class ProjectUnlockService {
|
|
|
39
52
|
return { type: "unlocked" }
|
|
40
53
|
}
|
|
41
54
|
|
|
42
|
-
const
|
|
55
|
+
const project = await this.database.backend.project.findUnique({
|
|
56
|
+
where: { id: projectId },
|
|
57
|
+
select: { unlockSuite: true },
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
if (!project) {
|
|
61
|
+
throw new ProjectNotFoundError(projectId)
|
|
62
|
+
}
|
|
63
|
+
|
|
43
64
|
return {
|
|
44
65
|
type: "locked",
|
|
45
|
-
unlockSuite,
|
|
66
|
+
unlockSuite: project.unlockSuite,
|
|
46
67
|
}
|
|
47
68
|
}
|
|
48
69
|
|
|
49
70
|
/**
|
|
50
|
-
* Sets up the project
|
|
71
|
+
* Sets up the project database by creating a master key and unlock suite with the provided unlock method.
|
|
72
|
+
*
|
|
73
|
+
* Creates databases, configures encryption and persists the unlock method inside the project database.
|
|
74
|
+
*
|
|
75
|
+
* Then returns the encrypted master key and the unlock suite for further persisting in the backend database.
|
|
51
76
|
*
|
|
52
77
|
* @param projectId The ID of the project to create the state for.
|
|
53
78
|
* @param unlockMethod The unlock method to use to encrypt the master key. Should be provided by the frontend.
|
|
54
79
|
*/
|
|
55
|
-
async
|
|
80
|
+
async setupProjectDatabase(
|
|
56
81
|
projectId: string,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
): Promise<void> {
|
|
60
|
-
const unlockMethod: UnlockMethod = {
|
|
61
|
-
id: this.random.uuidv7(),
|
|
62
|
-
...inputUnlockMethod,
|
|
63
|
-
}
|
|
64
|
-
|
|
82
|
+
unlockMethodInput: UnlockMethodInput,
|
|
83
|
+
): Promise<[encryptedMasterKey: string, unlockSuite: ProjectUnlockSuite]> {
|
|
65
84
|
// generate a new master key for the project
|
|
66
85
|
const masterKey = randomBytes(32)
|
|
67
86
|
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
await this.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await this.stateManager
|
|
85
|
-
.getUnlockMethodRepository(projectId)
|
|
86
|
-
.put(unlockMethod.id, unlockMethod, batch)
|
|
87
|
+
// set the master key to setup the database encryption
|
|
88
|
+
await this.projectUnlockBackend.unlockProject(projectId, masterKey)
|
|
89
|
+
|
|
90
|
+
const encryptedMasterKey = await this.encryptProjectMasterKey(projectId, [unlockMethodInput])
|
|
91
|
+
|
|
92
|
+
const database = await this.database.setupDatabase(projectId)
|
|
93
|
+
|
|
94
|
+
// persist unlock method (now we can do it since the database is set up and unlocked)
|
|
95
|
+
await database.unlockMethod.create({ data: unlockMethodInput })
|
|
96
|
+
|
|
97
|
+
const unlockSuite: ProjectUnlockSuite = {
|
|
98
|
+
encryptedIdentities: [unlockMethodInput.encryptedIdentity],
|
|
99
|
+
hasPasskey: unlockMethodInput.type === "passkey",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return [encryptedMasterKey, unlockSuite]
|
|
87
103
|
}
|
|
88
104
|
|
|
89
105
|
/**
|
|
@@ -103,12 +119,24 @@ export class ProjectUnlockService {
|
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
// load the encrypted master key for the project
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
const project = await this.database.backend.project.findUnique({
|
|
123
|
+
where: { id: projectId },
|
|
124
|
+
select: { encryptedMasterKey: true },
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
if (!project) {
|
|
128
|
+
throw new ProjectNotFoundError(projectId)
|
|
109
129
|
}
|
|
110
130
|
|
|
111
|
-
|
|
131
|
+
if (!this.config.HIGHSTATE_ENCRYPTION_ENABLED) {
|
|
132
|
+
// no cryptography, just unlock with an empty master key
|
|
133
|
+
await this.projectUnlockBackend.unlockProject(projectId, Buffer.alloc(0))
|
|
134
|
+
await this.pubsubManager.publish(["project-unlock-state", projectId], { type: "unlocked" })
|
|
135
|
+
await this.runUnlockTasks(projectId)
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const encryptedMasterKey = armor.decode(project.encryptedMasterKey)
|
|
112
140
|
|
|
113
141
|
const decrypter = new Decrypter()
|
|
114
142
|
decrypter.addIdentity(decryptedIdentity)
|
|
@@ -116,30 +144,8 @@ export class ProjectUnlockService {
|
|
|
116
144
|
// decrypt the master key using the provided identity
|
|
117
145
|
const masterKey = await decrypter.decrypt(encryptedMasterKey)
|
|
118
146
|
|
|
119
|
-
// fetch the namespace for the project
|
|
120
|
-
const namespace = await this.stateManager.getProjectNamespaceRepository().get(projectId)
|
|
121
|
-
if (!namespace) {
|
|
122
|
-
throw new Error(`Project ${projectId} does not have a namespace set.`)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
147
|
// unlock the project in the backend
|
|
126
|
-
await this.projectUnlockBackend.unlockProject(
|
|
127
|
-
projectId,
|
|
128
|
-
Buffer.from(masterKey).toString("base64"),
|
|
129
|
-
namespace,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
// load instance states to the hot state
|
|
133
|
-
// TODO: this should be done by something else, ideally lazy-loaded when needed
|
|
134
|
-
const instanceStates = await this.stateManager
|
|
135
|
-
.getInstanceStateRepository(projectId)
|
|
136
|
-
.getAllItems()
|
|
137
|
-
|
|
138
|
-
await this.hotStateManager.hmset(
|
|
139
|
-
["instance-states", projectId],
|
|
140
|
-
instanceStates.map(state => [state.id, state]),
|
|
141
|
-
)
|
|
142
|
-
|
|
148
|
+
await this.projectUnlockBackend.unlockProject(projectId, Buffer.from(masterKey))
|
|
143
149
|
await this.pubsubManager.publish(["project-unlock-state", projectId], { type: "unlocked" })
|
|
144
150
|
|
|
145
151
|
// run unlock tasks
|
|
@@ -161,24 +167,37 @@ export class ProjectUnlockService {
|
|
|
161
167
|
* The project must be unlocked.
|
|
162
168
|
*
|
|
163
169
|
* @param projectId The ID of the project to add the unlock method to.
|
|
164
|
-
* @param
|
|
170
|
+
* @param inputUnlockMethod The unlock method to add. Should be provided by the frontend.
|
|
165
171
|
*/
|
|
166
|
-
async addProjectUnlockMethod(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
await this.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
172
|
+
async addProjectUnlockMethod(
|
|
173
|
+
projectId: string,
|
|
174
|
+
inputUnlockMethod: UnlockMethodInput,
|
|
175
|
+
): Promise<void> {
|
|
176
|
+
const database = await this.database.forProject(projectId)
|
|
177
|
+
|
|
178
|
+
await database.$transaction(async tx => {
|
|
179
|
+
// 1. fetch all unlock method recipients for the project
|
|
180
|
+
const unlockMethods = await tx.unlockMethod.findMany({
|
|
181
|
+
select: { type: true, recipient: true, encryptedIdentity: true },
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const allUnlockMethods = [...unlockMethods, inputUnlockMethod]
|
|
185
|
+
|
|
186
|
+
// 2. encrypt the project data for all recipients + the new recipient
|
|
187
|
+
const encryptedMasterKey = await this.encryptProjectMasterKey(projectId, allUnlockMethods)
|
|
188
|
+
|
|
189
|
+
// 3. persist the new unlock method
|
|
190
|
+
await tx.unlockMethod.create({ data: inputUnlockMethod })
|
|
191
|
+
|
|
192
|
+
// 4. update the project with the new master key and unlock suite
|
|
193
|
+
await this.database.backend.project.update({
|
|
194
|
+
where: { id: projectId },
|
|
195
|
+
data: {
|
|
196
|
+
encryptedMasterKey,
|
|
197
|
+
unlockSuite: ProjectUnlockService.createUnlockSuite(allUnlockMethods),
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
})
|
|
182
201
|
}
|
|
183
202
|
|
|
184
203
|
/**
|
|
@@ -189,25 +208,34 @@ export class ProjectUnlockService {
|
|
|
189
208
|
* @param unlockMethodId The ID of the unlock method to remove.
|
|
190
209
|
*/
|
|
191
210
|
async removeProjectUnlockMethod(projectId: string, unlockMethodId: string): Promise<void> {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
// get all existing unlock methods
|
|
195
|
-
let existingMethods = await this.stateManager.getUnlockMethodRepository(projectId).getAllItems()
|
|
196
|
-
|
|
197
|
-
// do not allow removing the last unlock method under any circumstances
|
|
198
|
-
if (existingMethods.length === 1) {
|
|
199
|
-
throw new Error("Rejected removing the last unlock method!")
|
|
200
|
-
}
|
|
211
|
+
const database = await this.database.forProject(projectId)
|
|
201
212
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
213
|
+
await database.$transaction(async tx => {
|
|
214
|
+
// 1. fetch all unlock methods except the one to remove
|
|
215
|
+
const unlockMethods = await tx.unlockMethod.findMany({
|
|
216
|
+
where: { id: { not: unlockMethodId } },
|
|
217
|
+
select: { type: true, recipient: true, encryptedIdentity: true },
|
|
218
|
+
})
|
|
205
219
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
220
|
+
if (unlockMethods.length === 0) {
|
|
221
|
+
throw new CannotDeleteLastUnlockMethodError(projectId)
|
|
222
|
+
}
|
|
209
223
|
|
|
210
|
-
|
|
224
|
+
// 2. encrypt the project data for remaining recipients
|
|
225
|
+
const encryptedMasterKey = await this.encryptProjectMasterKey(projectId, unlockMethods)
|
|
226
|
+
|
|
227
|
+
// 3. delete the unlock method
|
|
228
|
+
await tx.unlockMethod.delete({ where: { id: unlockMethodId } })
|
|
229
|
+
|
|
230
|
+
// 4. update the project with the new master key and unlock suite
|
|
231
|
+
await this.database.backend.project.update({
|
|
232
|
+
where: { id: projectId },
|
|
233
|
+
data: {
|
|
234
|
+
encryptedMasterKey,
|
|
235
|
+
unlockSuite: ProjectUnlockService.createUnlockSuite(unlockMethods),
|
|
236
|
+
},
|
|
237
|
+
})
|
|
238
|
+
})
|
|
211
239
|
}
|
|
212
240
|
|
|
213
241
|
/**
|
|
@@ -221,40 +249,54 @@ export class ProjectUnlockService {
|
|
|
221
249
|
this.unlockTasks.push({ name, handler })
|
|
222
250
|
}
|
|
223
251
|
|
|
224
|
-
private async
|
|
252
|
+
private async encryptProjectMasterKey(
|
|
225
253
|
projectId: string,
|
|
226
|
-
unlockMethods:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
encryptedIdentities: unlockMethods.map(method => method.encryptedIdentity),
|
|
234
|
-
hasPasskey: unlockMethods.some(method => method.type === "passkey"),
|
|
235
|
-
},
|
|
236
|
-
batch,
|
|
237
|
-
)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
private async updateEncryptedMasterKey(
|
|
241
|
-
projectId: string,
|
|
242
|
-
unlockMethods: UnlockMethod[],
|
|
243
|
-
batch: StateBatch,
|
|
244
|
-
masterKey?: Uint8Array,
|
|
245
|
-
): Promise<void> {
|
|
246
|
-
masterKey ??= await this.stateManager.getProjectMasterKey(projectId)
|
|
254
|
+
unlockMethods: { recipient: string }[],
|
|
255
|
+
): Promise<string> {
|
|
256
|
+
const masterKey = await this.database.getProjectMasterKey(projectId)
|
|
257
|
+
if (!masterKey) {
|
|
258
|
+
// окак
|
|
259
|
+
return "encryption disabled"
|
|
260
|
+
}
|
|
247
261
|
|
|
262
|
+
// encrypt the master key for all unlock methods
|
|
248
263
|
const encrypter = new Encrypter()
|
|
249
|
-
for (const
|
|
250
|
-
encrypter.addRecipient(
|
|
264
|
+
for (const unlockMethod of unlockMethods) {
|
|
265
|
+
encrypter.addRecipient(unlockMethod.recipient)
|
|
251
266
|
}
|
|
252
267
|
|
|
253
|
-
// encrypt the master key for all unlock methods
|
|
254
268
|
const encryptedMasterKey = await encrypter.encrypt(masterKey)
|
|
255
|
-
|
|
256
|
-
// set the encrypted master key in the backend
|
|
257
269
|
const armoredMasterKey = armor.encode(encryptedMasterKey)
|
|
258
|
-
|
|
270
|
+
|
|
271
|
+
return armoredMasterKey
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Auto-unlocks the projects for the development environment.
|
|
276
|
+
*/
|
|
277
|
+
async autoUnlockProjects(): Promise<void> {
|
|
278
|
+
// just mark the projects as unlocked with an empty master key and run unlock tasks
|
|
279
|
+
for (const projectId of this.config.HIGHSTATE_DEV_AUTO_UNLOCK_PROJECT_IDS) {
|
|
280
|
+
const logger = createProjectLogger(this.logger, projectId)
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
logger.info("auto-unlocking project (dev mode)")
|
|
284
|
+
|
|
285
|
+
await this.projectUnlockBackend.unlockProject(projectId, Buffer.alloc(0))
|
|
286
|
+
await this.pubsubManager.publish(["project-unlock-state", projectId], { type: "unlocked" })
|
|
287
|
+
await this.runUnlockTasks(projectId)
|
|
288
|
+
} catch (error) {
|
|
289
|
+
logger.error({ error }, "failed to auto-unlock project")
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private static createUnlockSuite(
|
|
295
|
+
unlockMethods: { type: string; encryptedIdentity: string }[],
|
|
296
|
+
): ProjectUnlockSuite {
|
|
297
|
+
return {
|
|
298
|
+
encryptedIdentities: unlockMethods.map(method => method.encryptedIdentity),
|
|
299
|
+
hasPasskey: unlockMethods.some(method => method.type === "passkey"),
|
|
300
|
+
}
|
|
259
301
|
}
|
|
260
302
|
}
|