1import { createC2pa } from '/TemplatePackage/contrib/libs/c2pa/latest/c2pa.esm.min.js'; 2 3(async () => { 4 const c2pa = await createC2pa({ 5 wasmSrc: '/TemplatePackage/contrib/libs/c2pa/latest/toolkit_bg.wasm', 6 workerSrc: '/TemplatePackage/contrib/libs/c2pa/latest/c2pa.worker.min.js', 7 }); 8 9 const DEBUG = !!window.location?.search?.includes('cdcdebug'); 10 const manifests = {}; 11 12 // expose as recallable method 13 window.cdcc2paCheck = () => { 14 Array.from(document.getElementsByTagName('img')).forEach(async (image) => { 15 // skip images in page headers, footers, or non-indexed content, or images already checked 16 if (image?.closest('header, footer, .noindex, #hero-carousel')) { 17 return; 18 } 19 // skip some extensions 20 if (!image.src || image.src.match(/\.(svg|axd|gif|bmp)([#\?]|$)/i)) { 21 return; 22 } 23 24 let manifestStore = null; 25 if (manifests.hasOwnProperty(image.src)) { 26 manifestStore = manifests[image.src]; 27 } else { 28 // Get a manifest store for the image 29 try { 30 let manifest = await c2pa.read(image); 31 manifestStore = manifest.manifestStore; 32 } catch (e) { 33 DEBUG && console.error(`C2R: failed checking image:`, image, e); 34 return; 35 } 36 manifests[image.src] = manifestStore 37 } 38 const manifestFlat = JSON.stringify(manifestStore?.activeManifest?.assertions?.data || {}); 39 const manifestCheck = manifestFlat.includes('cv.iptc.org/newscodes/digitalsourcetype/compositeWithTrainedAlgorithmicMedia') || 40 manifestFlat.includes('cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia'); 41 42 DEBUG && console.info(`C2R: ${manifestCheck?'Y':'n'}`, image, manifestStore); 43 if (manifestStore && manifestCheck) { 44 const details = { 45 generator: String(manifestStore.activeManifest?.claimGenerator || ''), 46 tools: [], 47 issuer: '', 48 date: '', 49 }; 50 if (Array.isArray(manifestStore.activeManifest?.assertions?.data)) { 51 manifestStore.activeManifest.assertions.data.forEach((assertion) => { 52 let assertionData = assertion?.data; 53 if (assertionData) { 54 assertionData.actions.forEach((action) => { 55 if (action.digitalSourceType.includes('cv.iptc.org/newscodes/digitalsourcetype/compositeWithTrainedAlgorithmicMedia') || 56 action.digitalSourceType.includes('cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia')) { 57 details.tools.push(action?.softwareAgent); 58 } 59 }); 60 } 61 }); 62 } 63 details.issuer = String(manifestStore.activeManifest?.signatureInfo?.issuer || ''); 64 details.date = String(manifestStore.activeManifest?.signatureInfo?.time || ''); 65 // dispatch event and flag to avoid retriggering 66 image.dispatchEvent(new CustomEvent('cdc-image-c2r', { detail: details, bubbles: true })); 67 } 68 }); 69 } 70 if (document.readyState === 'loading') { 71 document.addEventListener('DOMContentLoaded', window.cdcc2paCheck); 72 } else { 73 window.cdcc2paCheck(); 74 } 75})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.