Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
"svelte-css-vars": "^0.0.3",
"svelte-focus-trap": "^1.2.0",
"svelte-i18n": "^3.7.4",
"intl-messageformat": "9.13.0",
"svelte-meta-tags": "^3.0.4",
"svelte-modals": "^1.3.0",
"tippy.js": "^6.3.7"
Expand Down
25 changes: 25 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions src/components/EmbeddedIcon/EmbeddedIcon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@
-->
<script lang="ts">
import type { ClaimGeneratorDisplayInfo } from '$src/lib/asset';
import { loadThumbnail } from '$src/lib/thumbnail';
interface DisposableBlobUrl {
url: string;
dispose: () => void;
}

import { onMount } from 'svelte';

export let generator: ClaimGeneratorDisplayInfo;
let iconUrl: string | undefined;

onMount(() => {
let dispose: DisposableBlobUrl['dispose'];
let dispose: () => void = () => {};

if (generator.icon) {
// The new SDK requires the active reader instance to fetch embedded resources.
Expand Down
42 changes: 31 additions & 11 deletions src/lib/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export async function resultToAssetMap({
dbg('Runtime validation statuses by manifest label', runtimeValidationStatuses);

const activeManifestValidationResults =
manifestStore?.validation_results?.activeManifest;
manifestStore?.validation_results?.activeManifest ?? undefined;

const rootValidationStatuses =
runtimeValidationStatuses[activeManifestLabel] ?? [];
Expand Down Expand Up @@ -260,7 +260,7 @@ export async function resultToAssetMap({
manifestData: await getManifestData(manifest, rootValidationResult),
dataType: null,
validationResult: rootValidationResult,
trustSource: (manifest as any).trust_source || 'none',
trustSource: ((manifest as Manifest & { trust_source?: 'legacy' | 'none' | 'official' }).trust_source || 'none') as 'legacy' | 'none' | 'official',
};

if (thumbnail?.dispose) {
Expand Down Expand Up @@ -288,7 +288,7 @@ export async function resultToAssetMap({
);

const activeManifestValidationResults =
ingredient.validation_results?.activeManifest;
ingredient.validation_results?.activeManifest ?? undefined;

let validationResult = selectValidationResult(
ingredient.validation_status || [],
Expand Down Expand Up @@ -318,7 +318,7 @@ export async function resultToAssetMap({
manifestData: await getManifestData(ingredientManifest, validationResult),
dataType: getIngredientDataType(ingredient),
validationResult,
trustSource: (ingredient as any)?.trust_source || 'none',
trustSource: ((ingredient as Ingredient & { trust_source?: 'legacy' | 'none' | 'official' })?.trust_source || 'none') as 'legacy' | 'none' | 'official',
};

if (thumbnail?.dispose) {
Expand All @@ -338,9 +338,11 @@ export async function resultToAssetMap({
return null;
}

function formattedGeneratorInfo(claim_generator: any) {
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
function formattedGeneratorInfo(claim_generator: any): any {
const version = claim_generator?.version;
claim_generator.version = version?.replace(/\([^()]*\)/g, '');

return claim_generator;
}

Expand All @@ -359,8 +361,6 @@ export async function resultToAssetMap({
icon: claimGeneratorInfo?.icon ?? null,
};

// Extract Organization (O) from the native X.509 certificate subject tree
let organization: string | undefined = undefined;
const safeSignatureInfo = manifest.signature_info
? { ...manifest.signature_info }
: null;
Expand All @@ -383,9 +383,25 @@ export async function resultToAssetMap({
);

if (editsAndActivity) {
const actionsAssertion = manifest.assertions?.['c2pa.actions'];
const assertions = manifest.assertions;

let actionsAssertion: unknown;

if (Array.isArray(assertions)) {
actionsAssertion = assertions.find(
(a): a is { label: string; data: unknown } =>
typeof a === 'object' &&
a !== null &&
'label' in a &&
typeof (a as Record<string, unknown>)['label'] === 'string' &&
(a as Record<string, unknown>)['label'] === 'c2pa.actions'
);
} else if (assertions && typeof assertions === 'object') {
actionsAssertion = (assertions as Record<string, unknown>)['c2pa.actions'];
}

const hasInference =
!!(actionsAssertion as any)?.data?.metadata?.['com.adobe.inference'];
!!(actionsAssertion as { data?: { metadata?: Record<string, unknown> } })?.data?.metadata?.['com.adobe.inference'];

const filteredEditsAndActivity = editsAndActivity.filter(
(value) => !!value.label,
Expand Down Expand Up @@ -415,15 +431,18 @@ export async function resultToAssetMap({

// 2. Must have exactly one action in the manifest history
let actionsAssertion;

if (manifest.assertions instanceof Map) {
actionsAssertion = manifest.assertions.get('c2pa.actions.v2')?.[0] || manifest.assertions.get('c2pa.actions')?.[0] || manifest.assertions.get('c2pa.actions.v2') || manifest.assertions.get('c2pa.actions');
} else if (Array.isArray(manifest.assertions)) {
actionsAssertion = manifest.assertions.find((a: any) => a.label === 'c2pa.actions.v2' || a.label === 'c2pa.actions');
actionsAssertion = manifest.assertions.find((a: { label?: string }) => a.label === 'c2pa.actions.v2' || a.label === 'c2pa.actions');
} else {
actionsAssertion = manifest.assertions?.['c2pa.actions.v2'] || manifest.assertions?.['c2pa.actions'];
}

const actions = (actionsAssertion as any)?.data?.actions || (actionsAssertion as any)?.actions || [];
type C2paActionItem = { action: string; digitalSourceType?: string; parameters?: { digitalSourceType?: string } };
type AssertionValue = { data?: { actions?: C2paActionItem[] }; actions?: C2paActionItem[] };
const actions = (actionsAssertion as AssertionValue)?.data?.actions || (actionsAssertion as AssertionValue)?.actions || [];
if (actions.length !== 1) return false;

// 3. First and only action must be c2pa.created
Expand All @@ -432,6 +451,7 @@ export async function resultToAssetMap({

// 4. Digital source type must be a standard captured media URI (including computational)
const sourceType = action.digitalSourceType || action.parameters?.digitalSourceType || '';

return sourceType.includes('digitalCapture') || sourceType.includes('compositeCapture') || sourceType.includes('computationalCapture');
})(),
};
Expand Down
Loading
Loading