mindoodb 0.0.44 → 0.0.46
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 +9 -0
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.js +4 -0
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
- package/dist/browser/index.mjs +31 -0
- package/dist/core/BaseMindooDB.d.ts +74 -0
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +160 -0
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +22 -0
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +57 -6
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantFactory.js +31 -9
- package/dist/core/BaseMindooTenantFactory.js.map +1 -1
- package/dist/core/copy/attachments.d.ts +53 -0
- package/dist/core/copy/attachments.d.ts.map +1 -0
- package/dist/core/copy/attachments.js +186 -0
- package/dist/core/copy/attachments.js.map +1 -0
- package/dist/core/copy/copyDocument.d.ts +86 -0
- package/dist/core/copy/copyDocument.d.ts.map +1 -0
- package/dist/core/copy/copyDocument.js +369 -0
- package/dist/core/copy/copyDocument.js.map +1 -0
- package/dist/core/copy/copyDocuments.d.ts +57 -0
- package/dist/core/copy/copyDocuments.d.ts.map +1 -0
- package/dist/core/copy/copyDocuments.js +167 -0
- package/dist/core/copy/copyDocuments.js.map +1 -0
- package/dist/core/copy/entryRewrite.d.ts +49 -0
- package/dist/core/copy/entryRewrite.d.ts.map +1 -0
- package/dist/core/copy/entryRewrite.js +74 -0
- package/dist/core/copy/entryRewrite.js.map +1 -0
- package/dist/core/copy/feasibility.d.ts +73 -0
- package/dist/core/copy/feasibility.d.ts.map +1 -0
- package/dist/core/copy/feasibility.js +169 -0
- package/dist/core/copy/feasibility.js.map +1 -0
- package/dist/core/copy/flatten.d.ts +55 -0
- package/dist/core/copy/flatten.d.ts.map +1 -0
- package/dist/core/copy/flatten.js +155 -0
- package/dist/core/copy/flatten.js.map +1 -0
- package/dist/core/copy/host.d.ts +92 -0
- package/dist/core/copy/host.d.ts.map +1 -0
- package/dist/core/copy/host.js +16 -0
- package/dist/core/copy/host.js.map +1 -0
- package/dist/core/copy/preflight.d.ts +62 -0
- package/dist/core/copy/preflight.d.ts.map +1 -0
- package/dist/core/copy/preflight.js +98 -0
- package/dist/core/copy/preflight.js.map +1 -0
- package/dist/core/copy/provenance.d.ts +74 -0
- package/dist/core/copy/provenance.d.ts.map +1 -0
- package/dist/core/copy/provenance.js +91 -0
- package/dist/core/copy/provenance.js.map +1 -0
- package/dist/core/copy/types.d.ts +418 -0
- package/dist/core/copy/types.d.ts.map +1 -0
- package/dist/core/copy/types.js +21 -0
- package/dist/core/copy/types.js.map +1 -0
- package/dist/core/crypto/DomainStatement.d.ts +44 -0
- package/dist/core/crypto/DomainStatement.d.ts.map +1 -0
- package/dist/core/crypto/DomainStatement.js +71 -0
- package/dist/core/crypto/DomainStatement.js.map +1 -0
- package/dist/core/crypto/EntrySignature.d.ts +109 -15
- package/dist/core/crypto/EntrySignature.d.ts.map +1 -1
- package/dist/core/crypto/EntrySignature.js +83 -22
- package/dist/core/crypto/EntrySignature.js.map +1 -1
- package/dist/core/index.d.ts +21 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +54 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/timestamps/timestampClient.d.ts +88 -0
- package/dist/core/timestamps/timestampClient.d.ts.map +1 -0
- package/dist/core/timestamps/timestampClient.js +157 -0
- package/dist/core/timestamps/timestampClient.js.map +1 -0
- package/dist/core/types.d.ts +134 -4
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/node/server/MindooDBServer.d.ts +37 -0
- package/dist/node/server/MindooDBServer.d.ts.map +1 -1
- package/dist/node/server/MindooDBServer.js +157 -0
- package/dist/node/server/MindooDBServer.js.map +1 -1
- package/dist/node/server/config.d.ts.map +1 -1
- package/dist/node/server/config.js +16 -0
- package/dist/node/server/config.js.map +1 -1
- package/dist/node/server/timestampProxy.d.ts +129 -0
- package/dist/node/server/timestampProxy.d.ts.map +1 -0
- package/dist/node/server/timestampProxy.js +361 -0
- package/dist/node/server/timestampProxy.js.map +1 -0
- package/dist/node/server/types.d.ts +20 -0
- package/dist/node/server/types.d.ts.map +1 -1
- package/dist/node/server/types.js +12 -0
- package/dist/node/server/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client transport for RFC 3161 timestamps.
|
|
3
|
+
*
|
|
4
|
+
* Two paths, because no single one works everywhere:
|
|
5
|
+
*
|
|
6
|
+
* - **Direct.** `https://rfc3161.ai.moda` is the only public TSA measured to
|
|
7
|
+
* send CORS headers, so a browser can reach it unaided. This keeps sealing
|
|
8
|
+
* working on a Haven with no MindooDB server at all.
|
|
9
|
+
* - **Proxy.** Everything else is http-only or CORS-less — including every
|
|
10
|
+
* eIDAS-qualified authority — so those go through the tenant's server at
|
|
11
|
+
* `POST /:tenantId/timestamps/rfc3161`.
|
|
12
|
+
*
|
|
13
|
+
* Both carry opaque DER. **Neither is trusted.** The caller must verify that
|
|
14
|
+
* the returned token's `messageImprint` equals the digest it sent and that the
|
|
15
|
+
* token chains to a trusted root (see `verifyTimestampResponse` in
|
|
16
|
+
* `mindoodb-seal`). With those two checks a hostile transport can withhold a
|
|
17
|
+
* timestamp but cannot forge one, which is why calling a third-party proxy from
|
|
18
|
+
* the browser is acceptable at all.
|
|
19
|
+
*/
|
|
20
|
+
export declare const TIMESTAMP_QUERY_CONTENT_TYPE = "application/timestamp-query";
|
|
21
|
+
export declare const TIMESTAMP_REPLY_CONTENT_TYPE = "application/timestamp-reply";
|
|
22
|
+
/** Bound on an accepted TimeStampResp; real tokens are a few KB. */
|
|
23
|
+
export declare const MAX_TIMESTAMP_RESPONSE_BYTES: number;
|
|
24
|
+
export declare const DEFAULT_TIMESTAMP_TIMEOUT_MS = 15000;
|
|
25
|
+
/**
|
|
26
|
+
* The one public TSA a browser can call directly (verified by CORS preflight:
|
|
27
|
+
* reflected origin, `POST, OPTIONS`, `Content-Type`). It is a failover proxy in
|
|
28
|
+
* front of DigiCert, Sectigo, Azure and others, so its tokens chain to roots
|
|
29
|
+
* already in public trust stores.
|
|
30
|
+
*/
|
|
31
|
+
export declare const BROWSER_REACHABLE_TSA: Readonly<{
|
|
32
|
+
id: "aimoda";
|
|
33
|
+
name: "ai.moda RFC 3161 proxy";
|
|
34
|
+
url: "https://rfc3161.ai.moda";
|
|
35
|
+
}>;
|
|
36
|
+
export type TimestampSource = "direct" | "proxy";
|
|
37
|
+
export interface TimestampTokenResult {
|
|
38
|
+
/** Raw DER TimeStampResp, unverified. */
|
|
39
|
+
response: Uint8Array;
|
|
40
|
+
providerId: string;
|
|
41
|
+
source: TimestampSource;
|
|
42
|
+
}
|
|
43
|
+
export declare class TimestampRequestError extends Error {
|
|
44
|
+
readonly source: TimestampSource;
|
|
45
|
+
readonly httpStatus?: number | undefined;
|
|
46
|
+
constructor(message: string, source: TimestampSource, httpStatus?: number | undefined);
|
|
47
|
+
}
|
|
48
|
+
interface PostTimestampOptions {
|
|
49
|
+
request: Uint8Array;
|
|
50
|
+
timeoutMs?: number;
|
|
51
|
+
fetchImpl?: typeof fetch;
|
|
52
|
+
maxResponseBytes?: number;
|
|
53
|
+
}
|
|
54
|
+
/** Call a CORS-enabled TSA straight from the client. */
|
|
55
|
+
export declare function requestTimestampDirect(options: PostTimestampOptions & {
|
|
56
|
+
url?: string;
|
|
57
|
+
providerId?: string;
|
|
58
|
+
}): Promise<TimestampTokenResult>;
|
|
59
|
+
export interface ProxyTimestampOptions extends PostTimestampOptions {
|
|
60
|
+
/** Base URL of the MindooDB server, e.g. `https://sync.example.com`. */
|
|
61
|
+
serverUrl: string;
|
|
62
|
+
tenantId: string;
|
|
63
|
+
/** Bearer token from the tenant's existing authenticated session. */
|
|
64
|
+
authToken: string;
|
|
65
|
+
/** Provider id from the server's advertised list. Never a URL — the server allowlists. */
|
|
66
|
+
providerId?: string;
|
|
67
|
+
}
|
|
68
|
+
/** Route through the tenant's MindooDB server, for http-only or CORS-less authorities. */
|
|
69
|
+
export declare function requestTimestampViaProxy(options: ProxyTimestampOptions): Promise<TimestampTokenResult>;
|
|
70
|
+
export interface TimestampWithFallbackOptions extends PostTimestampOptions {
|
|
71
|
+
/** Proxy details, when the client has an authenticated server connection. */
|
|
72
|
+
proxy?: Omit<ProxyTimestampOptions, keyof PostTimestampOptions>;
|
|
73
|
+
/** Try the proxy first — the right order when the tenant has a qualified provider configured. */
|
|
74
|
+
preferProxy?: boolean;
|
|
75
|
+
/** Skip the direct call (air-gapped deployments, or policy against third-party endpoints). */
|
|
76
|
+
allowDirect?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Try both transports, returning the first token obtained.
|
|
80
|
+
*
|
|
81
|
+
* A seal is worth little without a timestamp, so failing over is worth the
|
|
82
|
+
* extra round trip. The order is caller-chosen because it is a policy question,
|
|
83
|
+
* not a technical one: a tenant with a qualified provider configured wants the
|
|
84
|
+
* proxy first, while a laptop with no server reachable wants the direct path.
|
|
85
|
+
*/
|
|
86
|
+
export declare function requestTimestampWithFallback(options: TimestampWithFallbackOptions): Promise<TimestampTokenResult>;
|
|
87
|
+
export {};
|
|
88
|
+
//# sourceMappingURL=timestampClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestampClient.d.ts","sourceRoot":"","sources":["../../../src/core/timestamps/timestampClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,4BAA4B,gCAAgC,CAAC;AAC1E,eAAO,MAAM,4BAA4B,gCAAgC,CAAC;AAE1E,oEAAoE;AACpE,eAAO,MAAM,4BAA4B,QAAa,CAAC;AACvD,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;EAIhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,yCAAyC;IACzC,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG5C,QAAQ,CAAC,MAAM,EAAE,eAAe;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM;gBAF5B,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,eAAe,EACvB,UAAU,CAAC,EAAE,MAAM,YAAA;CAK/B;AAED,UAAU,oBAAoB;IAC5B,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkED,wDAAwD;AACxD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,oBAAoB,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE,OAAO,CAAC,oBAAoB,CAAC,CAQ/B;AAED,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0FAA0F;AAC1F,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAe/B;AAED,MAAM,WAAW,4BAA6B,SAAQ,oBAAoB;IACxE,6EAA6E;IAC7E,KAAK,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,oBAAoB,CAAC,CAAC;IAChE,iGAAiG;IACjG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CA+B/B"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Client transport for RFC 3161 timestamps.
|
|
4
|
+
*
|
|
5
|
+
* Two paths, because no single one works everywhere:
|
|
6
|
+
*
|
|
7
|
+
* - **Direct.** `https://rfc3161.ai.moda` is the only public TSA measured to
|
|
8
|
+
* send CORS headers, so a browser can reach it unaided. This keeps sealing
|
|
9
|
+
* working on a Haven with no MindooDB server at all.
|
|
10
|
+
* - **Proxy.** Everything else is http-only or CORS-less — including every
|
|
11
|
+
* eIDAS-qualified authority — so those go through the tenant's server at
|
|
12
|
+
* `POST /:tenantId/timestamps/rfc3161`.
|
|
13
|
+
*
|
|
14
|
+
* Both carry opaque DER. **Neither is trusted.** The caller must verify that
|
|
15
|
+
* the returned token's `messageImprint` equals the digest it sent and that the
|
|
16
|
+
* token chains to a trusted root (see `verifyTimestampResponse` in
|
|
17
|
+
* `mindoodb-seal`). With those two checks a hostile transport can withhold a
|
|
18
|
+
* timestamp but cannot forge one, which is why calling a third-party proxy from
|
|
19
|
+
* the browser is acceptable at all.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.TimestampRequestError = exports.BROWSER_REACHABLE_TSA = exports.DEFAULT_TIMESTAMP_TIMEOUT_MS = exports.MAX_TIMESTAMP_RESPONSE_BYTES = exports.TIMESTAMP_REPLY_CONTENT_TYPE = exports.TIMESTAMP_QUERY_CONTENT_TYPE = void 0;
|
|
23
|
+
exports.requestTimestampDirect = requestTimestampDirect;
|
|
24
|
+
exports.requestTimestampViaProxy = requestTimestampViaProxy;
|
|
25
|
+
exports.requestTimestampWithFallback = requestTimestampWithFallback;
|
|
26
|
+
exports.TIMESTAMP_QUERY_CONTENT_TYPE = "application/timestamp-query";
|
|
27
|
+
exports.TIMESTAMP_REPLY_CONTENT_TYPE = "application/timestamp-reply";
|
|
28
|
+
/** Bound on an accepted TimeStampResp; real tokens are a few KB. */
|
|
29
|
+
exports.MAX_TIMESTAMP_RESPONSE_BYTES = 128 * 1024;
|
|
30
|
+
exports.DEFAULT_TIMESTAMP_TIMEOUT_MS = 15000;
|
|
31
|
+
/**
|
|
32
|
+
* The one public TSA a browser can call directly (verified by CORS preflight:
|
|
33
|
+
* reflected origin, `POST, OPTIONS`, `Content-Type`). It is a failover proxy in
|
|
34
|
+
* front of DigiCert, Sectigo, Azure and others, so its tokens chain to roots
|
|
35
|
+
* already in public trust stores.
|
|
36
|
+
*/
|
|
37
|
+
exports.BROWSER_REACHABLE_TSA = Object.freeze({
|
|
38
|
+
id: "aimoda",
|
|
39
|
+
name: "ai.moda RFC 3161 proxy",
|
|
40
|
+
url: "https://rfc3161.ai.moda",
|
|
41
|
+
});
|
|
42
|
+
class TimestampRequestError extends Error {
|
|
43
|
+
constructor(message, source, httpStatus) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.source = source;
|
|
46
|
+
this.httpStatus = httpStatus;
|
|
47
|
+
this.name = "TimestampRequestError";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.TimestampRequestError = TimestampRequestError;
|
|
51
|
+
async function postTimestampQuery(url, source, options) {
|
|
52
|
+
const { request, timeoutMs = exports.DEFAULT_TIMESTAMP_TIMEOUT_MS, fetchImpl = fetch, maxResponseBytes = exports.MAX_TIMESTAMP_RESPONSE_BYTES, headers = {}, } = options;
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetchImpl(url, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: {
|
|
59
|
+
"content-type": exports.TIMESTAMP_QUERY_CONTENT_TYPE,
|
|
60
|
+
accept: exports.TIMESTAMP_REPLY_CONTENT_TYPE,
|
|
61
|
+
...headers,
|
|
62
|
+
},
|
|
63
|
+
body: request.slice().buffer,
|
|
64
|
+
signal: controller.signal,
|
|
65
|
+
});
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
throw new TimestampRequestError(`Timestamp request failed with HTTP ${response.status}`, source, response.status);
|
|
68
|
+
}
|
|
69
|
+
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
70
|
+
if (buffer.byteLength === 0) {
|
|
71
|
+
throw new TimestampRequestError("Timestamp authority returned an empty response", source);
|
|
72
|
+
}
|
|
73
|
+
if (buffer.byteLength > maxResponseBytes) {
|
|
74
|
+
throw new TimestampRequestError(`Timestamp response too large (${buffer.byteLength} bytes)`, source);
|
|
75
|
+
}
|
|
76
|
+
// Cheap sanity check; the real validation is CMS verification by the caller.
|
|
77
|
+
if (buffer[0] !== 0x30) {
|
|
78
|
+
throw new TimestampRequestError("Timestamp response is not DER-encoded", source);
|
|
79
|
+
}
|
|
80
|
+
return buffer;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error instanceof TimestampRequestError)
|
|
84
|
+
throw error;
|
|
85
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
86
|
+
throw new TimestampRequestError(`Timestamp request timed out after ${timeoutMs}ms`, source);
|
|
87
|
+
}
|
|
88
|
+
throw new TimestampRequestError(`Timestamp request failed: ${error instanceof Error ? error.message : String(error)}`, source);
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
clearTimeout(timer);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Call a CORS-enabled TSA straight from the client. */
|
|
95
|
+
async function requestTimestampDirect(options) {
|
|
96
|
+
const url = options.url ?? exports.BROWSER_REACHABLE_TSA.url;
|
|
97
|
+
const response = await postTimestampQuery(url, "direct", options);
|
|
98
|
+
return {
|
|
99
|
+
response,
|
|
100
|
+
providerId: options.providerId ?? exports.BROWSER_REACHABLE_TSA.id,
|
|
101
|
+
source: "direct",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** Route through the tenant's MindooDB server, for http-only or CORS-less authorities. */
|
|
105
|
+
async function requestTimestampViaProxy(options) {
|
|
106
|
+
const base = options.serverUrl.replace(/\/+$/, "");
|
|
107
|
+
const query = options.providerId ? `?provider=${encodeURIComponent(options.providerId)}` : "";
|
|
108
|
+
const url = `${base}/${encodeURIComponent(options.tenantId)}/timestamps/rfc3161${query}`;
|
|
109
|
+
const response = await postTimestampQuery(url, "proxy", {
|
|
110
|
+
...options,
|
|
111
|
+
headers: { authorization: `Bearer ${options.authToken}` },
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
response,
|
|
115
|
+
providerId: options.providerId ?? "server",
|
|
116
|
+
source: "proxy",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Try both transports, returning the first token obtained.
|
|
121
|
+
*
|
|
122
|
+
* A seal is worth little without a timestamp, so failing over is worth the
|
|
123
|
+
* extra round trip. The order is caller-chosen because it is a policy question,
|
|
124
|
+
* not a technical one: a tenant with a qualified provider configured wants the
|
|
125
|
+
* proxy first, while a laptop with no server reachable wants the direct path.
|
|
126
|
+
*/
|
|
127
|
+
async function requestTimestampWithFallback(options) {
|
|
128
|
+
const { proxy, preferProxy = false, allowDirect = true, ...post } = options;
|
|
129
|
+
const attempts = [];
|
|
130
|
+
const direct = () => requestTimestampDirect(post);
|
|
131
|
+
const viaProxy = proxy ? () => requestTimestampViaProxy({ ...proxy, ...post }) : undefined;
|
|
132
|
+
if (preferProxy && viaProxy) {
|
|
133
|
+
attempts.push(viaProxy);
|
|
134
|
+
if (allowDirect)
|
|
135
|
+
attempts.push(direct);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
if (allowDirect)
|
|
139
|
+
attempts.push(direct);
|
|
140
|
+
if (viaProxy)
|
|
141
|
+
attempts.push(viaProxy);
|
|
142
|
+
}
|
|
143
|
+
if (attempts.length === 0) {
|
|
144
|
+
throw new TimestampRequestError("No timestamp transport is available", "direct");
|
|
145
|
+
}
|
|
146
|
+
const errors = [];
|
|
147
|
+
for (const attempt of attempts) {
|
|
148
|
+
try {
|
|
149
|
+
return await attempt();
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
errors.push(error instanceof Error ? error.message : String(error));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
throw new TimestampRequestError(`No timestamp authority could be reached (${errors.join("; ")})`, "direct");
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=timestampClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestampClient.js","sourceRoot":"","sources":["../../../src/core/timestamps/timestampClient.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import type { PublicUserId, PrivateUserId } from "./userid";
|
|
|
4
4
|
import { StoreKind } from "./appendonlystores/types";
|
|
5
5
|
import type { ContentAddressedStore, OpenStoreOptions, RejectedPutEntry } from "./appendonlystores/types";
|
|
6
6
|
import type { CryptoAdapter } from "./crypto/CryptoAdapter";
|
|
7
|
+
import type { EntryProvenance } from "./crypto/EntrySignature";
|
|
8
|
+
import type { CopyDocumentOptions, CopyDocumentResult, CopyDocumentSelector, CopyDocumentsOptions, CopyDocumentsResult, CopyFeasibility } from "./copy/types";
|
|
7
9
|
import { MindooDocSigner } from "./crypto/MindooDocSigner";
|
|
8
10
|
import type { DefaultAccessPolicyDoc, KeyDistributionPushRecipient, KeyDistributionRequest, KeyDistributionView, KeyVersionRef, AppDistributionRequest, AppDistributionView, AppDistributionReconcilePlan, SyncSetupPolicyRequest, SyncSetupPolicyView, SyncSetupPolicyReconcilePlan, DocHistoryPurgeRequest, DocHistoryPurgeView, RuleTargets, RuleType, WithFieldClause, AclRuleDoc, AccessDecision } from "./accesscontrol/types";
|
|
9
11
|
import type { DirectoryStateNode } from "./accesscontrol/DirectoryStateNode";
|
|
@@ -242,10 +244,25 @@ export interface CreateTenantResult {
|
|
|
242
244
|
* Can be serialized to a mdb://join-request/... URI for out-of-band exchange.
|
|
243
245
|
*/
|
|
244
246
|
export interface JoinRequest {
|
|
245
|
-
/**
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Protocol version. A `v: 1` request always carries {@link username}; a
|
|
249
|
+
* `v: 2` request may omit it and leave the name to the approving admin.
|
|
250
|
+
* Emitting `2` only for nameless requests keeps older readers from silently
|
|
251
|
+
* registering an undefined username — they reject the unknown version
|
|
252
|
+
* instead.
|
|
253
|
+
*/
|
|
254
|
+
v: 1 | 2;
|
|
255
|
+
/**
|
|
256
|
+
* The username the user wants to be registered as (e.g. "cn=user2/o=acme").
|
|
257
|
+
*
|
|
258
|
+
* Optional from v2 on. Omitting it is the recommended path when enrolling an
|
|
259
|
+
* additional device for someone who is already in the directory: the exact
|
|
260
|
+
* spelling only exists on the admin's device, and a mistyped name here would
|
|
261
|
+
* silently register a second person rather than a second device (§6.5). The
|
|
262
|
+
* approving admin then supplies the name via
|
|
263
|
+
* {@link ApproveJoinRequestOptions.username}.
|
|
264
|
+
*/
|
|
265
|
+
username?: string;
|
|
249
266
|
/** Ed25519 public signing key (PEM format) */
|
|
250
267
|
signingPublicKey: string;
|
|
251
268
|
/** RSA-OAEP public encryption key (PEM format) */
|
|
@@ -288,6 +305,16 @@ export interface ApproveJoinRequestOptions {
|
|
|
288
305
|
* §6.5). Useful for recording a date or a note about the device type.
|
|
289
306
|
*/
|
|
290
307
|
label?: string;
|
|
308
|
+
/**
|
|
309
|
+
* Username to register the joining device under, overriding whatever the
|
|
310
|
+
* request suggested. Required when the request omits a username.
|
|
311
|
+
*
|
|
312
|
+
* Passing the exact spelling of an existing directory entry is what turns a
|
|
313
|
+
* join request into an additional device for that user instead of a new
|
|
314
|
+
* person, so admin UIs should offer a pick-from-directory choice here rather
|
|
315
|
+
* than trusting the requester's spelling (§6.5).
|
|
316
|
+
*/
|
|
317
|
+
username?: string;
|
|
291
318
|
/** If "uri", approveJoinRequest returns a mdb://join-response/... URI string instead of an object */
|
|
292
319
|
format?: "object" | "uri";
|
|
293
320
|
}
|
|
@@ -323,6 +350,15 @@ export interface JoinResponse {
|
|
|
323
350
|
serverUrl?: string;
|
|
324
351
|
/** Optional admin username for display purposes */
|
|
325
352
|
adminUsername?: string;
|
|
353
|
+
/**
|
|
354
|
+
* The username the joining device was actually registered as.
|
|
355
|
+
*
|
|
356
|
+
* The joining device adopts this so its local identity matches the directory
|
|
357
|
+
* even when the admin corrected the requested name or supplied one for a
|
|
358
|
+
* nameless request. Absent in responses from older admins, in which case the
|
|
359
|
+
* requester keeps the name it chose itself.
|
|
360
|
+
*/
|
|
361
|
+
username?: string;
|
|
326
362
|
/** Selected tenant document keys, encrypted with the sharePassword. */
|
|
327
363
|
encryptedDocKeys: JoinResponseEncryptedDocKey[];
|
|
328
364
|
}
|
|
@@ -381,6 +417,12 @@ export interface JoinTenantResult {
|
|
|
381
417
|
tenant: MindooTenant;
|
|
382
418
|
/** The KeyBag containing the imported tenant and $publicinfos keys */
|
|
383
419
|
keyBag: KeyBag;
|
|
420
|
+
/**
|
|
421
|
+
* The identity the tenant was opened with. Identical to the supplied user
|
|
422
|
+
* unless the join response carried a different username, in which case this
|
|
423
|
+
* is the renamed copy (same keys) that the caller should persist locally.
|
|
424
|
+
*/
|
|
425
|
+
user: PrivateUserId;
|
|
384
426
|
}
|
|
385
427
|
/**
|
|
386
428
|
* Options for publishing a tenant to a server.
|
|
@@ -593,6 +635,28 @@ export interface MindooTenant {
|
|
|
593
635
|
* @return The signature (Ed25519 signature as Uint8Array)
|
|
594
636
|
*/
|
|
595
637
|
signPayloadWithKey(payload: Uint8Array, signingKeyPair: SigningKeyPair, password: string): Promise<Uint8Array>;
|
|
638
|
+
/**
|
|
639
|
+
* Sign application-supplied bytes under an allowlisted domain, signing
|
|
640
|
+
* `utf8(domain) || 0x00 || statement`.
|
|
641
|
+
*
|
|
642
|
+
* The only sanctioned way to have the identity key sign content an
|
|
643
|
+
* application chose. The domain prefix keeps such bytes disjoint from the
|
|
644
|
+
* store-entry and auth-challenge layouts, so a signature obtained here cannot
|
|
645
|
+
* be replayed as either (see `crypto/DomainStatement.ts`).
|
|
646
|
+
*
|
|
647
|
+
* @param domain One of `SIGNING_DOMAINS`; anything else is rejected.
|
|
648
|
+
* @param statement Canonical statement bytes.
|
|
649
|
+
* @return The Ed25519 signature over the domain-prefixed bytes.
|
|
650
|
+
*/
|
|
651
|
+
signDomainStatement(domain: string, statement: Uint8Array): Promise<Uint8Array>;
|
|
652
|
+
/**
|
|
653
|
+
* Verify a domain-separated statement signature against a named public key.
|
|
654
|
+
*
|
|
655
|
+
* Does not consult the directory: whether that key is *currently trusted* is
|
|
656
|
+
* a separate question from whether it made this signature, and an evidence
|
|
657
|
+
* verifier legitimately asks only the second one.
|
|
658
|
+
*/
|
|
659
|
+
verifyDomainStatement(domain: string, statement: Uint8Array, signature: Uint8Array, publicKeyPem: string): Promise<boolean>;
|
|
596
660
|
/**
|
|
597
661
|
* Verify a signature for a payload with a public key.
|
|
598
662
|
*
|
|
@@ -922,6 +986,21 @@ export interface StoreEntryMetadata {
|
|
|
922
986
|
* fall back to {@link signature} when it is missing (backward compatible).
|
|
923
987
|
*/
|
|
924
988
|
metadataSignature?: Uint8Array;
|
|
989
|
+
/**
|
|
990
|
+
* Set on entries produced by copying a document into another database with
|
|
991
|
+
* `mode: "history"` and re-authored signatures (see `copyDocumentTo`). Records
|
|
992
|
+
* where the entry came from and who originally authored it, in a form a reader
|
|
993
|
+
* can verify rather than merely trust.
|
|
994
|
+
*
|
|
995
|
+
* Bound into {@link metadataSignature} as a tagged trailing block (see
|
|
996
|
+
* `crypto/EntrySignature.ts`), so a relay can neither attach, strip nor rewrite
|
|
997
|
+
* it. Absent on every entry that is not the product of such a copy, in which
|
|
998
|
+
* case the signing input is byte-identical to the original layout.
|
|
999
|
+
*
|
|
1000
|
+
* Plain JSON by design (the signature inside is base64) so it survives the
|
|
1001
|
+
* on-disk, IndexedDB and network serializers without per-field binary handling.
|
|
1002
|
+
*/
|
|
1003
|
+
provenance?: EntryProvenance;
|
|
925
1004
|
/**
|
|
926
1005
|
* Original size of the plaintext data before encryption (in bytes).
|
|
927
1006
|
* For doc_* entries: size of the Automerge binary change/snapshot
|
|
@@ -4338,6 +4417,57 @@ export interface MindooDB {
|
|
|
4338
4417
|
* call.
|
|
4339
4418
|
*/
|
|
4340
4419
|
getBackgroundWarmerProgress?(): BackgroundWarmerProgress | null;
|
|
4420
|
+
/**
|
|
4421
|
+
* Copy one document into another database, either flattened to a single
|
|
4422
|
+
* revision or with its full revision history.
|
|
4423
|
+
*
|
|
4424
|
+
* Unlike {@link pullChangesFrom} / {@link pushChangesTo}, which replicate one
|
|
4425
|
+
* database between peers, this moves content ACROSS databases — and, with
|
|
4426
|
+
* `signingKeyPair` unset and the right options, across tenants too.
|
|
4427
|
+
*
|
|
4428
|
+
* The default is a flattened copy under a freshly generated document id,
|
|
4429
|
+
* authored by the current user. `mode: "history"` carries the whole revision
|
|
4430
|
+
* graph instead; adding `targetDocId: "same"` and `authorship: "preserve"`
|
|
4431
|
+
* (only legal within one tenant, under the same encryption key, into a
|
|
4432
|
+
* different database) keeps the original signers' signatures valid, which is
|
|
4433
|
+
* what makes {@link copyDocumentsTo} usable as a sharding tool.
|
|
4434
|
+
*
|
|
4435
|
+
* See `docs/document-copy.md` for the full strategy matrix and caveats.
|
|
4436
|
+
*
|
|
4437
|
+
* @param docId The document to copy.
|
|
4438
|
+
* @param target The database to copy into.
|
|
4439
|
+
* @param options See {@link CopyDocumentOptions}.
|
|
4440
|
+
* @return What was copied, including the resulting target document id.
|
|
4441
|
+
*/
|
|
4442
|
+
copyDocumentTo(docId: string, target: MindooDB, options?: CopyDocumentOptions): Promise<CopyDocumentResult>;
|
|
4443
|
+
/**
|
|
4444
|
+
* Report what {@link copyDocumentTo} would do with these options, without
|
|
4445
|
+
* writing anything: the strategy it would use, whether the original authors'
|
|
4446
|
+
* signatures would survive, whether it would merge into an existing document,
|
|
4447
|
+
* and — via `reasons` — why not, when the answer is no.
|
|
4448
|
+
*
|
|
4449
|
+
* @param docId The document that would be copied.
|
|
4450
|
+
* @param target The database it would be copied into.
|
|
4451
|
+
* @param options The same options that would be passed to {@link copyDocumentTo}.
|
|
4452
|
+
*/
|
|
4453
|
+
canCopyDocumentTo(docId: string, target: MindooDB, options?: CopyDocumentOptions): Promise<CopyFeasibility>;
|
|
4454
|
+
/**
|
|
4455
|
+
* Copy many documents into another database in one pass.
|
|
4456
|
+
*
|
|
4457
|
+
* With `mode: "history"`, `targetDocId: "same"` and `authorship: "preserve"`
|
|
4458
|
+
* this splits a database into shards with document ids, full history and
|
|
4459
|
+
* original signers intact, without decrypting or re-signing anything.
|
|
4460
|
+
* Repeated runs transfer only the delta, so a shard can proceed while users
|
|
4461
|
+
* keep working; see the migration playbook in `docs/document-copy.md`.
|
|
4462
|
+
*
|
|
4463
|
+
* A failure on one document does not abort the run — failures are collected
|
|
4464
|
+
* in {@link CopyDocumentsResult.failed}.
|
|
4465
|
+
*
|
|
4466
|
+
* @param selector Which documents to copy: explicit ids, id prefixes, or both.
|
|
4467
|
+
* @param target The database to copy into.
|
|
4468
|
+
* @param options See {@link CopyDocumentsOptions}.
|
|
4469
|
+
*/
|
|
4470
|
+
copyDocumentsTo(selector: CopyDocumentSelector, target: MindooDB, options?: CopyDocumentsOptions): Promise<CopyDocumentsResult>;
|
|
4341
4471
|
/**
|
|
4342
4472
|
* Pull changes from a remote content-addressed store or another MindooDB instance.
|
|
4343
4473
|
*
|