@calimero-network/mero-js 24.6.0 → 25.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account/create-context.js +17 -6
- package/dist/account/index.d.ts +1 -1
- package/dist/account/index.js +1 -1
- package/dist/account/session.d.ts +23 -1
- package/dist/account/session.js +96 -12
- package/dist/admin-api/admin-types.d.ts +2 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +89 -14
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +89 -14
- package/dist/index.mjs.map +3 -3
- package/dist/sealed/index.d.ts +2 -2
- package/dist/sealed/index.js +1 -1
- package/dist/sealed/release.d.ts +2 -4
- package/dist/sealed/release.js +5 -1
- package/dist/sealed/verify.d.ts +16 -2
- package/dist/sealed/verify.js +19 -1
- package/dist/transport/mero-client.d.ts +9 -0
- package/dist/transport/mero-client.js +13 -5
- package/package.json +1 -1
package/dist/sealed/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createAttestedSealedFetch, createSealedFetch, fetchAttestedTransportKey, transportKeyBinding, } from './sealed.js';
|
|
2
2
|
export type { AttestedSealedFetchOptions, SealedFetchOptions, VerifyTransportQuote } from './sealed.js';
|
|
3
|
-
export { createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
|
|
4
|
-
export type { DcapCollateral, DcapVerifiedReport, DcapVerify, PublishedMrtds, QuoteVerifier, QuoteVerifierOptions, TrustedMeasurements, } from './verify.js';
|
|
3
|
+
export { PRODUCTION_PROFILE, createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
|
|
4
|
+
export type { DcapCollateral, DcapVerifiedReport, DcapVerify, PublishedMrtds, QuoteVerifier, QuoteVerifierOptions, TrustedMeasurements, TrustedProfileOptions, } from './verify.js';
|
|
5
5
|
export { DEFAULT_RELEASE_MIRROR, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseSealedFetch, createSignedReleaseVerifier, fetchNodeRelease, fetchNodeReleaseVersion, nodeReleaseVersionFromImage, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
|
|
6
6
|
export type { SignedNodeRelease, SignedReleaseSealedFetchOptions, SignedReleaseVerifierOptions, TrustSignedReleaseOptions, VerifySignedNodeReleaseOptions, } from './release.js';
|
|
7
7
|
export type { SignerIdentity } from './sigstore.js';
|
package/dist/sealed/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createAttestedSealedFetch, createSealedFetch, fetchAttestedTransportKey, transportKeyBinding, } from './sealed.js';
|
|
2
|
-
export { createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
|
|
2
|
+
export { PRODUCTION_PROFILE, createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
|
|
3
3
|
export { DEFAULT_RELEASE_MIRROR, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseSealedFetch, createSignedReleaseVerifier, fetchNodeRelease, fetchNodeReleaseVersion, nodeReleaseVersionFromImage, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
|
package/dist/sealed/release.d.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* another.
|
|
28
28
|
*/
|
|
29
29
|
import { type SignerIdentity } from './sigstore.js';
|
|
30
|
-
import { type DcapVerify, type PublishedMrtds, type QuoteVerifier, type QuoteVerifierOptions } from './verify.js';
|
|
30
|
+
import { type DcapVerify, type PublishedMrtds, type QuoteVerifier, type QuoteVerifierOptions, type TrustedProfileOptions } from './verify.js';
|
|
31
31
|
/** The workflow that signs every mero-tee node release, and the issuer of its identity. */
|
|
32
32
|
export declare const NODE_RELEASE_SIGNER: Readonly<SignerIdentity>;
|
|
33
33
|
/**
|
|
@@ -107,11 +107,9 @@ export declare function fetchNodeReleaseVersion(baseUrl: string, options?: {
|
|
|
107
107
|
}): Promise<string>;
|
|
108
108
|
/** Where the cloud at `cloudUrl` (e.g. `https://cloud.calimero.network`) mirrors node release `version`. */
|
|
109
109
|
export declare function cloudNodeReleaseUrl(cloudUrl: string, version: string): string;
|
|
110
|
-
export interface TrustSignedReleaseOptions {
|
|
110
|
+
export interface TrustSignedReleaseOptions extends TrustedProfileOptions {
|
|
111
111
|
/** The release, from any source; it is verified here. */
|
|
112
112
|
release: SignedNodeRelease;
|
|
113
|
-
/** The image profile to trust, e.g. `locked-read-only`. */
|
|
114
|
-
profile: string;
|
|
115
113
|
/**
|
|
116
114
|
* The oldest release accepted, e.g. `2.3.87`. Required: every release ever
|
|
117
115
|
* signed stays validly signed, so without a floor a relay could present an
|
package/dist/sealed/release.js
CHANGED
|
@@ -200,7 +200,10 @@ export async function trustSignedRelease(options) {
|
|
|
200
200
|
if (compareReleaseVersions(version, minimum) < 0) {
|
|
201
201
|
throw new Error(`Release ${version} is older than the minimum trusted, ${minimum}`);
|
|
202
202
|
}
|
|
203
|
-
return trustedMeasurementsFromReleases([published], {
|
|
203
|
+
return trustedMeasurementsFromReleases([published], {
|
|
204
|
+
profile: options.profile,
|
|
205
|
+
allowDebugProfile: options.allowDebugProfile,
|
|
206
|
+
});
|
|
204
207
|
}
|
|
205
208
|
/**
|
|
206
209
|
* A {@link createQuoteVerifier} whose trusted image is the signed release the
|
|
@@ -220,6 +223,7 @@ export function createSignedReleaseVerifier(options) {
|
|
|
220
223
|
const trusted = await trustSignedRelease({
|
|
221
224
|
release: await options.release(),
|
|
222
225
|
profile: options.profile,
|
|
226
|
+
allowDebugProfile: options.allowDebugProfile,
|
|
223
227
|
minReleaseVersion: options.minReleaseVersion,
|
|
224
228
|
identity: options.identity,
|
|
225
229
|
issuer: options.issuer,
|
package/dist/sealed/verify.d.ts
CHANGED
|
@@ -167,6 +167,20 @@ export interface PublishedMrtds {
|
|
|
167
167
|
* (checked out of a release you verified) trusts that release; fetching it at
|
|
168
168
|
* run time trusts whoever serves it.
|
|
169
169
|
*/
|
|
170
|
-
|
|
170
|
+
/**
|
|
171
|
+
* The one image profile a release publishes for production. The `debug` and
|
|
172
|
+
* `debug-read-only` images are signed and published beside it, but run with
|
|
173
|
+
* SSH and the operator's tooling inside the TD, so trusting one trusts an
|
|
174
|
+
* image the operator can read.
|
|
175
|
+
*/
|
|
176
|
+
export declare const PRODUCTION_PROFILE = "locked-read-only";
|
|
177
|
+
export interface TrustedProfileOptions {
|
|
178
|
+
/** The image profile to trust, e.g. `locked-read-only`. */
|
|
171
179
|
profile: string;
|
|
172
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Trust a profile other than {@link PRODUCTION_PROFILE}, such as `debug`.
|
|
182
|
+
* Its image is readable by whoever operates the node, so only for testing.
|
|
183
|
+
*/
|
|
184
|
+
allowDebugProfile?: boolean;
|
|
185
|
+
}
|
|
186
|
+
export declare function trustedMeasurementsFromReleases(releases: PublishedMrtds[], { profile, allowDebugProfile }: TrustedProfileOptions): Required<Pick<QuoteVerifierOptions, 'allowedMeasurements' | 'allowedTcbStatuses'>>;
|
package/dist/sealed/verify.js
CHANGED
|
@@ -90,6 +90,13 @@ export function createQuoteVerifier(options) {
|
|
|
90
90
|
throw new Error(`The platform's TCB status is ${verified.status}, which is not accepted`);
|
|
91
91
|
}
|
|
92
92
|
const td = tdReport(verified.report);
|
|
93
|
+
// TUD bit 0. A debug TD's memory and registers are open to the host, so its
|
|
94
|
+
// measurements prove nothing about what runs in it. Checked here, not left
|
|
95
|
+
// to `dcapVerify`, which a caller may swap for one that allows debug; an
|
|
96
|
+
// attribute field that cannot be read counts as debug.
|
|
97
|
+
if (td.tdAttributes?.length !== 8 || (td.tdAttributes[0] & 0x01) !== 0) {
|
|
98
|
+
throw new Error('The quote is from a debug TD, or its TD attributes cannot be read');
|
|
99
|
+
}
|
|
93
100
|
const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((register) => hex(register));
|
|
94
101
|
if (allowedImages.length > 0 && !allowedImages.includes(measured.join())) {
|
|
95
102
|
throw new Error(`The measurements (MRTD ${measured[0]}, RTMR0-3 ${measured.slice(1).join(', ')}) are not an image this verifier trusts`);
|
|
@@ -166,7 +173,14 @@ const TCB_STATUSES = [
|
|
|
166
173
|
* (checked out of a release you verified) trusts that release; fetching it at
|
|
167
174
|
* run time trusts whoever serves it.
|
|
168
175
|
*/
|
|
169
|
-
|
|
176
|
+
/**
|
|
177
|
+
* The one image profile a release publishes for production. The `debug` and
|
|
178
|
+
* `debug-read-only` images are signed and published beside it, but run with
|
|
179
|
+
* SSH and the operator's tooling inside the TD, so trusting one trusts an
|
|
180
|
+
* image the operator can read.
|
|
181
|
+
*/
|
|
182
|
+
export const PRODUCTION_PROFILE = 'locked-read-only';
|
|
183
|
+
export function trustedMeasurementsFromReleases(releases, { profile, allowDebugProfile = false }) {
|
|
170
184
|
if (releases.length === 0) {
|
|
171
185
|
throw new Error('No release given, so no image would be trusted');
|
|
172
186
|
}
|
|
@@ -181,6 +195,10 @@ export function trustedMeasurementsFromReleases(releases, { profile }) {
|
|
|
181
195
|
const known = Object.keys(release?.profiles ?? {}).join(', ') || 'none';
|
|
182
196
|
throw new Error(`${name} has no profile ${JSON.stringify(profile)} (it has: ${known})`);
|
|
183
197
|
}
|
|
198
|
+
if (profile !== PRODUCTION_PROFILE && !allowDebugProfile) {
|
|
199
|
+
throw new Error(`${JSON.stringify(profile)} is not a production profile: its image is readable by whoever ` +
|
|
200
|
+
`operates the node. Trust ${JSON.stringify(PRODUCTION_PROFILE)}, or pass allowDebugProfile to test`);
|
|
201
|
+
}
|
|
184
202
|
const accepted = (image.allowed_tcb_statuses ?? ['uptodate']).map((status) => tcbStatus(status, name));
|
|
185
203
|
statuses = statuses === undefined ? accepted : statuses.filter((status) => accepted.includes(status));
|
|
186
204
|
return {
|
|
@@ -82,6 +82,13 @@ export interface RelayTransportConfig {
|
|
|
82
82
|
* would have that caller take the client apart to put it back together.
|
|
83
83
|
*/
|
|
84
84
|
relay: RelayClient | RelayClientConfig;
|
|
85
|
+
/**
|
|
86
|
+
* Fetch for everything this client sends the relay: intents (unless `relay`
|
|
87
|
+
* names its own), admin reads, the observing login and events. Typically a
|
|
88
|
+
* sealed fetch (`createAttestedSealedFetch`), so none of it can be read where
|
|
89
|
+
* TLS ends. Defaults to global `fetch`.
|
|
90
|
+
*/
|
|
91
|
+
fetch?: typeof fetch;
|
|
85
92
|
/**
|
|
86
93
|
* A session on the relay, if this client has one.
|
|
87
94
|
*
|
|
@@ -156,6 +163,8 @@ export declare class MeroClient {
|
|
|
156
163
|
private readonly proofAuthorizer;
|
|
157
164
|
private readonly relayUrl;
|
|
158
165
|
private proofEvents;
|
|
166
|
+
/** The relay transport's `fetch`, if one was given. */
|
|
167
|
+
private readonly relayFetch;
|
|
159
168
|
private relayPresence;
|
|
160
169
|
constructor(config: MeroClientConfig);
|
|
161
170
|
/**
|
|
@@ -88,7 +88,7 @@ function missingNodeKey(surface) {
|
|
|
88
88
|
* authors is the device that observes, and taking a second copy from the caller
|
|
89
89
|
* is how the two come to name different keys.
|
|
90
90
|
*/
|
|
91
|
-
function buildObserver(relay, observe) {
|
|
91
|
+
function buildObserver(relay, observe, fetchImpl) {
|
|
92
92
|
const nodeKey = observe?.nodeKey;
|
|
93
93
|
if (!nodeKey)
|
|
94
94
|
return null;
|
|
@@ -100,7 +100,7 @@ function buildObserver(relay, observe) {
|
|
|
100
100
|
signer: observe?.signer ? async () => observe.signer : () => relay.authorSigner(),
|
|
101
101
|
clientName: observe?.clientName,
|
|
102
102
|
ttlSeconds: observe?.ttlSeconds,
|
|
103
|
-
fetch: observe?.fetch,
|
|
103
|
+
fetch: observe?.fetch ?? fetchImpl,
|
|
104
104
|
timeoutMs: observe?.timeoutMs,
|
|
105
105
|
});
|
|
106
106
|
}
|
|
@@ -128,12 +128,18 @@ export class MeroClient {
|
|
|
128
128
|
this.proofAuthorizer = null;
|
|
129
129
|
this.relayUrl = null;
|
|
130
130
|
this.proofEvents = null;
|
|
131
|
+
/** The relay transport's `fetch`, if one was given. */
|
|
132
|
+
this.relayFetch = undefined;
|
|
131
133
|
this.relayPresence = null;
|
|
132
134
|
if (config.transport === 'relay') {
|
|
133
135
|
this.transport = 'relay';
|
|
134
136
|
this.nodeClient = null;
|
|
135
|
-
const
|
|
136
|
-
this.
|
|
137
|
+
const fetchImpl = config.fetch;
|
|
138
|
+
this.relayFetch = fetchImpl;
|
|
139
|
+
const relay = config.relay instanceof RelayClient
|
|
140
|
+
? config.relay
|
|
141
|
+
: new RelayClient({ ...config.relay, fetch: config.relay.fetch ?? fetchImpl });
|
|
142
|
+
this.relayObserver = buildObserver(relay, config.observe, fetchImpl);
|
|
137
143
|
this.rpcTransport = new RelayTransport(relay, this.relayObserver);
|
|
138
144
|
this.relayUrl = relay.relayUrl;
|
|
139
145
|
if (config.proof) {
|
|
@@ -150,12 +156,13 @@ export class MeroClient {
|
|
|
150
156
|
this.relayAdmin = createAdminApiClient({
|
|
151
157
|
baseUrl: relay.relayUrl,
|
|
152
158
|
getAuthToken: typeof token === 'string' ? async () => token : token,
|
|
159
|
+
fetch: fetchImpl,
|
|
153
160
|
});
|
|
154
161
|
}
|
|
155
162
|
else if (this.proofAuthorizer) {
|
|
156
163
|
const authorizeRequest = this.proofAuthorizer;
|
|
157
164
|
this.relayAdmin = createAdminApiClientFromHttpClient(createHttpClient({
|
|
158
|
-
fetch: (url, init) => globalThis.fetch(url, init),
|
|
165
|
+
fetch: (url, init) => fetchImpl ? fetchImpl(url, init) : globalThis.fetch(url, init),
|
|
159
166
|
baseUrl: relay.relayUrl,
|
|
160
167
|
authorizeRequest,
|
|
161
168
|
}), { baseUrl: relay.relayUrl });
|
|
@@ -281,6 +288,7 @@ export class MeroClient {
|
|
|
281
288
|
this.proofEvents ?? (this.proofEvents = new SseClient({
|
|
282
289
|
baseUrl: this.relayUrl,
|
|
283
290
|
authorize: this.proofAuthorizer,
|
|
291
|
+
fetch: this.relayFetch,
|
|
284
292
|
}));
|
|
285
293
|
return this.proofEvents;
|
|
286
294
|
}
|