@svta/cml-c2pa 1.0.0 → 1.1.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/README.md +20 -6
- package/dist/index.d.ts +121 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +418 -108
- package/dist/index.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
C2PA (Coalition for Content Provenance and Authenticity) live video validation for BMFF/MP4 containers.
|
|
4
4
|
|
|
5
|
-
Supports
|
|
5
|
+
Supports the segment validation methods defined in the C2PA specification:
|
|
6
6
|
|
|
7
|
-
- **§19.3
|
|
8
|
-
- **§19.4
|
|
7
|
+
- **§19.3 Per-segment C2PA Manifest Box**: each segment embeds a full C2PA manifest with COSE signature
|
|
8
|
+
- **§19.4 Verifiable Segment Info (VSI/EMSG)**: the init segment carries the manifest and session keys; each media segment carries a lightweight signed EMSG box
|
|
9
|
+
- **§15.12.2 / §18.6 VOD Merkle**: for on-demand fragmented MP4 assets, the init manifest stores one Merkle tree row per track, and each media segment carries its own leaf hash and proof
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
## Installation
|
|
@@ -55,11 +56,24 @@ const segmentBytes = new Uint8Array(await fetch(segmentUrl).then(r => r.arrayBuf
|
|
|
55
56
|
const validated = await validateC2paSegment(segmentBytes, init.sessionKeys)
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
### VOD Merkle method (init segment + media segments)
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { validateC2paInitSegment, validateC2paMerkleSegment } from '@svta/cml-c2pa'
|
|
63
|
+
|
|
64
|
+
const initBytes = new Uint8Array(await fetch(initUrl).then(r => r.arrayBuffer()))
|
|
65
|
+
const init = await validateC2paInitSegment(initBytes)
|
|
66
|
+
|
|
67
|
+
const segmentBytes = new Uint8Array(await fetch(segmentUrl).then(r => r.arrayBuffer()))
|
|
68
|
+
const { result } = await validateC2paMerkleSegment(segmentBytes, init.merkleMaps)
|
|
69
|
+
```
|
|
70
|
+
|
|
58
71
|
## Docs
|
|
59
72
|
|
|
60
|
-
- [VSI/EMSG Validation](https://github.com/streaming-video-technology-alliance/common-media-library/blob/main/libs/c2pa/docs/vsi-validation.md)
|
|
61
|
-
- [Manifest Box Validation](https://github.com/streaming-video-technology-alliance/common-media-library/blob/main/libs/c2pa/docs/manifest-box-validation.md)
|
|
62
|
-
- [
|
|
73
|
+
- [VSI/EMSG Validation](https://github.com/streaming-video-technology-alliance/common-media-library/blob/main/libs/c2pa/docs/vsi-validation.md): Validate using Verifiable Segment Info (§19.4)
|
|
74
|
+
- [Manifest Box Validation](https://github.com/streaming-video-technology-alliance/common-media-library/blob/main/libs/c2pa/docs/manifest-box-validation.md): Validate using per-segment manifests (§19.3)
|
|
75
|
+
- [VOD Merkle Validation](https://github.com/streaming-video-technology-alliance/common-media-library/blob/main/libs/c2pa/docs/merkle-validation.md): Validate on-demand fragmented MP4 assets using Merkle tree proofs (§15.12.2 / §18.6)
|
|
76
|
+
- [Results and Error Codes](https://github.com/streaming-video-technology-alliance/common-media-library/blob/main/libs/c2pa/docs/results-and-error-codes.md): Interpret results, error codes, and manifest data
|
|
63
77
|
|
|
64
78
|
## References
|
|
65
79
|
|
package/dist/index.d.ts
CHANGED
|
@@ -57,6 +57,10 @@ declare const C2paStatusCode: {
|
|
|
57
57
|
readonly ASSERTION_ACTION_INGREDIENT_MISMATCH: "assertion.action.ingredientMismatch";
|
|
58
58
|
/** Claim signature verification failed (§15.7) */
|
|
59
59
|
readonly CLAIM_SIGNATURE_MISMATCH: "claim.signature.mismatch";
|
|
60
|
+
/** BMFF hash assertion or Merkle structure is malformed (§15.2.2.3) */
|
|
61
|
+
readonly ASSERTION_BMFFHASH_MALFORMED: "assertion.bmffHash.malformed";
|
|
62
|
+
/** BMFF content hash does not match the committed value (§15.2.2.3) */
|
|
63
|
+
readonly ASSERTION_BMFFHASH_MISMATCH: "assertion.bmffHash.mismatch";
|
|
60
64
|
};
|
|
61
65
|
/**
|
|
62
66
|
* Union type of all {@link (C2paStatusCode:variable)} values.
|
|
@@ -97,10 +101,16 @@ declare const LiveVideoStatusCode: {
|
|
|
97
101
|
readonly MANIFEST_INVALID: "livevideo.manifest.invalid";
|
|
98
102
|
/** Segment structure invalid: missing Manifest Box/emsg, signature/hash/key failure (§19.7) */
|
|
99
103
|
readonly SEGMENT_INVALID: "livevideo.segment.invalid";
|
|
100
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Live video assertion field invalid: sequenceNumber or streamId mismatch
|
|
106
|
+
* (§19.7.2). Also reused for VOD Merkle per-track location discontinuity
|
|
107
|
+
* (§15.12.2), which has no dedicated code.
|
|
108
|
+
*/
|
|
101
109
|
readonly ASSERTION_INVALID: "livevideo.assertion.invalid";
|
|
102
110
|
/** continuityMethod absent, unsupported, or companion fields incorrect (§19.7.2) */
|
|
103
111
|
readonly CONTINUITY_METHOD_INVALID: "livevideo.continuityMethod.invalid";
|
|
112
|
+
/** Custom continuityMethod with no registered validator (§19.7.2) */
|
|
113
|
+
readonly CONTINUITY_METHOD_UNSUPPORTED: "livevideo.continuityMethod.unsupported";
|
|
104
114
|
/** Session key invalid: signerBinding failed or required fields absent (§19.7.3) */
|
|
105
115
|
readonly SESSIONKEY_INVALID: "livevideo.sessionkey.invalid";
|
|
106
116
|
};
|
|
@@ -111,6 +121,73 @@ declare const LiveVideoStatusCode: {
|
|
|
111
121
|
*/
|
|
112
122
|
type LiveVideoStatusCode = ValueOf<typeof LiveVideoStatusCode>;
|
|
113
123
|
//#endregion
|
|
124
|
+
//#region src/bmff/BmffHashExclusion.d.ts
|
|
125
|
+
/**
|
|
126
|
+
* A byte-level constraint used to match specific BMFF box content
|
|
127
|
+
* within a C2PA BMFF hash exclusion.
|
|
128
|
+
*
|
|
129
|
+
* @public
|
|
130
|
+
*/
|
|
131
|
+
type BmffHashConstraint = {
|
|
132
|
+
readonly offset: number;
|
|
133
|
+
readonly value: Uint8Array | readonly number[];
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Identifies a BMFF box to exclude from the C2PA content hash (`c2pa.hash.bmff.v3`).
|
|
137
|
+
*
|
|
138
|
+
* The `xpath` uses C2PA path notation (e.g. `/emsg`, `/moof/traf`).
|
|
139
|
+
* Optional `data` constraints narrow the match to specific box content
|
|
140
|
+
* by byte offset within the box.
|
|
141
|
+
*
|
|
142
|
+
* @public
|
|
143
|
+
*/
|
|
144
|
+
type BmffHashExclusion = {
|
|
145
|
+
readonly xpath: string;
|
|
146
|
+
readonly data?: readonly BmffHashConstraint[];
|
|
147
|
+
};
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/merkle/MerkleSegmentValidation.d.ts
|
|
150
|
+
/**
|
|
151
|
+
* One merkle map from the `c2pa.hash.bmff.v3` assertion (§18.6).
|
|
152
|
+
*
|
|
153
|
+
* @public
|
|
154
|
+
*/
|
|
155
|
+
type MerkleMap = {
|
|
156
|
+
readonly uniqueId: number;
|
|
157
|
+
readonly localId: number;
|
|
158
|
+
readonly count: number;
|
|
159
|
+
readonly hashes: readonly Uint8Array[];
|
|
160
|
+
readonly initHash: Uint8Array | null;
|
|
161
|
+
readonly alg: string | null;
|
|
162
|
+
readonly exclusions: readonly BmffHashExclusion[];
|
|
163
|
+
readonly offsetPrefixSize: number;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Continuity state carried between calls to `validateC2paMerkleSegment`.
|
|
167
|
+
* Reset (pass `undefined`) after a seek.
|
|
168
|
+
*
|
|
169
|
+
* `lastLocations` is keyed by `${uniqueId}:${localId}`, matching the
|
|
170
|
+
* `MerkleMap` fields of the track it tracks. The first location seen for a
|
|
171
|
+
* key is always accepted (no prior state to compare against), so a caller
|
|
172
|
+
* that needs strict start-at-zero enforcement must seed this map itself.
|
|
173
|
+
*
|
|
174
|
+
* @public
|
|
175
|
+
*/
|
|
176
|
+
type MerkleSegmentState = {
|
|
177
|
+
readonly lastLocations: ReadonlyMap<string, number>;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Result of `validateC2paMerkleSegment` for one media segment.
|
|
181
|
+
*
|
|
182
|
+
* @public
|
|
183
|
+
*/
|
|
184
|
+
type MerkleSegmentValidation = {
|
|
185
|
+
readonly location: number | null;
|
|
186
|
+
readonly bmffHashHex: string | null;
|
|
187
|
+
readonly isValid: boolean;
|
|
188
|
+
readonly errorCodes: readonly (LiveVideoStatusCode | C2paStatusCode)[];
|
|
189
|
+
};
|
|
190
|
+
//#endregion
|
|
114
191
|
//#region src/init/InitSegmentValidation.d.ts
|
|
115
192
|
/**
|
|
116
193
|
* A session key extracted and verified from a C2PA `c2pa.session-keys` assertion.
|
|
@@ -139,6 +216,7 @@ type InitSegmentValidation = {
|
|
|
139
216
|
readonly certificate: Uint8Array | null;
|
|
140
217
|
readonly manifestId: string | null;
|
|
141
218
|
readonly sessionKeys: readonly ValidatedSessionKey[];
|
|
219
|
+
readonly merkleMaps: readonly MerkleMap[];
|
|
142
220
|
readonly isValid: boolean;
|
|
143
221
|
readonly errorCodes: readonly (LiveVideoStatusCode | C2paStatusCode)[];
|
|
144
222
|
};
|
|
@@ -294,6 +372,23 @@ type ManifestBoxValidationResult = {
|
|
|
294
372
|
readonly errorCodes: readonly (LiveVideoStatusCode | C2paStatusCode)[];
|
|
295
373
|
};
|
|
296
374
|
/**
|
|
375
|
+
* Validates continuity for an implementer-defined continuity method (§19.3.2).
|
|
376
|
+
*
|
|
377
|
+
* @public
|
|
378
|
+
*/
|
|
379
|
+
type ManifestBoxContinuityValidator = (liveVideoAssertion: Readonly<Record<string, unknown>>, manifest: C2paManifest) => boolean | Promise<boolean>;
|
|
380
|
+
/**
|
|
381
|
+
* Options for `validateC2paManifestBoxSegment`.
|
|
382
|
+
*
|
|
383
|
+
* @public
|
|
384
|
+
*/
|
|
385
|
+
type ManifestBoxValidationOptions = {
|
|
386
|
+
readonly continuityValidator?: {
|
|
387
|
+
readonly method: string;
|
|
388
|
+
readonly validate: ManifestBoxContinuityValidator;
|
|
389
|
+
};
|
|
390
|
+
};
|
|
391
|
+
/**
|
|
297
392
|
* State to carry between consecutive manifest-box segment validations.
|
|
298
393
|
*
|
|
299
394
|
* Pass the `nextState` returned by {@link validateC2paManifestBoxSegment}
|
|
@@ -314,6 +409,8 @@ type ManifestBoxValidationState = {
|
|
|
314
409
|
* Recomputes the `c2pa.hash.bmff.v3` content hash from the raw segment bytes and compares
|
|
315
410
|
* it against the expected hash in the manifest assertion. Checks live-video assertions
|
|
316
411
|
* (sequenceNumber, streamId, continuityMethod) and manifest-ID chain continuity.
|
|
412
|
+
* A validator for an implementer-defined continuity method can be registered
|
|
413
|
+
* via {@link ManifestBoxValidationOptions}.
|
|
317
414
|
*
|
|
318
415
|
* This function is **pure** — it does not access any external state. The
|
|
319
416
|
* caller is responsible for persisting `nextManifestId` and `nextState`
|
|
@@ -322,6 +419,7 @@ type ManifestBoxValidationState = {
|
|
|
322
419
|
* @param bytes - Raw segment bytes
|
|
323
420
|
* @param lastManifestId - Manifest ID from the previous segment, or null for the first segment
|
|
324
421
|
* @param state - Optional state from the previous segment for streamId/sequenceNumber checks
|
|
422
|
+
* @param options - Optional custom continuity method validator
|
|
325
423
|
* @returns Validation result, the manifest ID, and state to persist for the next call
|
|
326
424
|
*
|
|
327
425
|
* @example
|
|
@@ -329,11 +427,31 @@ type ManifestBoxValidationState = {
|
|
|
329
427
|
*
|
|
330
428
|
* @public
|
|
331
429
|
*/
|
|
332
|
-
declare function validateC2paManifestBoxSegment(bytes: Uint8Array, lastManifestId: string | null, state?: ManifestBoxValidationState): Promise<{
|
|
430
|
+
declare function validateC2paManifestBoxSegment(bytes: Uint8Array, lastManifestId: string | null, state?: ManifestBoxValidationState, options?: ManifestBoxValidationOptions): Promise<{
|
|
333
431
|
readonly result: ManifestBoxValidationResult;
|
|
334
432
|
readonly nextManifestId: string | null;
|
|
335
433
|
readonly nextState: ManifestBoxValidationState;
|
|
336
434
|
}>;
|
|
337
435
|
//#endregion
|
|
338
|
-
|
|
436
|
+
//#region src/merkle/validateC2paMerkleSegment.d.ts
|
|
437
|
+
/**
|
|
438
|
+
* Validates a fragmented MP4 VOD media segment against the init manifest's
|
|
439
|
+
* merkle maps (§15.12.2.2). Pure: the caller persists `nextState` and resets
|
|
440
|
+
* `state` after a seek.
|
|
441
|
+
*
|
|
442
|
+
* `merkleMaps` must be non-empty; the caller is responsible for only calling
|
|
443
|
+
* this in VOD Merkle mode (i.e. after `InitSegmentValidation.merkleMaps` came
|
|
444
|
+
* back non-empty).
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* {@includeCode ../../test/merkle/validateC2paMerkleSegment.test.ts#example}
|
|
448
|
+
*
|
|
449
|
+
* @public
|
|
450
|
+
*/
|
|
451
|
+
declare function validateC2paMerkleSegment(segmentBytes: Uint8Array, merkleMaps: readonly MerkleMap[], state?: MerkleSegmentState): Promise<{
|
|
452
|
+
readonly result: MerkleSegmentValidation;
|
|
453
|
+
readonly nextState: MerkleSegmentState;
|
|
454
|
+
}>;
|
|
455
|
+
//#endregion
|
|
456
|
+
export { BmffHashConstraint, BmffHashExclusion, C2paAssertion, C2paManifest, C2paSignatureInfo, C2paStatusCode, CoseKeyJwk, InitSegmentValidation, LiveVideoStatusCode, ManifestBoxContinuityValidator, ManifestBoxValidationOptions, ManifestBoxValidationResult, ManifestBoxValidationState, MerkleMap, MerkleSegmentState, MerkleSegmentValidation, SegmentValidationResult, type SequenceState, SequenceValidationReason, type SequenceValidationResult, ValidatedSessionKey, validateC2paInitSegment, validateC2paManifestBoxSegment, validateC2paMerkleSegment, validateC2paSegment };
|
|
339
457
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/C2paAssertion.ts","../src/C2paSignatureInfo.ts","../src/C2paManifest.ts","../src/C2paStatusCode.ts","../src/cose/CoseKeyJwk.ts","../src/LiveVideoStatusCode.ts","../src/init/InitSegmentValidation.ts","../src/init/validateC2paInitSegment.ts","../src/vsi/SequenceState.ts","../src/segment/SegmentValidation.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/ManifestBoxValidation.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts"],"sourcesContent":[],"mappings":";;;;;;;AAKA;;KAAY,aAAA;;ECAZ,SAAY,IAAA,EAAA,OAAA;;;;;;;ADAZ;;KCAY,iBAAA;;EAAZ,SAAY,aAAA,EAAA,MAAA,GAAA,IAAA;;;;;ADAZ;;;;ACAY,KCGA,YAAA,GDHA;;;;ECGZ,SAAY,aAAA,EAIa,iBAAA;gCACM;;;;;;AFR/B;;;;ACAA;;;;ACGY,cCIC,cDAY,EAAA;;;;ECAzB,SAAa,iBAAA,EAAA,mBAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/C2paAssertion.ts","../src/C2paSignatureInfo.ts","../src/C2paManifest.ts","../src/C2paStatusCode.ts","../src/cose/CoseKeyJwk.ts","../src/LiveVideoStatusCode.ts","../src/bmff/BmffHashExclusion.ts","../src/merkle/MerkleSegmentValidation.ts","../src/init/InitSegmentValidation.ts","../src/init/validateC2paInitSegment.ts","../src/vsi/SequenceState.ts","../src/segment/SegmentValidation.ts","../src/segment/validateC2paSegment.ts","../src/manifestbox/ManifestBoxValidation.ts","../src/manifestbox/validateC2paManifestBoxSegment.ts","../src/merkle/validateC2paMerkleSegment.ts"],"sourcesContent":[],"mappings":"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"}
|