@trylimbo/sdk-verifier-wasm 0.1.0-canary.100
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/gen/wasm/comlink.js +270 -0
- package/gen/wasm/trylimbo_sdk_verifier.d.ts +704 -0
- package/gen/wasm/trylimbo_sdk_verifier.js +1683 -0
- package/gen/wasm/trylimbo_sdk_verifier_bg.wasm +0 -0
- package/gen/wasm/trylimbo_sdk_verifier_bg.wasm.d.ts +62 -0
- package/gen/wasm/worker-thread.js +1604 -0
- package/gen/wasm/worker.d.ts +624 -0
- package/gen/wasm/worker.js +21 -0
- package/package.json +45 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
//#region ../../../../node_modules/comlink/dist/umd/comlink.d.ts
|
|
2
|
+
declare const proxyMarker: unique symbol;
|
|
3
|
+
declare const createEndpoint: unique symbol;
|
|
4
|
+
declare const releaseProxy: unique symbol;
|
|
5
|
+
declare const finalizer: unique symbol;
|
|
6
|
+
/**
|
|
7
|
+
* Interface of values that were marked to be proxied with `comlink.proxy()`.
|
|
8
|
+
* Can also be implemented by classes.
|
|
9
|
+
*/
|
|
10
|
+
interface ProxyMarked {
|
|
11
|
+
[proxyMarker]: true;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Takes a type and wraps it in a Promise, if it not already is one.
|
|
15
|
+
* This is to avoid `Promise<Promise<T>>`.
|
|
16
|
+
*
|
|
17
|
+
* This is the inverse of `Unpromisify<T>`.
|
|
18
|
+
*/
|
|
19
|
+
type Promisify<T> = T extends Promise<unknown> ? T : Promise<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Takes a type that may be Promise and unwraps the Promise type.
|
|
22
|
+
* If `P` is not a Promise, it returns `P`.
|
|
23
|
+
*
|
|
24
|
+
* This is the inverse of `Promisify<T>`.
|
|
25
|
+
*/
|
|
26
|
+
type Unpromisify<P> = P extends Promise<infer T> ? T : P;
|
|
27
|
+
/**
|
|
28
|
+
* Takes the raw type of a remote property and returns the type that is visible to the local thread on the proxy.
|
|
29
|
+
*
|
|
30
|
+
* Note: This needs to be its own type alias, otherwise it will not distribute over unions.
|
|
31
|
+
* See https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types
|
|
32
|
+
*/
|
|
33
|
+
type RemoteProperty<T> = T extends Function | ProxyMarked ? Remote<T> : Promisify<T>;
|
|
34
|
+
/**
|
|
35
|
+
* Takes the raw type of a property as a remote thread would see it through a proxy (e.g. when passed in as a function
|
|
36
|
+
* argument) and returns the type that the local thread has to supply.
|
|
37
|
+
*
|
|
38
|
+
* This is the inverse of `RemoteProperty<T>`.
|
|
39
|
+
*
|
|
40
|
+
* Note: This needs to be its own type alias, otherwise it will not distribute over unions. See
|
|
41
|
+
* https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types
|
|
42
|
+
*/
|
|
43
|
+
type LocalProperty<T> = T extends Function | ProxyMarked ? Local<T> : Unpromisify<T>;
|
|
44
|
+
/**
|
|
45
|
+
* Proxies `T` if it is a `ProxyMarked`, clones it otherwise (as handled by structured cloning and transfer handlers).
|
|
46
|
+
*/
|
|
47
|
+
type ProxyOrClone<T> = T extends ProxyMarked ? Remote<T> : T;
|
|
48
|
+
/**
|
|
49
|
+
* Inverse of `ProxyOrClone<T>`.
|
|
50
|
+
*/
|
|
51
|
+
type UnproxyOrClone<T> = T extends RemoteObject<ProxyMarked> ? Local<T> : T;
|
|
52
|
+
/**
|
|
53
|
+
* Takes the raw type of a remote object in the other thread and returns the type as it is visible to the local thread
|
|
54
|
+
* when proxied with `Comlink.proxy()`.
|
|
55
|
+
*
|
|
56
|
+
* This does not handle call signatures, which is handled by the more general `Remote<T>` type.
|
|
57
|
+
*
|
|
58
|
+
* @template T The raw type of a remote object as seen in the other thread.
|
|
59
|
+
*/
|
|
60
|
+
type RemoteObject<T> = { [P in keyof T]: RemoteProperty<T[P]>; };
|
|
61
|
+
/**
|
|
62
|
+
* Takes the type of an object as a remote thread would see it through a proxy (e.g. when passed in as a function
|
|
63
|
+
* argument) and returns the type that the local thread has to supply.
|
|
64
|
+
*
|
|
65
|
+
* This does not handle call signatures, which is handled by the more general `Local<T>` type.
|
|
66
|
+
*
|
|
67
|
+
* This is the inverse of `RemoteObject<T>`.
|
|
68
|
+
*
|
|
69
|
+
* @template T The type of a proxied object.
|
|
70
|
+
*/
|
|
71
|
+
type LocalObject<T> = { [P in keyof T]: LocalProperty<T[P]>; };
|
|
72
|
+
/**
|
|
73
|
+
* Additional special comlink methods available on each proxy returned by `Comlink.wrap()`.
|
|
74
|
+
*/
|
|
75
|
+
interface ProxyMethods {
|
|
76
|
+
[createEndpoint]: () => Promise<MessagePort>;
|
|
77
|
+
[releaseProxy]: () => void;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Takes the raw type of a remote object, function or class in the other thread and returns the type as it is visible to
|
|
81
|
+
* the local thread from the proxy return value of `Comlink.wrap()` or `Comlink.proxy()`.
|
|
82
|
+
*/
|
|
83
|
+
type Remote<T> = RemoteObject<T> & (T extends ((...args: infer TArguments) => infer TReturn) ? (...args: { [I in keyof TArguments]: UnproxyOrClone<TArguments[I]>; }) => Promisify<ProxyOrClone<Unpromisify<TReturn>>> : unknown) & (T extends {
|
|
84
|
+
new (...args: infer TArguments): infer TInstance;
|
|
85
|
+
} ? {
|
|
86
|
+
new (...args: { [I in keyof TArguments]: UnproxyOrClone<TArguments[I]>; }): Promisify<Remote<TInstance>>;
|
|
87
|
+
} : unknown) & ProxyMethods;
|
|
88
|
+
/**
|
|
89
|
+
* Expresses that a type can be either a sync or async.
|
|
90
|
+
*/
|
|
91
|
+
type MaybePromise<T> = Promise<T> | T;
|
|
92
|
+
/**
|
|
93
|
+
* Takes the raw type of a remote object, function or class as a remote thread would see it through a proxy (e.g. when
|
|
94
|
+
* passed in as a function argument) and returns the type the local thread has to supply.
|
|
95
|
+
*
|
|
96
|
+
* This is the inverse of `Remote<T>`. It takes a `Remote<T>` and returns its original input `T`.
|
|
97
|
+
*/
|
|
98
|
+
type Local<T> = Omit<LocalObject<T>, keyof ProxyMethods> & (T extends ((...args: infer TArguments) => infer TReturn) ? (...args: { [I in keyof TArguments]: ProxyOrClone<TArguments[I]>; }) => MaybePromise<UnproxyOrClone<Unpromisify<TReturn>>> : unknown) & (T extends {
|
|
99
|
+
new (...args: infer TArguments): infer TInstance;
|
|
100
|
+
} ? {
|
|
101
|
+
new (...args: { [I in keyof TArguments]: ProxyOrClone<TArguments[I]>; }): MaybePromise<Local<Unpromisify<TInstance>>>;
|
|
102
|
+
} : unknown);
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region gen/wasm/trylimbo_sdk_verifier.d.ts
|
|
105
|
+
/** Sync ranged reader for Node.js (backed by `fs.readSync`). */
|
|
106
|
+
interface RangeSource {
|
|
107
|
+
length: number;
|
|
108
|
+
readAt: (offset: number, length: number) => Uint8Array;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* A C2PA soft binding: an algorithm id (from the C2PA soft-binding algorithm
|
|
112
|
+
* list, e.g. `io.iscc.v0`) plus its algorithm-specific value (the `ISCC:…` code,
|
|
113
|
+
* a watermark token, …). The signer embeds it as a `c2pa.soft-binding` assertion
|
|
114
|
+
* and indexes it, so a transcoded copy whose exact content hash no longer
|
|
115
|
+
* matches still recovers the manifest from the registry.
|
|
116
|
+
*/
|
|
117
|
+
interface SoftBinding {
|
|
118
|
+
/**
|
|
119
|
+
* C2PA soft-binding algorithm id, e.g. `io.iscc.v0`.
|
|
120
|
+
*/
|
|
121
|
+
alg: string;
|
|
122
|
+
/**
|
|
123
|
+
* Algorithm-specific binding value: the canonical string the algorithm
|
|
124
|
+
* produces (an `ISCC:…` code, a watermark token). Its UTF-8 bytes are what
|
|
125
|
+
* the registry lookup base64-encodes.
|
|
126
|
+
*/
|
|
127
|
+
value: string;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A session signing key from the init manifest\'s roster (spec §19.4.4).
|
|
131
|
+
*/
|
|
132
|
+
interface SessionKeySummary {
|
|
133
|
+
/**
|
|
134
|
+
* Identifier of the session signing key.
|
|
135
|
+
*/
|
|
136
|
+
keyId: Uint8Array;
|
|
137
|
+
/**
|
|
138
|
+
* The session key\'s public half (SEC1-encoded bytes).
|
|
139
|
+
*/
|
|
140
|
+
publicKey: Uint8Array;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* C2PA validation state of a manifest (spec §14.3).
|
|
144
|
+
*/
|
|
145
|
+
type ValidationState = "Invalid" | "Valid" | "Trusted";
|
|
146
|
+
/**
|
|
147
|
+
* Construction options for [`AssetVerifier::new`] (and the `AssetVerifier.create` JS
|
|
148
|
+
* binding). `trust_c2pa_anchors` defaults to `true` when omitted.
|
|
149
|
+
*
|
|
150
|
+
* One definition, all lanes: `#[binding]` derives the shapes directly here:
|
|
151
|
+
* tsify (camelCase, optional fields) on wasm, a `uniffi::Record` on the native
|
|
152
|
+
* `ffi` build, so there is no per-lane DTO copy. Off both lanes it is a plain struct.
|
|
153
|
+
*/
|
|
154
|
+
interface AssetVerifierOptions {
|
|
155
|
+
/**
|
|
156
|
+
* The registry to recover from. Omit for a verifier that only checks embedded manifests.
|
|
157
|
+
*/
|
|
158
|
+
registry?: RegistryOptions;
|
|
159
|
+
/**
|
|
160
|
+
* PEM trust anchors for the caller\'s own issuers.
|
|
161
|
+
*/
|
|
162
|
+
trustAnchors: string[];
|
|
163
|
+
/**
|
|
164
|
+
* Also trust the bundled official C2PA anchors on top of `trust_anchors`.
|
|
165
|
+
* Defaults to `true`; set `false` to trust only `trust_anchors`.
|
|
166
|
+
*/
|
|
167
|
+
trustC2paAnchors?: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Issuer DIDs whose CAWG identity (ICA) credentials count as validated, matched
|
|
170
|
+
* exactly against the credential issuer. Omitted or empty trusts no issuer: every
|
|
171
|
+
* identity assertion then reports `cawg.ica.untrusted_issuer` and withholds
|
|
172
|
+
* `cawg.ica.credential_valid`, which leaves the manifest\'s own validity untouched.
|
|
173
|
+
*/
|
|
174
|
+
trustedIcaIssuers?: string[];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Construction options for [`StreamVerifier::new`] (and the `StreamVerifier.create`
|
|
178
|
+
* JS binding). `trust_c2pa_anchors` defaults to `true` when omitted.
|
|
179
|
+
*
|
|
180
|
+
* `#[binding]` derives the wasm shape (`trustC2paAnchors` camelCase, optional) and,
|
|
181
|
+
* with `ffi`, a `uniffi::Record` for the native `StreamVerifier.create` binding, so there
|
|
182
|
+
* is no per-lane DTO copy. Off both lanes it is a plain struct.
|
|
183
|
+
*/
|
|
184
|
+
interface StreamVerifierOptions {
|
|
185
|
+
/**
|
|
186
|
+
* PEM trust anchors for the caller\'s own issuers.
|
|
187
|
+
*/
|
|
188
|
+
trustAnchors: string[];
|
|
189
|
+
/**
|
|
190
|
+
* Also trust the bundled official C2PA anchors on top of `trust_anchors`.
|
|
191
|
+
* Defaults to `true`; set `false` to trust only `trust_anchors`.
|
|
192
|
+
*/
|
|
193
|
+
trustC2paAnchors?: boolean;
|
|
194
|
+
/**
|
|
195
|
+
* Issuer DIDs whose CAWG identity (ICA) credentials count as validated, matched
|
|
196
|
+
* exactly against the credential issuer. Omitted or empty trusts no issuer: an
|
|
197
|
+
* identity assertion on the init segment\'s manifest then reports
|
|
198
|
+
* `cawg.ica.untrusted_issuer` and withholds `cawg.ica.credential_valid`.
|
|
199
|
+
*/
|
|
200
|
+
trustedIcaIssuers?: string[];
|
|
201
|
+
/**
|
|
202
|
+
* How far a segment\'s timestamp may sit from wall-clock before it is rejected as
|
|
203
|
+
* skewed. Defaults to [`DEFAULT_SEGMENT_SKEW_TOLERANCE_SECS`]. A deployment whose
|
|
204
|
+
* encoder clock drifts further than that needs this rather than a fork.
|
|
205
|
+
*/
|
|
206
|
+
segmentSkewToleranceSecs?: number;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* How far a recovery may go, which decides what leaves the caller.
|
|
210
|
+
*
|
|
211
|
+
* Separate from [`RecoveryPolicy`], which decides *when* a recovery runs: one names the trigger
|
|
212
|
+
* and the other the reach, and crossing them is what the two enums exist to keep legible.
|
|
213
|
+
*/
|
|
214
|
+
type RegistryQueries = "derived" | "derivedThenContent";
|
|
215
|
+
/**
|
|
216
|
+
* One C2PA validation status entry (spec §15.3).
|
|
217
|
+
*/
|
|
218
|
+
interface ValidationCode {
|
|
219
|
+
/**
|
|
220
|
+
* C2PA validation status string (e.g. `signingCredential.trusted`).
|
|
221
|
+
*/
|
|
222
|
+
code: string;
|
|
223
|
+
kind: ValidationCodeKind;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* One `verify` credential: the c2pa `ManifestStore`, where it came from, and whether the
|
|
227
|
+
* asset\'s own fingerprint backs it up.
|
|
228
|
+
*/
|
|
229
|
+
interface FoundCredential {
|
|
230
|
+
/**
|
|
231
|
+
* The bytes behind every thumbnail the manifests reference, by that reference\'s
|
|
232
|
+
* `identifier`: each manifest\'s claim thumbnail and each ingredient\'s. The manifests state
|
|
233
|
+
* identifiers and no images, so this is what a chain draws from.
|
|
234
|
+
*/
|
|
235
|
+
thumbnails: Record<string, Uint8Array>;
|
|
236
|
+
/**
|
|
237
|
+
* Where this credential came from. See [`CredentialOrigin`].
|
|
238
|
+
*/
|
|
239
|
+
origin: CredentialOrigin;
|
|
240
|
+
manifest: import('@contentauth/c2pa-types').ManifestStore;
|
|
241
|
+
/**
|
|
242
|
+
* Whether the asset\'s own fingerprint backs up a mark that led here (C2PA 2.4 1.2.2.3).
|
|
243
|
+
*/
|
|
244
|
+
fingerprintCheck: FingerprintCheck;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Outcome of validating a media segment against its stream\'s init.
|
|
248
|
+
*/
|
|
249
|
+
interface MediaValidation {
|
|
250
|
+
valid: boolean;
|
|
251
|
+
codes: ValidationCode[];
|
|
252
|
+
keyId: Uint8Array;
|
|
253
|
+
timing: SegmentTiming;
|
|
254
|
+
manifestId: string;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Outcome of validating a stream\'s init segment.
|
|
258
|
+
*/
|
|
259
|
+
interface InitValidation {
|
|
260
|
+
state: ValidationState;
|
|
261
|
+
codes: ValidationCode[];
|
|
262
|
+
manifest: import('@contentauth/c2pa-types').ManifestStore;
|
|
263
|
+
sessionKeys: SessionKeySummary[];
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Result of `StreamValidation.validate`, discriminated by `kind`.
|
|
267
|
+
*/
|
|
268
|
+
type SegmentValidation = ({
|
|
269
|
+
kind: "init";
|
|
270
|
+
} & InitValidation) | ({
|
|
271
|
+
kind: "media";
|
|
272
|
+
} & MediaValidation) | {
|
|
273
|
+
kind: "unknown";
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Timing facts carried by a media segment\'s container.
|
|
277
|
+
*/
|
|
278
|
+
interface SegmentTiming {
|
|
279
|
+
/**
|
|
280
|
+
* Media segment sequence number (exact below 2^53).
|
|
281
|
+
*/
|
|
282
|
+
sequenceNumber: number;
|
|
283
|
+
/**
|
|
284
|
+
* MP4 timescale (ticks per second) for this segment\'s timing, if present.
|
|
285
|
+
*/
|
|
286
|
+
timescale?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Segment duration in seconds, if the container reports it.
|
|
289
|
+
*/
|
|
290
|
+
eventDurationSecs?: number;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* When [`AssetVerifier::verify_asset`] queries the registry.
|
|
294
|
+
*/
|
|
295
|
+
type RecoveryPolicy = "whenMissing" | "always";
|
|
296
|
+
/**
|
|
297
|
+
* Where the registry is, when to query it, and how far. One value rather than an endpoint beside
|
|
298
|
+
* loose flags, so a policy cannot be configured on a verifier that has nowhere to apply it.
|
|
299
|
+
*/
|
|
300
|
+
interface RegistryOptions {
|
|
301
|
+
/**
|
|
302
|
+
* Soft Binding Resolution API base URL (`https://registry.trylimbo.com`).
|
|
303
|
+
*/
|
|
304
|
+
url: string;
|
|
305
|
+
/**
|
|
306
|
+
* Defaults to [`RecoveryPolicy::WhenMissing`].
|
|
307
|
+
*/
|
|
308
|
+
recovery?: RecoveryPolicy;
|
|
309
|
+
/**
|
|
310
|
+
* Defaults to [`RegistryQueries::DerivedThenContent`].
|
|
311
|
+
*/
|
|
312
|
+
queries?: RegistryQueries;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Whether a code is a success, an informational note, or a failure.
|
|
316
|
+
*/
|
|
317
|
+
type ValidationCodeKind = "success" | "informational" | "failure";
|
|
318
|
+
/**
|
|
319
|
+
* [`crate::asset::CredentialOrigin`] as JS sees it: a tagged union, since each way of finding a
|
|
320
|
+
* credential carries different evidence. Lane-local for the same reason [`FingerprintCheck`] is: a
|
|
321
|
+
* tag layout is what `#[binding(wasm)]` declines to express.
|
|
322
|
+
*/
|
|
323
|
+
type CredentialOrigin = {
|
|
324
|
+
kind: "embedded";
|
|
325
|
+
} | {
|
|
326
|
+
kind: "recoveredByFingerprint";
|
|
327
|
+
binding: SoftBinding;
|
|
328
|
+
registryScore: number | undefined;
|
|
329
|
+
} | {
|
|
330
|
+
kind: "recoveredByWatermark";
|
|
331
|
+
binding: SoftBinding;
|
|
332
|
+
registryScore: number | undefined;
|
|
333
|
+
} | {
|
|
334
|
+
kind: "recoveredByContent";
|
|
335
|
+
discoveries: ContentBindingEvidence[];
|
|
336
|
+
};
|
|
337
|
+
/**
|
|
338
|
+
* [`crate::asset::FingerprintCheck`] as JS sees it: a tagged union, since `compared` carries a
|
|
339
|
+
* measurement the other two do not. Lane-local rather than `#[binding(wasm)]` on the core,
|
|
340
|
+
* because a tag layout is exactly what that macro declines to express.
|
|
341
|
+
*/
|
|
342
|
+
type FingerprintCheck = {
|
|
343
|
+
kind: "notNeeded";
|
|
344
|
+
} | {
|
|
345
|
+
kind: "nothingToCompare";
|
|
346
|
+
} | {
|
|
347
|
+
kind: "unsupported";
|
|
348
|
+
algorithm: string;
|
|
349
|
+
} | {
|
|
350
|
+
kind: "indeterminate";
|
|
351
|
+
} | {
|
|
352
|
+
kind: "compared";
|
|
353
|
+
score: number;
|
|
354
|
+
};
|
|
355
|
+
interface AssetVerification {
|
|
356
|
+
credentials: FoundCredential[];
|
|
357
|
+
recovery: RecoverySummary;
|
|
358
|
+
goldenComparison: GoldenComparison;
|
|
359
|
+
}
|
|
360
|
+
interface ContentBindingEvidence {
|
|
361
|
+
algorithm: string;
|
|
362
|
+
class: ContentBindingClass;
|
|
363
|
+
hint: SoftBinding | undefined;
|
|
364
|
+
registryScore: number | undefined;
|
|
365
|
+
}
|
|
366
|
+
interface RecoveryIssue {
|
|
367
|
+
kind: RecoveryIssueKind;
|
|
368
|
+
manifestId: string | undefined;
|
|
369
|
+
message: string;
|
|
370
|
+
}
|
|
371
|
+
interface RecoverySummary {
|
|
372
|
+
status: RecoveryStatus;
|
|
373
|
+
bestCredentialIndex: number | undefined;
|
|
374
|
+
issues: RecoveryIssue[];
|
|
375
|
+
}
|
|
376
|
+
type ContentBindingClass = "fingerprint" | "watermark";
|
|
377
|
+
type GoldenComparison = {
|
|
378
|
+
kind: "notRequested";
|
|
379
|
+
} | {
|
|
380
|
+
kind: "noEmbeddedManifest";
|
|
381
|
+
} | {
|
|
382
|
+
kind: "noRecoveredManifest";
|
|
383
|
+
} | {
|
|
384
|
+
kind: "matches";
|
|
385
|
+
recoveredIndex: number;
|
|
386
|
+
} | {
|
|
387
|
+
kind: "differs";
|
|
388
|
+
recoveredIndex: number;
|
|
389
|
+
} | {
|
|
390
|
+
kind: "indeterminate";
|
|
391
|
+
recoveredIndex: number | undefined;
|
|
392
|
+
};
|
|
393
|
+
type RecoveryIssueKind = "binder" | "bindingQuery" | "queryRefused" | "contentQuery" | "capabilities" | "contentTooLarge" | "candidateFetch" | "candidateValidation" | "resourceLimit";
|
|
394
|
+
type RecoveryStatus = "notRequested" | "notFound" | "recovered" | "incomplete";
|
|
395
|
+
declare class AssetVerifier {
|
|
396
|
+
private constructor();
|
|
397
|
+
free(): void;
|
|
398
|
+
[Symbol.dispose](): void;
|
|
399
|
+
/**
|
|
400
|
+
* # Errors
|
|
401
|
+
*
|
|
402
|
+
* Throws `TRUST_CONFIG_INVALID` when the trust anchors are invalid.
|
|
403
|
+
*/
|
|
404
|
+
static create(options: AssetVerifierOptions): AssetVerifier;
|
|
405
|
+
/**
|
|
406
|
+
* Verify an asset against the configured trust anchors. `binders` compose
|
|
407
|
+
* soft-binding recovery after the embedded pass, tried in order,
|
|
408
|
+
* first hit wins; pass `[]` to proceed directly to registry `byContent` recovery.
|
|
409
|
+
*
|
|
410
|
+
* Reads the C2PA-native formats. A container format (MXF) is plugin-backed, and plugins
|
|
411
|
+
* are native, so a master is verified through the native SDK.
|
|
412
|
+
*
|
|
413
|
+
* # Errors
|
|
414
|
+
*
|
|
415
|
+
* Throws on a malformed `input`, a registry (or binder) failure, or a validation
|
|
416
|
+
* failure.
|
|
417
|
+
*/
|
|
418
|
+
verify(input: RangeSource, binders: Binder[]): Promise<AssetVerification>;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* A soft-binding binder a client runs itself. Build with `Binder.iscc()` or
|
|
422
|
+
* `Binder.held(binding)`, and pass a list to `verify`.
|
|
423
|
+
*
|
|
424
|
+
* Vendor watermark detection is registry-side in this SDK: configured detectors participate in
|
|
425
|
+
* `verify` through `byContent`, while `Binder.held` covers values already available to the caller.
|
|
426
|
+
*/
|
|
427
|
+
declare class Binder {
|
|
428
|
+
private constructor();
|
|
429
|
+
free(): void;
|
|
430
|
+
[Symbol.dispose](): void;
|
|
431
|
+
/**
|
|
432
|
+
* Derive this binder's binding standalone; `undefined` when it finds none.
|
|
433
|
+
* Input is a `RangeSource` (format inferred from content when omitted).
|
|
434
|
+
*
|
|
435
|
+
* # Errors
|
|
436
|
+
*
|
|
437
|
+
* Throws on malformed or unreadable input.
|
|
438
|
+
*/
|
|
439
|
+
derive(content: RangeSource, format?: string | null): Promise<SoftBinding | undefined>;
|
|
440
|
+
/**
|
|
441
|
+
* A binder contributing a binding you already hold (e.g. an out-of-band video ISCC).
|
|
442
|
+
*/
|
|
443
|
+
static held(binding: SoftBinding): Binder;
|
|
444
|
+
/**
|
|
445
|
+
* Local ISCC Image-Code for supported image formats.
|
|
446
|
+
*/
|
|
447
|
+
static iscc(): Binder;
|
|
448
|
+
}
|
|
449
|
+
declare function C2PA_TRUST_LIST(): string;
|
|
450
|
+
declare function C2PA_TSA_TRUST_LIST(): string;
|
|
451
|
+
declare function DEV_CA(): string;
|
|
452
|
+
/**
|
|
453
|
+
* One stream being validated. It owns the session keys and manifest ids its init segments
|
|
454
|
+
* advertised, so releasing the stream is dropping this object.
|
|
455
|
+
*/
|
|
456
|
+
declare class StreamValidation {
|
|
457
|
+
private constructor();
|
|
458
|
+
free(): void;
|
|
459
|
+
[Symbol.dispose](): void;
|
|
460
|
+
/**
|
|
461
|
+
* Everything this stream's init segments have registered, as CBOR for another node to
|
|
462
|
+
* `StreamVerifier.resume` from.
|
|
463
|
+
*
|
|
464
|
+
* The one piece of stream state that leaves the SDK, and only because a clustered
|
|
465
|
+
* verifier needs it: the init URL is overwritten on rotation, so a node joining during
|
|
466
|
+
* the overlap cannot rebuild the previous key by refetching. One value, produced once
|
|
467
|
+
* and consumed once. Not a store.
|
|
468
|
+
*
|
|
469
|
+
* # Errors
|
|
470
|
+
*
|
|
471
|
+
* Throws an `SdkError` (`STREAM_INVALID`) when a registered session key cannot be
|
|
472
|
+
* re-encoded.
|
|
473
|
+
*/
|
|
474
|
+
export(): Uint8Array;
|
|
475
|
+
/**
|
|
476
|
+
* Validate a stream segment.
|
|
477
|
+
*
|
|
478
|
+
* # Errors
|
|
479
|
+
*
|
|
480
|
+
* Throws an `SdkError` on parse or signature failure, or when a media segment arrives
|
|
481
|
+
* before any init was processed for the stream.
|
|
482
|
+
*/
|
|
483
|
+
validate(data: RangeSource): Promise<SegmentValidation>;
|
|
484
|
+
}
|
|
485
|
+
declare class StreamVerifier {
|
|
486
|
+
private constructor();
|
|
487
|
+
free(): void;
|
|
488
|
+
[Symbol.dispose](): void;
|
|
489
|
+
/**
|
|
490
|
+
* Create a `StreamVerifier`.
|
|
491
|
+
*
|
|
492
|
+
* # Errors
|
|
493
|
+
*
|
|
494
|
+
* Throws an `SdkError` (`TRUST_CONFIG_INVALID`) when the trust anchors are invalid.
|
|
495
|
+
*/
|
|
496
|
+
static create(options: StreamVerifierOptions): StreamVerifier;
|
|
497
|
+
/**
|
|
498
|
+
* Open `stream_id` for validation, handing back a `StreamValidation` to feed segments to.
|
|
499
|
+
*
|
|
500
|
+
* No I/O: the handle carries the id so it cannot be mistyped or confused with another
|
|
501
|
+
* stream's, and classification still happens per segment. Opening one id twice hands
|
|
502
|
+
* back the same live session, so a component that remounts keeps the state its earlier
|
|
503
|
+
* handle accumulated.
|
|
504
|
+
*/
|
|
505
|
+
open(stream_id: string): StreamValidation;
|
|
506
|
+
/**
|
|
507
|
+
* Open `stream_id` on the state another node exported, merged into whatever this one
|
|
508
|
+
* holds for that id already.
|
|
509
|
+
*
|
|
510
|
+
* # Errors
|
|
511
|
+
*
|
|
512
|
+
* Throws an `SdkError` (`STREAM_INVALID`) when `state` is not a value
|
|
513
|
+
* `StreamValidation.export` produced, or carries a version this SDK no longer reads.
|
|
514
|
+
*/
|
|
515
|
+
resume(stream_id: string, state: Uint8Array): StreamValidation;
|
|
516
|
+
}
|
|
517
|
+
//#endregion
|
|
518
|
+
//#region src/worker-thread.d.ts
|
|
519
|
+
/**
|
|
520
|
+
* An asset as it crosses a thread. A `Blob` (a `File` from an `<input>`, a `Response.blob()`) is a
|
|
521
|
+
* handle: nothing is copied to send it and nothing is resident to hold it, so it has no size
|
|
522
|
+
* ceiling. Bytes are copied once, and are bounded by what the caller already holds in memory.
|
|
523
|
+
*/
|
|
524
|
+
type Asset = Blob | Uint8Array | ArrayBuffer;
|
|
525
|
+
/**
|
|
526
|
+
* A `Binder`, spelled as data: `Binder.iscc()` and `Binder.held(binding)` in the order the direct
|
|
527
|
+
* import declares them.
|
|
528
|
+
*/
|
|
529
|
+
type BinderSpec = {
|
|
530
|
+
readonly kind: "iscc";
|
|
531
|
+
} | {
|
|
532
|
+
readonly kind: "held";
|
|
533
|
+
readonly binding: SoftBinding;
|
|
534
|
+
};
|
|
535
|
+
/**
|
|
536
|
+
* A wasm object held in this thread on the caller's behalf.
|
|
537
|
+
*
|
|
538
|
+
* The subclasses exist to convert arguments, which is the one job a transfer handler cannot take
|
|
539
|
+
* over: a handler rewrites the value on the wire but not its declared type, so `Remote<Sdk>` would
|
|
540
|
+
* go on telling the caller to pass the `RangeSource` that is the whole reason there is a worker.
|
|
541
|
+
* A method that takes an `Asset` and converts it says the same thing in the type the caller reads.
|
|
542
|
+
*
|
|
543
|
+
* The finalizer is the whole lifetime. Comlink registers every proxy it hands out with a
|
|
544
|
+
* `FinalizationRegistry`, so dropping the handle over there frees the wasm object here.
|
|
545
|
+
*/
|
|
546
|
+
declare abstract class Handle<T extends {
|
|
547
|
+
free(): void;
|
|
548
|
+
}> {
|
|
549
|
+
protected readonly inner: T;
|
|
550
|
+
constructor(inner: T);
|
|
551
|
+
[finalizer](): void;
|
|
552
|
+
}
|
|
553
|
+
declare class AssetVerifierHandle extends Handle<AssetVerifier> {
|
|
554
|
+
verify(asset: Asset, binders?: readonly BinderSpec[]): Promise<AssetVerification>;
|
|
555
|
+
}
|
|
556
|
+
/** One stream being validated. Dropping the handle releases the session it accumulated. */
|
|
557
|
+
declare class StreamValidationHandle extends Handle<StreamValidation> {
|
|
558
|
+
validate(segment: Asset): Promise<SegmentValidation>;
|
|
559
|
+
export(): Uint8Array;
|
|
560
|
+
}
|
|
561
|
+
declare class StreamVerifierHandle extends Handle<StreamVerifier> {
|
|
562
|
+
open(streamId: string): StreamValidationHandle & ProxyMarked;
|
|
563
|
+
resume(streamId: string, state: Uint8Array): StreamValidationHandle & ProxyMarked;
|
|
564
|
+
}
|
|
565
|
+
/** The module's own surface, name for name with the direct import. */
|
|
566
|
+
declare const sdk: {
|
|
567
|
+
/**
|
|
568
|
+
* Compile and instantiate. `connect()` awaits this before handing the caller its proxy, so no
|
|
569
|
+
* other call can find an uninstantiated module. Compiles once however often it is called.
|
|
570
|
+
*/
|
|
571
|
+
init(module?: BufferSource | WebAssembly.Module): Promise<void>;
|
|
572
|
+
AssetVerifier: {
|
|
573
|
+
create: (options: AssetVerifierOptions) => AssetVerifierHandle & ProxyMarked;
|
|
574
|
+
} & ProxyMarked;
|
|
575
|
+
StreamVerifier: {
|
|
576
|
+
create: (options: StreamVerifierOptions) => StreamVerifierHandle & ProxyMarked;
|
|
577
|
+
} & ProxyMarked;
|
|
578
|
+
Binder: {
|
|
579
|
+
/**
|
|
580
|
+
* Derive one binder's binding standalone. The binder is built, used and dropped here, so there
|
|
581
|
+
* is no handle to keep: what the caller wants back is the binding.
|
|
582
|
+
*/
|
|
583
|
+
derive: (spec: BinderSpec, content: Asset, format?: string) => Promise<SoftBinding | undefined>;
|
|
584
|
+
} & ProxyMarked;
|
|
585
|
+
/**
|
|
586
|
+
* Read a detached manifest store. Contents, not a verdict: with no asset there is no hard binding
|
|
587
|
+
* to check, so the store's validation fields state nothing this established.
|
|
588
|
+
*/
|
|
589
|
+
parse(manifest: Asset): Promise<import("@contentauth/c2pa-types").ManifestStore>;
|
|
590
|
+
/**
|
|
591
|
+
* The bytes behind one resource the store references, by the `identifier` on its reference: any
|
|
592
|
+
* manifest's claim thumbnail, and any ingredient's.
|
|
593
|
+
*/
|
|
594
|
+
resource(manifest: Asset, uri: string): Promise<Uint8Array<ArrayBufferLike> | undefined>;
|
|
595
|
+
/**
|
|
596
|
+
* Every thumbnail the store references, by the identifier it references them under. One parse
|
|
597
|
+
* and one thread hop for the whole set, where `resource` pays both per call.
|
|
598
|
+
*/
|
|
599
|
+
thumbnails(manifest: Asset): Promise<Record<string, Uint8Array<ArrayBufferLike>>>;
|
|
600
|
+
C2PA_TRUST_LIST: typeof C2PA_TRUST_LIST;
|
|
601
|
+
C2PA_TSA_TRUST_LIST: typeof C2PA_TSA_TRUST_LIST;
|
|
602
|
+
DEV_CA: typeof DEV_CA;
|
|
603
|
+
close(): void;
|
|
604
|
+
};
|
|
605
|
+
/** What the caller's thread holds a `Comlink.Remote` of. */
|
|
606
|
+
type Sdk = typeof sdk;
|
|
607
|
+
//#endregion
|
|
608
|
+
//#region src/worker.d.ts
|
|
609
|
+
interface ConnectOptions {
|
|
610
|
+
/**
|
|
611
|
+
* Already-fetched `.wasm` bytes, or a compiled module, for where the worker cannot fetch beside
|
|
612
|
+
* itself: a bundler that rewrites the URL, or a page that has the binary in hand already.
|
|
613
|
+
*/
|
|
614
|
+
readonly module?: BufferSource | WebAssembly.Module;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Start the SDK in a Worker and wait for its module to instantiate.
|
|
618
|
+
*
|
|
619
|
+
* Handles taken from the returned SDK (a verifier, a stream, a validation) free themselves when they
|
|
620
|
+
* are collected, so the only lifetime to hold is the SDK's own: `close()` ends the thread.
|
|
621
|
+
*/
|
|
622
|
+
declare function connect({ module }?: ConnectOptions): Promise<Remote<Sdk>>;
|
|
623
|
+
//#endregion
|
|
624
|
+
export { ConnectOptions, connect };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { i as wrap } from "./comlink.js";
|
|
2
|
+
//#region src/worker.ts
|
|
3
|
+
/**
|
|
4
|
+
* Start the SDK in a Worker and wait for its module to instantiate.
|
|
5
|
+
*
|
|
6
|
+
* Handles taken from the returned SDK (a verifier, a stream, a validation) free themselves when they
|
|
7
|
+
* are collected, so the only lifetime to hold is the SDK's own: `close()` ends the thread.
|
|
8
|
+
*/
|
|
9
|
+
async function connect({ module } = {}) {
|
|
10
|
+
const worker = new Worker(new URL("./worker-thread.js", import.meta.url), { type: "module" });
|
|
11
|
+
const sdk = wrap(worker);
|
|
12
|
+
try {
|
|
13
|
+
await sdk.init(module);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
worker.terminate();
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
return sdk;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { connect };
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trylimbo/sdk-verifier-wasm",
|
|
3
|
+
"version": "0.1.0-canary.100",
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/limboai/limbo-integrity.git",
|
|
8
|
+
"directory": "host/verifier/node/wasm"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"types": "./gen/wasm/trylimbo_sdk_verifier.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./gen/wasm/trylimbo_sdk_verifier.d.ts",
|
|
15
|
+
"default": "./gen/wasm/trylimbo_sdk_verifier.js"
|
|
16
|
+
},
|
|
17
|
+
"./wasm": "./gen/wasm/trylimbo_sdk_verifier_bg.wasm",
|
|
18
|
+
"./worker": {
|
|
19
|
+
"types": "./gen/wasm/worker.d.ts",
|
|
20
|
+
"default": "./gen/wasm/worker.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"gen/wasm/**/*"
|
|
25
|
+
],
|
|
26
|
+
"trylimbo": {
|
|
27
|
+
"lane": "wasm",
|
|
28
|
+
"role": "sdk",
|
|
29
|
+
"rust": {
|
|
30
|
+
"dir": "api/sdk/verifier"
|
|
31
|
+
},
|
|
32
|
+
"toolchain": "wasm-bindgen"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@contentauth/c2pa-types": "^0.7.4"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"comlink": "4.4.2",
|
|
42
|
+
"typescript": "^7.0.2"
|
|
43
|
+
},
|
|
44
|
+
"stableVersion": "0.0.8"
|
|
45
|
+
}
|