Use RE for proof extraxtion

This commit is contained in:
N-Pex 2025-09-01 16:26:05 +02:00
parent 46cab38b8a
commit 2d4143fde6

View file

@ -72,6 +72,11 @@ type FlagMatchRule = {
description: string;
};
type FlagMatchRuleValue = {
path: string;
value: string;
};
type FlagMatchInfo = {
field: string;
value: string;
@ -87,13 +92,35 @@ const ruleScreenshot = (): FlagMatchRule[] => {
return [
{
field:
"integrity/c2pa/manifest_info/manifests[]/assertions[]/{label=c2pa.actions}/data/actions[]/{action=c2pa.created}/digitalSourceType",
"integrity/c2pa/manifest_info/manifests[]/assertions[label=c2pa.actions]/data/actions[action=c2pa.created]/digitalSourceType",
match: [C2PASourceTypeScreenCapture],
description: "Screen capture",
},
];
};
const ruleCamera = (): FlagMatchRule[] => {
return [
{
field:
"integrity/c2pa/manifest_info/manifests[]/assertions[label=c2pa.actions]/data/actions[action=c2pa.created]/digitalSourceType",
match: [C2PASourceTypeDigitalCapture, C2PASourceTypeComputationalCapture, C2PASourceTypeCompositeCapture],
description: "Captured by camera",
},
];
};
const ruleAiGenerated = (): FlagMatchRule[] => {
return [
{
field:
"integrity/c2pa/manifest_info/manifests[]/assertions[label=c2pa.actions]/data/actions[action=c2pa.created]/digitalSourceType",
match: [C2PASourceTypeTrainedAlgorithmicMedia, C2PASourceTypeCompositeWithTrainedAlgorithmicMedia],
description: "Generated by AI",
},
];
};
const aiHintFlags = (): FlagMatchRule[] => {
const knownAIServices = [
"ChatGPT",
@ -122,13 +149,22 @@ const matchFlag = (rules: FlagMatchRule[], file: any) => {
const matchParts = (parts: string[], o: any, re: RegExp[]): FlagMatch[] | undefined => {
if (parts.length == 0 || o == undefined) return undefined;
let part = parts[0];
if (part.endsWith("[]")) {
part = part.substring(0, part.length - 2);
const lastBracket = part.lastIndexOf("[");
if (part.endsWith("]") && lastBracket > 0) {
const optionalConstraint = part.substring(lastBracket + 1, part.length - 1);
part = part.substring(0, lastBracket);
if (o[part] != undefined) {
let opart: any[] = o[part];
if (!Array.isArray(opart)) {
opart = Object.values(opart) ?? [];
}
// Any constraints controlling what array object(s) to consider?
if (optionalConstraint) {
const [prop, val] = optionalConstraint.split("=");
opart = opart.filter((item) => item[prop] === val);
}
if (parts.length == 1) {
let strings = opart as string[];
if (!strings) return undefined;
@ -156,13 +192,6 @@ const matchFlag = (rules: FlagMatchRule[], file: any) => {
} else {
return undefined;
}
} else if (part.startsWith("{") && part.endsWith("}")) {
const [prop, val] = part.substring(1, part.length - 1).split("=");
if (o[prop] === val) {
return matchParts(parts.slice(1), o, re);
} else {
return undefined;
}
} else {
if (o[part] != undefined) {
if (parts.length == 1) {
@ -203,6 +232,71 @@ const matchFlag = (rules: FlagMatchRule[], file: any) => {
return { result: result, matches: resultInfo };
};
const extractFlagValues = (flagPath: string, file: any): FlagMatchRuleValue[] => {
const getValues = (path: string[], objectPath: any[], actualPath: string, o: any): FlagMatchRuleValue[] | undefined => {
if (path.length == 0 || o == undefined) return undefined;
let part = path[0];
const lastBracket = part.lastIndexOf("[");
if (part === "..") {
return getValues(path.slice(1), objectPath.slice(1), actualPath + "/..", objectPath[0]);
}
if (part.endsWith("]") && lastBracket > 0) {
const optionalConstraint = part.substring(lastBracket + 1, part.length - 1);
part = part.substring(0, lastBracket);
if (o[part] != undefined) {
let opart: any[] = o[part];
if (!Array.isArray(opart)) {
opart = Object.values(opart) ?? [];
}
// Any constraints controlling what array object(s) to consider?
if (optionalConstraint) {
const [prop, val] = optionalConstraint.split("=");
opart = opart.filter((item) => item[prop] === val);
}
if (path.length == 1) {
let strings = opart as string[];
return strings.map((s, i) => ({ path: actualPath + "/" + part + "[" + i + "]", value: s }));
} else {
return opart.reduce((res: FlagMatchRuleValue[] | undefined, o: any, i: number) => {
const newObjectPaths = [o, ...objectPath];
let matches = getValues(path.slice(1), newObjectPaths, actualPath + "/" + part + "[" + i + "]", o);
if (matches) {
const r2 = res || [];
r2.push(...matches);
return r2;
}
return res;
}, undefined);
}
} else {
return undefined;
}
} else {
if (o[part] != undefined) {
if (path.length == 1) {
return [{ path: actualPath + "/" + part, value: o[part] }];
} else {
const newObjectPaths = [o, ...objectPath];
return getValues(path.slice(1), newObjectPaths, actualPath + "/" + part, o[part]);
}
} else {
return undefined;
}
}
};
let result: FlagMatchRuleValue[] = [];
try {
let parts = flagPath.split("/");
result = getValues(parts, [], "", file) ?? [];
} catch (e) {
console.error("Invalid RE", e);
}
return result;
};
export const extractProofHintFlags = (proof?: Proof): ProofHintFlags | undefined => {
if (!proof) return undefined;
@ -258,6 +352,10 @@ export const extractProofHintFlags = (proof?: Proof): ProofHintFlags | undefined
}
}
if (valid) {
const dateCreated = extractFlagValues("integrity/c2pa/manifest_info/manifests[]/assertions[label=c2pa.actions]/data/actions[action=c2pa.created]/../../../../signature_info/issuer", proof);
console.error("DATE CREATED", dateCreated);
screenshot = matchFlag(ruleScreenshot(), proof).result;
const flags: ProofHintFlags = {
aiGenerated,