Skip to content

Commit

Permalink
Merge pull request #140 from TrustNXT/feature/additional-assertions
Browse files Browse the repository at this point in the history
Support additional assertions
  • Loading branch information
cyraxx authored Oct 17, 2024
2 parents 28dfeaa + 0fb414c commit 3be9c64
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/pink-deers-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@trustnxt/c2pa-ts': minor
---

Support additional assertions (Training and Data Mining, CAWG Metadata)
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Anything that's not listed below is not currently planned to be implemented.

:information_source: On C2PA versions: The library is targeted at C2PA specification 2.0, however data structures from older versions of the specification are also supported for backwards compatibility.

:information_source: Although it is a separate project from C2PA, the library also includes support for several [CAWG](https://github.com/creator-assertions/) assertions.

### Asset file formats

- :white_check_mark: JPEG
Expand All @@ -43,9 +45,10 @@ Anything that's not listed below is not currently planned to be implemented.
- :white_check_mark: Thumbnail
- :white_check_mark: Actions (except action templates and metadata)
- :white_check_mark: Ingredient
- :white_check_mark: Metadata
- :white_check_mark: Metadata (specialized, common, generic, and CAWG variants)
- :white_check_mark: Creative Work
- :x: [CAWG](https://github.com/creator-assertions/) assertions
- :white_check_mark: Training and Data Mining (C2PA and CAWG variants)
- :x: CAWG Identity

### JUMBF boxes

Expand Down
5 changes: 5 additions & 0 deletions src/manifest/AssertionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
DataHashAssertion,
IngredientAssertion,
MetadataAssertion,
TrainingAndDataMiningAssertion,
UnknownAssertion,
} from './assertions';
import { AssertionLabels } from './assertions/AssertionLabels';
Expand Down Expand Up @@ -67,6 +68,10 @@ export class AssertionStore implements ManifestComponent {
assertion = new IngredientAssertion();
} else if (AssertionLabels.metadataAssertions.includes(label.label)) {
assertion = new MetadataAssertion();
} else if (label.label === AssertionLabels.trainingAndDataMining) {
assertion = new TrainingAndDataMiningAssertion(false);
} else if (label.label === AssertionLabels.cawgTrainingAndDataMining) {
assertion = new TrainingAndDataMiningAssertion(true);
} else if (
box.descriptionBox.label.startsWith(AssertionLabels.thumbnailPrefix) ||
box.descriptionBox.label.startsWith(AssertionLabels.ingredientThumbnailPrefix)
Expand Down
8 changes: 8 additions & 0 deletions src/manifest/assertions/AssertionLabels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export class AssertionLabels {

/** Generic JSON-LD based metadata assertion (C2PA 2.0) */
public static readonly metadata = 'c2pa.metadata';
/** CAWG JSON-LD based metadata assertion */
public static readonly cawgMetadata = 'cawg.metadata';
/** Common metadata assertion (deprecated as of C2PA 2.0) */
public static readonly commonMetadata = 'stds.metadata';
/** EXIF metadata assertion (deprecated as of C2PA 1.4) */
Expand All @@ -31,6 +33,7 @@ export class AssertionLabels {
/** All JSON-LD based metadata assertions */
public static readonly metadataAssertions = [
AssertionLabels.metadata,
AssertionLabels.cawgMetadata,
AssertionLabels.commonMetadata,
AssertionLabels.exifMetadata,
AssertionLabels.iptcMetadata,
Expand All @@ -40,6 +43,11 @@ export class AssertionLabels {
/** Schema.org based Creative Work assertion (deprecated as of C2PA 2.0) */
public static readonly creativeWork = 'stds.schema-org.CreativeWork';

/** Training and Data Mining assertion (deprecated as of C2PA 2.0) */
public static readonly trainingAndDataMining = 'c2pa.training-mining';
/** CAWG Training and Data Mining assertion */
public static readonly cawgTrainingAndDataMining = 'cawg.training-mining';

public static readonly thumbnailPrefix = 'c2pa.thumbnail.claim.';
public static readonly ingredientThumbnailPrefix = 'c2pa.thumbnail.ingredient';
}
74 changes: 74 additions & 0 deletions src/manifest/assertions/TrainingAndDataMiningAssertion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { CBORBox, IBox } from '../../jumbf';
import { BinaryHelper } from '../../util';
import * as raw from '../rawTypes';
import { TrainingAndDataMiningChoice, TrainingAndDataMiningEntry, ValidationStatusCode } from '../types';
import { ValidationError } from '../ValidationError';
import { Assertion } from './Assertion';
import { AssertionLabels } from './AssertionLabels';

// The specification is unclear about whether the individual entries should go into the `entries` field or
// directly into the top level of the payload content. Thus we support reading both. When writing, we include
// the `entries` field for the C2PA 1.x version of the assertion and omit it for the CAWG version.
// See also: https://github.com/creator-assertions/training-and-data-mining-assertion/issues/3
type RawTrainingMiningMap = Record<string, RawEntry> & {
entries?: Record<string, RawEntry>;
metadata?: raw.AssertionMetadataMap;
};

interface RawEntry {
use: TrainingAndDataMiningChoice;
constraint_info?: string;
}

export class TrainingAndDataMiningAssertion extends Assertion {
public label: string;
public uuid = raw.UUIDs.cborAssertion;
public isCAWG: boolean;

public entries: Record<string, TrainingAndDataMiningEntry> = {};

constructor(isCAWG = true) {
super();
this.isCAWG = isCAWG;
this.label = isCAWG ? AssertionLabels.cawgTrainingAndDataMining : AssertionLabels.trainingAndDataMining;
}

public readContentFromJUMBF(box: IBox): void {
if (!(box instanceof CBORBox) || !this.uuid || !BinaryHelper.bufEqual(this.uuid, raw.UUIDs.cborAssertion))
throw new ValidationError(
ValidationStatusCode.AssertionRequiredMissing,
this.sourceBox,
'Training and Data Mining assertion has invalid type',
);

const content = box.content as RawTrainingMiningMap;

const entries: Record<string, RawEntry> = content.entries ?? content;

for (const [key, entry] of Object.entries(entries)) {
if (key === 'metadata') continue;
if (!entry.use) continue;

this.entries[key] = {
choice: entry.use,
constraintInfo: entry.constraint_info,
};
}
}

public generateJUMBFBoxForContent(): IBox {
if (!Object.keys(this.entries).length) throw new Error('Assertion has no entries');

const content: Record<string, RawEntry> = {};
for (const [key, entry] of Object.entries(this.entries)) {
content[key] = {
use: entry.choice,
constraint_info: entry.constraintInfo,
};
}

const box = new CBORBox();
box.content = this.isCAWG ? content : { entries: content };
return box;
}
}
1 change: 1 addition & 0 deletions src/manifest/assertions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export * from './IngredientAssertion';
export * from './MetadataAssertion';
export * from './SchemaOrgAssertion';
export * from './ThumbnailAssertion';
export * from './TrainingAndDataMiningAssertion';
export * from './UnknownAssertion';
25 changes: 25 additions & 0 deletions src/manifest/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,28 @@ export enum ThumbnailType {
Claim,
Ingredient,
}

export enum TrainingAndDataMiningChoice {
Allowed = 'allowed',
NotAllowed = 'notAllowed',
Constrained = 'constrained',
}

export interface TrainingAndDataMiningEntry {
choice: TrainingAndDataMiningChoice;
constraintInfo?: string;
}

export enum TrainingAndDataMiningKey {
DataMining = 'c2pa.data_mining',
AIInference = 'c2pa.ai_inference',
AIGenerativeTraining = 'c2pa.ai_generative_training',
AITraining = 'c2pa.ai_training',
}

export enum CAWGTrainingAndDataMiningKey {
DataMining = 'cawg.data_mining',
AIInference = 'cawg.ai_inference',
AIGenerativeTraining = 'cawg.ai_generative_training',
AITraining = 'cawg.ai_training',
}

0 comments on commit 3be9c64

Please sign in to comment.