borgmcp 2.10.2 → 2.12.1
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/README.md +7 -3
- package/dist/assimilate-cmd.d.ts +5 -2
- package/dist/assimilate-cmd.d.ts.map +1 -1
- package/dist/assimilate-cmd.js +3 -1
- package/dist/assimilate-cmd.js.map +1 -1
- package/dist/assimilate-deps.d.ts.map +1 -1
- package/dist/assimilate-deps.js +2 -2
- package/dist/assimilate-deps.js.map +1 -1
- package/dist/claude.js +3 -3
- package/dist/claude.js.map +1 -1
- package/dist/cli-help.js +3 -3
- package/dist/cli-help.js.map +1 -1
- package/dist/cli-platform.d.ts +1 -0
- package/dist/cli-platform.d.ts.map +1 -1
- package/dist/cli-platform.js +10 -1
- package/dist/cli-platform.js.map +1 -1
- package/dist/cli-tool-approval.d.ts +3 -1
- package/dist/cli-tool-approval.d.ts.map +1 -1
- package/dist/cli-tool-approval.js +8 -14
- package/dist/cli-tool-approval.js.map +1 -1
- package/dist/config.d.ts +34 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +487 -105
- package/dist/config.js.map +1 -1
- package/dist/enrollment-lock.d.ts +10 -0
- package/dist/enrollment-lock.d.ts.map +1 -0
- package/dist/enrollment-lock.js +49 -0
- package/dist/enrollment-lock.js.map +1 -0
- package/dist/enrollment-types.d.ts +47 -0
- package/dist/enrollment-types.d.ts.map +1 -0
- package/dist/enrollment-types.js +2 -0
- package/dist/enrollment-types.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/invitation-artifact.d.ts +3 -1
- package/dist/invitation-artifact.d.ts.map +1 -1
- package/dist/invitation-artifact.js +3 -1
- package/dist/invitation-artifact.js.map +1 -1
- package/dist/parse-assimilate-args.d.ts +1 -1
- package/dist/parse-assimilate-args.d.ts.map +1 -1
- package/dist/parse-assimilate-args.js +5 -2
- package/dist/parse-assimilate-args.js.map +1 -1
- package/dist/recover-enrollment-cmd.d.ts.map +1 -1
- package/dist/recover-enrollment-cmd.js +34 -15
- package/dist/recover-enrollment-cmd.js.map +1 -1
- package/dist/remote-client.d.ts +3 -2
- package/dist/remote-client.d.ts.map +1 -1
- package/dist/remote-client.js +32 -11
- package/dist/remote-client.js.map +1 -1
- package/dist/server-errors.d.ts +4 -0
- package/dist/server-errors.d.ts.map +1 -1
- package/dist/server-errors.js +8 -0
- package/dist/server-errors.js.map +1 -1
- package/dist/server-handshake.d.ts +11 -3
- package/dist/server-handshake.d.ts.map +1 -1
- package/dist/server-handshake.js +103 -45
- package/dist/server-handshake.js.map +1 -1
- package/dist/server-trust.d.ts +14 -1
- package/dist/server-trust.d.ts.map +1 -1
- package/dist/server-trust.js +363 -66
- package/dist/server-trust.js.map +1 -1
- package/dist/tool-manifest.d.ts.map +1 -1
- package/dist/tool-manifest.js +4 -10
- package/dist/tool-manifest.js.map +1 -1
- package/docs/EXTRACTION_PROVENANCE.md +5 -5
- package/docs/LOCAL_SERVER.md +1 -1
- package/docs/RELEASING.md +10 -5
- package/package.json +3 -3
- package/src/assimilate-cmd.ts +10 -3
- package/src/assimilate-deps.ts +3 -2
- package/src/claude.ts +4 -3
- package/src/cli-help.ts +3 -3
- package/src/cli-platform.ts +16 -2
- package/src/cli-tool-approval.ts +9 -16
- package/src/config.ts +544 -101
- package/src/enrollment-lock.ts +53 -0
- package/src/enrollment-types.ts +51 -0
- package/src/index.ts +1 -1
- package/src/invitation-artifact.ts +7 -1
- package/src/parse-assimilate-args.ts +4 -2
- package/src/recover-enrollment-cmd.ts +39 -15
- package/src/remote-client.ts +36 -10
- package/src/server-errors.ts +7 -0
- package/src/server-handshake.ts +130 -52
- package/src/server-trust.ts +392 -66
- package/src/tool-manifest.ts +4 -10
package/src/server-handshake.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
type ServerCapability,
|
|
33
33
|
} from 'borgmcp-shared/protocol';
|
|
34
34
|
import { createHash, randomUUID } from 'node:crypto';
|
|
35
|
+
import { withEnrollmentOriginLock } from './enrollment-lock.js';
|
|
35
36
|
import {
|
|
36
37
|
activatePendingServerEnrollment,
|
|
37
38
|
clearPendingServerCubeCreation,
|
|
@@ -40,9 +41,12 @@ import {
|
|
|
40
41
|
getServerCredentialRecord,
|
|
41
42
|
hasServerCredentialForOrigin,
|
|
42
43
|
getPendingServerEnrollment,
|
|
44
|
+
findPendingServerEnrollment,
|
|
43
45
|
getOrCreatePendingServerCubeCreation,
|
|
44
46
|
getOrCreatePendingServerEnrollment,
|
|
47
|
+
createPendingServerEnrollmentWithReplacementConsent,
|
|
45
48
|
type PendingServerCubeCreationRecord,
|
|
49
|
+
type PendingServerEnrollmentRecord,
|
|
46
50
|
} from './config.js';
|
|
47
51
|
import {
|
|
48
52
|
activateAndBindSeat,
|
|
@@ -69,6 +73,7 @@ import { readBoundedResponseBody } from './server-response.js';
|
|
|
69
73
|
import {
|
|
70
74
|
loadBorgServerTrust,
|
|
71
75
|
loadBorgServerTrustFromPresentedChain,
|
|
76
|
+
loadStagedBorgServerTrust,
|
|
72
77
|
type BorgServerTrust,
|
|
73
78
|
type StagedBorgServerTrust,
|
|
74
79
|
} from './server-trust.js';
|
|
@@ -79,6 +84,7 @@ import {
|
|
|
79
84
|
InvitationArtifactTrustError,
|
|
80
85
|
decodeAndVerifyInvitationArtifact,
|
|
81
86
|
} from './invitation-artifact.js';
|
|
87
|
+
import type { EnrollmentArtifactBinding } from './enrollment-types.js';
|
|
82
88
|
|
|
83
89
|
const HANDSHAKE_BODY_LIMIT = 64 * 1024;
|
|
84
90
|
const HANDSHAKE_TIMEOUT_MS = 5_000;
|
|
@@ -462,6 +468,7 @@ export async function enrollBorgServer(
|
|
|
462
468
|
deps: {
|
|
463
469
|
fetchImpl?: FetchLike;
|
|
464
470
|
prepareEnrollment?: typeof getOrCreatePendingServerEnrollment;
|
|
471
|
+
prepareReplacementEnrollment?: typeof createPendingServerEnrollmentWithReplacementConsent;
|
|
465
472
|
activateEnrollment?: typeof activatePendingServerEnrollment;
|
|
466
473
|
clearPendingEnrollment?: typeof clearPendingServerEnrollment;
|
|
467
474
|
loadCredentialRecord?: typeof getServerCredentialRecord;
|
|
@@ -469,8 +476,10 @@ export async function enrollBorgServer(
|
|
|
469
476
|
confirmReplacement?: () => Promise<boolean>;
|
|
470
477
|
clientName?: string;
|
|
471
478
|
expectedAuthority?: InvitationArtifact['authority'];
|
|
472
|
-
|
|
479
|
+
artifactBinding?: EnrollmentArtifactBinding;
|
|
480
|
+
commitTrust?: StagedBorgServerTrust['commitTrust'];
|
|
473
481
|
discardTrust?: () => Promise<void>;
|
|
482
|
+
resumePending?: PendingServerEnrollmentRecord;
|
|
474
483
|
} = {},
|
|
475
484
|
): Promise<NewServerEnrollment> {
|
|
476
485
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
@@ -485,15 +494,13 @@ export async function enrollBorgServer(
|
|
|
485
494
|
throw error;
|
|
486
495
|
}
|
|
487
496
|
|
|
488
|
-
const existingCredential =
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const existingOriginCredential = existingCredential !== null || await (
|
|
497
|
+
const existingCredential = deps.resumePending ? null : await (
|
|
498
|
+
deps.loadCredentialRecord ?? getServerCredentialRecord
|
|
499
|
+
)(origin, trustIdentity);
|
|
500
|
+
const existingOriginCredential = deps.resumePending ? false : existingCredential !== null || await (
|
|
493
501
|
deps.hasCredentialForOrigin ?? hasServerCredentialForOrigin
|
|
494
502
|
)(origin);
|
|
495
503
|
let replacementConfirmed = false;
|
|
496
|
-
let replacementCapability: string | undefined;
|
|
497
504
|
if (existingOriginCredential) {
|
|
498
505
|
const confirmed = deps.confirmReplacement !== undefined
|
|
499
506
|
? await deps.confirmReplacement()
|
|
@@ -506,16 +513,33 @@ export async function enrollBorgServer(
|
|
|
506
513
|
);
|
|
507
514
|
}
|
|
508
515
|
replacementConfirmed = true;
|
|
509
|
-
replacementCapability = randomUUID();
|
|
510
516
|
}
|
|
511
517
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
518
|
+
if (replacementConfirmed && deps.artifactBinding === undefined) {
|
|
519
|
+
await deps.discardTrust?.();
|
|
520
|
+
throw new BorgServerError(
|
|
521
|
+
'LOCAL_CREDENTIAL_EXISTS',
|
|
522
|
+
'replacement requires a current verified enrollment invitation',
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
let pending = deps.resumePending;
|
|
526
|
+
if (!pending) {
|
|
527
|
+
const common = {
|
|
528
|
+
origin,
|
|
529
|
+
trustIdentity,
|
|
530
|
+
invitation,
|
|
531
|
+
...(deps.clientName ? { clientName: deps.clientName } : {}),
|
|
532
|
+
};
|
|
533
|
+
pending = replacementConfirmed
|
|
534
|
+
? await (deps.prepareReplacementEnrollment ?? createPendingServerEnrollmentWithReplacementConsent)({
|
|
535
|
+
...common,
|
|
536
|
+
artifactBinding: deps.artifactBinding!,
|
|
537
|
+
})
|
|
538
|
+
: await (deps.prepareEnrollment ?? getOrCreatePendingServerEnrollment)({
|
|
539
|
+
...common,
|
|
540
|
+
...(deps.artifactBinding === undefined ? {} : { artifactBinding: deps.artifactBinding }),
|
|
541
|
+
});
|
|
542
|
+
}
|
|
519
543
|
const request = decodeEnrollmentExchangeRequest({
|
|
520
544
|
invitation: pending.invitation,
|
|
521
545
|
retry_key: pending.retryKey,
|
|
@@ -545,7 +569,6 @@ export async function enrollBorgServer(
|
|
|
545
569
|
}
|
|
546
570
|
}
|
|
547
571
|
if (!response) {
|
|
548
|
-
await deps.discardTrust?.();
|
|
549
572
|
throw lastTransportError;
|
|
550
573
|
}
|
|
551
574
|
|
|
@@ -562,7 +585,6 @@ export async function enrollBorgServer(
|
|
|
562
585
|
);
|
|
563
586
|
}
|
|
564
587
|
if (response.status !== 201) {
|
|
565
|
-
await deps.discardTrust?.();
|
|
566
588
|
throw new Error(`Borg server enrollment failed (HTTP ${response.status})`);
|
|
567
589
|
}
|
|
568
590
|
let decoded: ReturnType<typeof decodeEnrollmentExchangeResponseEnvelope>;
|
|
@@ -571,7 +593,6 @@ export async function enrollBorgServer(
|
|
|
571
593
|
JSON.parse(await readHandshakeBodyWithTimeout(response)),
|
|
572
594
|
);
|
|
573
595
|
} catch (error) {
|
|
574
|
-
await deps.discardTrust?.();
|
|
575
596
|
if (error instanceof Error && error.message.includes('response limit')) throw error;
|
|
576
597
|
throw new Error('Borg server returned an invalid enrollment envelope');
|
|
577
598
|
}
|
|
@@ -589,16 +610,18 @@ export async function enrollBorgServer(
|
|
|
589
610
|
}
|
|
590
611
|
}
|
|
591
612
|
|
|
592
|
-
const activate = (
|
|
613
|
+
const activate = (context?: { generationId: string; previousPointer: import('./enrollment-types.js').EnrollmentTrustPointer | null }) =>
|
|
614
|
+
(deps.activateEnrollment ?? activatePendingServerEnrollment)({
|
|
593
615
|
origin,
|
|
594
616
|
trustIdentity,
|
|
595
617
|
retryKey: pending.retryKey,
|
|
596
618
|
credential: pending.credential,
|
|
597
619
|
clientId: decoded.payload.client_id,
|
|
598
620
|
serverCapabilities: decoded.payload.server_capabilities,
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
621
|
+
...(context === undefined ? {} : context),
|
|
622
|
+
...(pending.replacementCapability === undefined
|
|
623
|
+
? {}
|
|
624
|
+
: { replacementCapabilityToken: pending.replacementCapability.token }),
|
|
602
625
|
});
|
|
603
626
|
if (deps.commitTrust) await deps.commitTrust(activate);
|
|
604
627
|
else await activate();
|
|
@@ -621,6 +644,8 @@ export async function resumeBorgServerEnrollment(
|
|
|
621
644
|
activateEnrollment?: typeof activatePendingServerEnrollment;
|
|
622
645
|
clearPendingEnrollment?: typeof clearPendingServerEnrollment;
|
|
623
646
|
onPending?: () => void;
|
|
647
|
+
commitTrust?: StagedBorgServerTrust['commitTrust'];
|
|
648
|
+
discardTrust?: () => Promise<void>;
|
|
624
649
|
} = {},
|
|
625
650
|
): Promise<NewServerEnrollment | null> {
|
|
626
651
|
const pending = await (deps.loadPendingEnrollment ?? getPendingServerEnrollment)(
|
|
@@ -628,10 +653,21 @@ export async function resumeBorgServerEnrollment(
|
|
|
628
653
|
trustIdentity,
|
|
629
654
|
);
|
|
630
655
|
if (!pending) return null;
|
|
656
|
+
if (pending.artifactBinding) {
|
|
657
|
+
const verified = decodeAndVerifyInvitationArtifact(pending.invitation);
|
|
658
|
+
const digest = createHash('sha256').update(pending.invitation).digest('hex');
|
|
659
|
+
if (
|
|
660
|
+
digest !== pending.artifactBinding.artifactDigest ||
|
|
661
|
+
verified.version !== pending.artifactBinding.artifactFormatVersion ||
|
|
662
|
+
verified.endpoint !== pending.artifactBinding.endpoint ||
|
|
663
|
+
verified.ca_spki_sha256 !== pending.artifactBinding.caSpkiSha256 ||
|
|
664
|
+
verified.authority !== pending.artifactBinding.expectedAuthority
|
|
665
|
+
) throw new InvitationArtifactTrustError();
|
|
666
|
+
}
|
|
631
667
|
deps.onPending?.();
|
|
632
668
|
return enrollBorgServer(origin, trustIdentity, pending.invitation, {
|
|
633
669
|
...(deps.fetchImpl === undefined ? {} : { fetchImpl: deps.fetchImpl }),
|
|
634
|
-
|
|
670
|
+
resumePending: pending,
|
|
635
671
|
...(deps.activateEnrollment === undefined
|
|
636
672
|
? {}
|
|
637
673
|
: { activateEnrollment: deps.activateEnrollment }),
|
|
@@ -639,6 +675,14 @@ export async function resumeBorgServerEnrollment(
|
|
|
639
675
|
? {}
|
|
640
676
|
: { clearPendingEnrollment: deps.clearPendingEnrollment }),
|
|
641
677
|
...(pending.clientName === undefined ? {} : { clientName: pending.clientName }),
|
|
678
|
+
...(pending.artifactBinding === undefined
|
|
679
|
+
? {}
|
|
680
|
+
: {
|
|
681
|
+
artifactBinding: pending.artifactBinding,
|
|
682
|
+
expectedAuthority: pending.artifactBinding.expectedAuthority,
|
|
683
|
+
}),
|
|
684
|
+
...(deps.commitTrust === undefined ? {} : { commitTrust: deps.commitTrust }),
|
|
685
|
+
...(deps.discardTrust === undefined ? {} : { discardTrust: deps.discardTrust }),
|
|
642
686
|
});
|
|
643
687
|
}
|
|
644
688
|
|
|
@@ -1037,23 +1081,25 @@ export async function resolveBorgServerAuthority(
|
|
|
1037
1081
|
loadCredentialRecord?: typeof getServerCredentialRecord;
|
|
1038
1082
|
} = {},
|
|
1039
1083
|
): Promise<ResolvedServerAuthority> {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
if (!token) {
|
|
1051
|
-
throw new BorgServerError(
|
|
1052
|
-
'NOT_ENROLLED',
|
|
1053
|
-
'no enrolled credential is stored for this Borg server identity',
|
|
1084
|
+
return withEnrollmentOriginLock(origin, async () => {
|
|
1085
|
+
const trust = await (deps.loadTrust ?? loadBorgServerTrust)(origin);
|
|
1086
|
+
const active = deps.loadCredentialRecord
|
|
1087
|
+
? await deps.loadCredentialRecord(origin, trust.identity)
|
|
1088
|
+
: deps.loadCredential
|
|
1089
|
+
? null
|
|
1090
|
+
: await getServerCredentialRecord(origin, trust.identity);
|
|
1091
|
+
const token = active?.credential ?? await (deps.loadCredential ?? getServerCredential)(
|
|
1092
|
+
origin,
|
|
1093
|
+
trust.identity,
|
|
1054
1094
|
);
|
|
1055
|
-
|
|
1056
|
-
|
|
1095
|
+
if (!token) {
|
|
1096
|
+
throw new BorgServerError(
|
|
1097
|
+
'NOT_ENROLLED',
|
|
1098
|
+
'no enrolled credential is stored for this Borg server identity',
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
return { ...trust, token };
|
|
1102
|
+
});
|
|
1057
1103
|
}
|
|
1058
1104
|
|
|
1059
1105
|
/** Load pinned trust, then prove the stored credential against /api/protocol. */
|
|
@@ -1065,13 +1111,15 @@ export async function connectLocalBorgServer(
|
|
|
1065
1111
|
loadCredentialRecord?: typeof getServerCredentialRecord;
|
|
1066
1112
|
} = {},
|
|
1067
1113
|
): Promise<EnrolledServerConnection> {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1114
|
+
return withEnrollmentOriginLock(origin, async () => {
|
|
1115
|
+
const trust = await (deps.loadTrust ?? loadBorgServerTrust)(origin);
|
|
1116
|
+
return connectEnrolledBorgServer(origin, trust.identity, {
|
|
1117
|
+
fetchImpl: trust.fetchImpl,
|
|
1118
|
+
...(deps.loadCredential === undefined ? {} : { loadCredential: deps.loadCredential }),
|
|
1119
|
+
...(deps.loadCredentialRecord === undefined
|
|
1120
|
+
? {}
|
|
1121
|
+
: { loadCredentialRecord: deps.loadCredentialRecord }),
|
|
1122
|
+
});
|
|
1075
1123
|
});
|
|
1076
1124
|
}
|
|
1077
1125
|
|
|
@@ -1116,6 +1164,7 @@ export async function enrollLocalBorgServerArtifact(
|
|
|
1116
1164
|
clientName?: string;
|
|
1117
1165
|
loadTrustFromPresentedChain?: typeof loadBorgServerTrustFromPresentedChain;
|
|
1118
1166
|
prepareEnrollment?: typeof getOrCreatePendingServerEnrollment;
|
|
1167
|
+
prepareReplacementEnrollment?: typeof createPendingServerEnrollmentWithReplacementConsent;
|
|
1119
1168
|
activateEnrollment?: typeof activatePendingServerEnrollment;
|
|
1120
1169
|
clearPendingEnrollment?: typeof clearPendingServerEnrollment;
|
|
1121
1170
|
loadCredentialRecord?: typeof getServerCredentialRecord;
|
|
@@ -1141,16 +1190,29 @@ export async function enrollLocalBorgServerArtifact(
|
|
|
1141
1190
|
if (error instanceof InvitationArtifactStorageError) throw error;
|
|
1142
1191
|
throw new InvitationArtifactTransportError();
|
|
1143
1192
|
}
|
|
1193
|
+
const artifactBinding: EnrollmentArtifactBinding = {
|
|
1194
|
+
artifactFormatVersion: verifiedArtifact.version,
|
|
1195
|
+
artifactDigest: createHash('sha256').update(opaqueArtifact).digest('hex'),
|
|
1196
|
+
endpoint: verifiedArtifact.endpoint,
|
|
1197
|
+
caSpkiSha256: verifiedArtifact.ca_spki_sha256,
|
|
1198
|
+
trustIdentity: trust.identity,
|
|
1199
|
+
expectedAuthority: verifiedArtifact.authority,
|
|
1200
|
+
stagedGenerationId: trust.generationId,
|
|
1201
|
+
};
|
|
1144
1202
|
return enrollBorgServer(verifiedArtifact.endpoint, trust.identity, opaqueArtifact, {
|
|
1145
1203
|
fetchImpl: trust.fetchImpl,
|
|
1146
1204
|
...(deps.confirmReplacement === undefined ? {} : { confirmReplacement: deps.confirmReplacement }),
|
|
1147
1205
|
...(deps.clientName === undefined ? {} : { clientName: deps.clientName }),
|
|
1148
1206
|
...(deps.prepareEnrollment === undefined ? {} : { prepareEnrollment: deps.prepareEnrollment }),
|
|
1207
|
+
...(deps.prepareReplacementEnrollment === undefined
|
|
1208
|
+
? {}
|
|
1209
|
+
: { prepareReplacementEnrollment: deps.prepareReplacementEnrollment }),
|
|
1149
1210
|
...(deps.activateEnrollment === undefined ? {} : { activateEnrollment: deps.activateEnrollment }),
|
|
1150
1211
|
...(deps.clearPendingEnrollment === undefined ? {} : { clearPendingEnrollment: deps.clearPendingEnrollment }),
|
|
1151
1212
|
...(deps.loadCredentialRecord === undefined ? {} : { loadCredentialRecord: deps.loadCredentialRecord }),
|
|
1152
1213
|
...(deps.hasCredentialForOrigin === undefined ? {} : { hasCredentialForOrigin: deps.hasCredentialForOrigin }),
|
|
1153
1214
|
expectedAuthority: verifiedArtifact.authority,
|
|
1215
|
+
artifactBinding,
|
|
1154
1216
|
commitTrust: trust.commitTrust,
|
|
1155
1217
|
discardTrust: trust.discardTrust,
|
|
1156
1218
|
});
|
|
@@ -1161,26 +1223,42 @@ export async function resumeLocalBorgServerEnrollment(
|
|
|
1161
1223
|
origin: string,
|
|
1162
1224
|
deps: {
|
|
1163
1225
|
loadTrust?: typeof loadBorgServerTrust;
|
|
1226
|
+
loadStagedTrust?: typeof loadStagedBorgServerTrust;
|
|
1164
1227
|
loadPendingEnrollment?: typeof getPendingServerEnrollment;
|
|
1165
1228
|
onPending?: () => void;
|
|
1166
1229
|
} = {},
|
|
1167
1230
|
): Promise<NewServerEnrollment | null> {
|
|
1168
|
-
|
|
1231
|
+
const discovered = await findPendingServerEnrollment();
|
|
1232
|
+
const pending = discovered?.origin === origin
|
|
1233
|
+
? await (deps.loadPendingEnrollment ?? getPendingServerEnrollment)(
|
|
1234
|
+
origin,
|
|
1235
|
+
discovered.trustIdentity,
|
|
1236
|
+
)
|
|
1237
|
+
: null;
|
|
1238
|
+
if (!pending) return null;
|
|
1239
|
+
let trust: BorgServerTrust | StagedBorgServerTrust;
|
|
1169
1240
|
try {
|
|
1170
|
-
trust =
|
|
1241
|
+
trust = pending.artifactBinding
|
|
1242
|
+
? await (deps.loadStagedTrust ?? loadStagedBorgServerTrust)(origin, pending.artifactBinding)
|
|
1243
|
+
: await (deps.loadTrust ?? loadBorgServerTrust)(origin);
|
|
1171
1244
|
} catch (error) {
|
|
1172
|
-
if (error instanceof Error && /trust files were not found|trust metadata/i.test(error.message)) return null;
|
|
1173
1245
|
throw error;
|
|
1174
1246
|
}
|
|
1175
1247
|
return resumeBorgServerEnrollment(origin, trust.identity, {
|
|
1176
1248
|
fetchImpl: trust.fetchImpl,
|
|
1177
|
-
|
|
1178
|
-
? {}
|
|
1179
|
-
: { loadPendingEnrollment: deps.loadPendingEnrollment }),
|
|
1249
|
+
loadPendingEnrollment: async () => pending,
|
|
1180
1250
|
...(deps.onPending === undefined ? {} : { onPending: deps.onPending }),
|
|
1251
|
+
...(isStagedTrust(trust) ? {
|
|
1252
|
+
commitTrust: trust.commitTrust,
|
|
1253
|
+
discardTrust: trust.discardTrust,
|
|
1254
|
+
} : {}),
|
|
1181
1255
|
});
|
|
1182
1256
|
}
|
|
1183
1257
|
|
|
1258
|
+
function isStagedTrust(trust: BorgServerTrust | StagedBorgServerTrust): trust is StagedBorgServerTrust {
|
|
1259
|
+
return 'generationId' in trust && 'commitTrust' in trust && 'discardTrust' in trust;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1184
1262
|
/** Advisory discovery that still verifies the server-owned CA. */
|
|
1185
1263
|
export async function probeLocalBorgServer(origin: string): Promise<boolean> {
|
|
1186
1264
|
try {
|