2025-07-04 12:51:57 +02:00
|
|
|
export type AIInferenceResult = {
|
|
|
|
|
aiGenerated: boolean;
|
|
|
|
|
aiProbability: number;
|
|
|
|
|
humanProbability: number;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-11 14:36:58 +02:00
|
|
|
export const C2PASourceTypeScreenCapture = "http://cv.iptc.org/newscodes/digitalsourcetype/screenCapture";
|
|
|
|
|
export const C2PASourceTypeDigitalCapture = "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture";
|
|
|
|
|
export const C2PASourceTypeComputationalCapture = "http://cv.iptc.org/newscodes/digitalsourcetype/computationalCapture";
|
|
|
|
|
export const C2PASourceTypeCompositeCapture = "http://cv.iptc.org/newscodes/digitalsourcetype/compositeCapture";
|
|
|
|
|
export const C2PASourceTypeTrainedAlgorithmicMedia = "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia";
|
|
|
|
|
export const C2PASourceTypeCompositeWithTrainedAlgorithmicMedia = "http://cv.iptc.org/newscodes/digitalsourcetype/compositeWithTrainedAlgorithmicMedia";
|
|
|
|
|
|
2025-07-04 12:51:57 +02:00
|
|
|
export type C2PAActionsAssertion = {
|
|
|
|
|
actions: {
|
|
|
|
|
action: string;
|
|
|
|
|
softwareAgent?: string;
|
2025-07-11 14:36:58 +02:00
|
|
|
digitalSourceType?: string;
|
2025-07-04 12:51:57 +02:00
|
|
|
}[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type C2PAAssertion = {
|
|
|
|
|
label: string;
|
|
|
|
|
data: C2PAActionsAssertion | undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type C2PAManifest = {
|
|
|
|
|
assertions: C2PAAssertion[];
|
|
|
|
|
signature_info: {
|
|
|
|
|
time: string;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-11 14:36:58 +02:00
|
|
|
export type C2PAValidationResults = {
|
|
|
|
|
activeManifest?: {
|
|
|
|
|
failure: any[];
|
|
|
|
|
success: any[];
|
|
|
|
|
informational: any[];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-04 12:51:57 +02:00
|
|
|
export type C2PAManifestInfo = {
|
|
|
|
|
active_manifest: string;
|
|
|
|
|
manifests: {[key: string]: C2PAManifest};
|
2025-07-11 14:36:58 +02:00
|
|
|
validation_results?: C2PAValidationResults;
|
2025-07-04 12:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type C2PAData = {
|
|
|
|
|
manifest_info: C2PAManifestInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type Proof = {
|
2025-07-17 10:30:14 +02:00
|
|
|
data?: any;
|
2025-07-04 12:51:57 +02:00
|
|
|
name?: string;
|
|
|
|
|
json?: string;
|
2025-08-20 15:12:04 +02:00
|
|
|
integrity?: { pgp?: any; c2pa?: C2PAData; exif?: {[key: string]: string | Object}; opentimestamps?: any };
|
2025-07-04 12:51:57 +02:00
|
|
|
ai?: { inferenceResult?: AIInferenceResult};
|
|
|
|
|
}
|
2025-08-20 15:12:04 +02:00
|
|
|
|
|
|
|
|
export type ProofHintFlags = {
|
|
|
|
|
aiGenerated?: boolean;
|
|
|
|
|
aiEdited?: boolean;
|
|
|
|
|
screenshot?: boolean;
|
|
|
|
|
camera?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const extractProofHintFlags = (proof?: Proof): (ProofHintFlags | undefined) => {
|
|
|
|
|
if (!proof) return undefined;
|
|
|
|
|
|
|
|
|
|
let screenshot = false;
|
|
|
|
|
let camera = false;
|
|
|
|
|
let aiGenerated = false;
|
|
|
|
|
let aiEdited = false;
|
|
|
|
|
let valid = false;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
let results = proof.integrity?.c2pa?.manifest_info.validation_results?.activeManifest;
|
|
|
|
|
if (results) {
|
|
|
|
|
valid = results.failure.length == 0 && results.success.length > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const manifests = Object.values(proof.integrity?.c2pa?.manifest_info.manifests ?? {});
|
|
|
|
|
for (const manifest of manifests) {
|
|
|
|
|
for (const assertion of manifest.assertions) {
|
|
|
|
|
if (assertion.label === "c2pa.actions") {
|
|
|
|
|
const actions = (assertion.data as C2PAActionsAssertion)?.actions ?? [];
|
|
|
|
|
const a = actions.find((a) => a.action === "c2pa.created");
|
|
|
|
|
if (a) {
|
|
|
|
|
// creator.value = a.softwareAgent;
|
|
|
|
|
// dateCreated.value = dayjs(Date.parse(manifest.signature_info.time));
|
|
|
|
|
if (a.digitalSourceType === C2PASourceTypeScreenCapture) {
|
|
|
|
|
screenshot = true;
|
|
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
a.digitalSourceType === C2PASourceTypeDigitalCapture ||
|
|
|
|
|
a.digitalSourceType === C2PASourceTypeComputationalCapture ||
|
|
|
|
|
a.digitalSourceType === C2PASourceTypeCompositeCapture
|
|
|
|
|
) {
|
|
|
|
|
camera = true;
|
|
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
a.digitalSourceType === C2PASourceTypeTrainedAlgorithmicMedia ||
|
|
|
|
|
a.digitalSourceType === C2PASourceTypeCompositeWithTrainedAlgorithmicMedia
|
|
|
|
|
) {
|
|
|
|
|
aiGenerated = true;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (valid) {
|
|
|
|
|
const flags: ProofHintFlags = {
|
|
|
|
|
aiGenerated,
|
|
|
|
|
aiEdited,
|
|
|
|
|
screenshot,
|
|
|
|
|
camera
|
|
|
|
|
};
|
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
};
|