C2PA Extension Implementation
Categories:
7 minute read
YouSeddit C2PA Extension Implementation
The YouSeddit C2PA Verification Extension is built upon the open-source c2pa-extension-validator project, extending its capabilities to support text quote validation with blockchain integration.
Building on Existing C2PA Validation
The base c2pa-extension-validator provides:
- Browser extension for validating C2PA digital assets (images, videos, audio)
- Support for Edge, Chrome, and Firefox browsers
- Automatic detection of C2PA-enabled media on webpages
- Visual indicators of validation status
Our implementation maintains these core capabilities while adding:
- Text quote validation through C2PA assertions
- Blockchain verification integration
- Smart contract validation for domains
Technical Implementation
Extension Structure
youseddit-c2pa-extension/
├── src/
│ ├── background/
│ │ └── background.ts # Background service worker
│ ├── content/
│ │ ├── content.ts # Content script for webpage integration
│ │ ├── c2pa-detector.ts # Identifies C2PA content
│ │ ├── text-detector.ts # New: Detects text quotes with C2PA refs
│ │ └── ui/ # UI components
│ ├── blockchain/
│ │ ├── ledger-api.ts # New: Blockchain interaction
│ │ └── contract-validator.ts # New: Smart contract validation
│ ├── c2pa/
│ │ ├── validator.ts # C2PA validation logic
│ │ └── manifest-parser.ts # Extended for YouSeddit assertions
│ ├── popup/
│ │ └── popup.tsx # Extension popup UI
│ └── utils/
│ └── crypto.ts # Cryptographic utilities
├── public/
│ ├── manifest.json # Extension manifest
│ └── icons/ # Extension icons
└── tests/
├── unit/ # Unit tests
└── e2e/ # End-to-end tests
Extending C2PA Manifest Parsing
Our extension extends the standard C2PA manifest parsing to recognize Youseddit-specific assertions:
// Extends the existing C2PA validator with YouSeddit functionality
export class YousedditManifestValidator extends C2PAValidator {
/**
* Check for YouSeddit blockchain assertions in the manifest
*/
public async checkBlockchainAssertion(manifest: C2PAManifest): Promise<BlockchainVerificationResult> {
const yousedditAssertion = manifest.assertions.find(
assertion => assertion.label === 'youseddit.blockchain'
);
if (!yousedditAssertion) {
return { hasBlockchainRef: false };
}
const blockchainId = yousedditAssertion.data.blockchainId;
return this.verifyWithBlockchain(blockchainId);
}
/**
* Verify content against blockchain entry
*/
private async verifyWithBlockchain(blockchainId: string): Promise<BlockchainVerificationResult> {
const blockchainApi = new YousedditLedgerAPI();
return blockchainApi.verifyContent(blockchainId);
}
}
Text Quote Detection
A new component detects and validates text quotes with C2PA references:
export class TextQuoteDetector {
/**
* Scan for potential text quotes with C2PA references
*/
public scanForQuotes(document: Document): QuoteElement[] {
const potentialQuotes: QuoteElement[] = [];
// Look for blockquote elements
const blockquotes = document.querySelectorAll('blockquote');
for (const blockquote of blockquotes) {
this.processQuoteElement(blockquote, potentialQuotes);
}
// Look for quoted text in paragraphs
const paragraphs = document.querySelectorAll('p');
for (const paragraph of paragraphs) {
if (this.containsQuotes(paragraph.textContent)) {
this.processQuoteElement(paragraph, potentialQuotes);
}
}
return potentialQuotes;
}
/**
* Check element for C2PA references
*/
private processQuoteElement(element: Element, results: QuoteElement[]): void {
// Check for data attributes with blockchain references
const blockchainId = element.getAttribute('data-youseddit-id');
if (blockchainId) {
results.push({
element,
text: element.textContent?.trim() || '',
blockchainId
});
return;
}
// Check for nearby C2PA indicators
const nearbyReference = this.findNearbyReference(element);
if (nearbyReference) {
results.push({
element,
text: element.textContent?.trim() || '',
blockchainId: nearbyReference.blockchainId
});
}
}
// Additional helper methods...
}
Blockchain Integration
A new blockchain API layer handles verification against the YouSeddit ledger:
export class YousedditLedgerAPI {
private readonly API_ENDPOINT = 'https://api.youseddit.com/v1';
/**
* Verify content against blockchain record
*/
public async verifyContent(blockchainId: string): Promise<BlockchainVerificationResult> {
try {
const response = await fetch(`${this.API_ENDPOINT}/verify/blockchain/${blockchainId}`);
if (!response.ok) {
return {
hasBlockchainRef: true,
verified: false,
error: 'Failed to fetch blockchain data'
};
}
const data = await response.json();
return {
hasBlockchainRef: true,
verified: true,
sourceInfo: data.sourceInfo,
timestamp: new Date(data.timestampVerified),
contentHash: data.contentHash
};
} catch (error) {
console.error('Blockchain verification error:', error);
return {
hasBlockchainRef: true,
verified: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
/**
* Verify domain has valid contract for content
*/
public async verifyDomainContract(domain: string, blockchainId: string): Promise<ContractVerificationResult> {
try {
const response = await fetch(
`${this.API_ENDPOINT}/contracts/validate?domain=${encodeURIComponent(domain)}&contentId=${blockchainId}`
);
if (!response.ok) {
return { valid: false, error: 'Failed to fetch contract data' };
}
const data = await response.json();
return {
valid: data.valid,
licenseType: data.licenseType,
expirationDate: new Date(data.expires),
paymentStatus: data.paymentStatus
};
} catch (error) {
console.error('Contract validation error:', error);
return {
valid: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
}
Text Validation
To validate text against blockchain records:
export class TextValidator {
/**
* Compare text against authenticated blockchain version
*/
public validateText(quoteText: string, authenticText: string): TextMatchResult {
// Remove extra whitespace and normalize
const normalizedQuote = this.normalizeText(quoteText);
const normalizedAuth = this.normalizeText(authenticText);
if (normalizedQuote === normalizedAuth) {
return { isMatch: true, matchPercentage: 100 };
}
// For partial matches, calculate similarity
const similarity = this.calculateSimilarity(normalizedQuote, normalizedAuth);
return {
isMatch: similarity >= 0.9, // 90% similarity threshold
matchPercentage: Math.round(similarity * 100),
differences: this.highlightDifferences(normalizedQuote, normalizedAuth)
};
}
/**
* Calculate similarity between two text strings
*/
private calculateSimilarity(text1: string, text2: string): number {
// Implement text similarity algorithm
// This could use Levenshtein distance, Jaccard similarity, etc.
// For simplicity, this is a placeholder
return 0; // Placeholder value
}
/**
* Normalize text for comparison
*/
private normalizeText(text: string): string {
return text
.replace(/\s+/g, ' ')
.replace(/[\u2018\u2019]/g, "'")
.replace(/[\u201C\u201D]/g, '"')
.trim();
}
/**
* Generate a diff showing where texts differ
*/
private highlightDifferences(text1: string, text2: string): string {
// Implement diff generation logic
// Placeholder for now
return '';
}
}
Content Script Integration
The content script brings everything together:
// Main content script
(async function() {
const c2paDetector = new C2PADetector();
const textDetector = new TextQuoteDetector();
const validator = new YousedditManifestValidator();
const ledgerApi = new YousedditLedgerAPI();
// Process standard C2PA media
const mediaElements = c2paDetector.detectC2PAMedia(document);
for (const element of mediaElements) {
try {
const manifest = await validator.getManifest(element);
if (!manifest) continue;
// Standard C2PA validation
const validationResult = await validator.validateManifest(manifest);
// Check for YouSeddit blockchain assertions
const blockchainResult = await validator.checkBlockchainAssertion(manifest);
// Create and display validation UI
displayMediaValidation(element, validationResult, blockchainResult);
} catch (error) {
console.error('Media validation error:', error);
}
}
// Process text quotes
const quoteElements = textDetector.scanForQuotes(document);
for (const quote of quoteElements) {
try {
// Verify quote against blockchain
const blockchainResult = await ledgerApi.verifyContent(quote.blockchainId);
if (blockchainResult.verified && blockchainResult.authenticText) {
// Validate quote text against authentic text
const textValidator = new TextValidator();
const textMatch = textValidator.validateText(
quote.text,
blockchainResult.authenticText
);
// Verify domain contract
const contractResult = await ledgerApi.verifyDomainContract(
window.location.hostname,
quote.blockchainId
);
// Display validation UI
displayTextValidation(quote.element, textMatch, blockchainResult, contractResult);
}
} catch (error) {
console.error('Text validation error:', error);
}
}
})();
Key Enhancements
The YouSeddit extension makes several key enhancements to the base c2pa-extension-validator:
1. Extended C2PA Format Support
Added support for Youseddit-specific C2PA assertions:
{
"label": "youseddit.blockchain",
"data": {
"blockchainId": "0x7d931ff3a802d6c5...",
"ledgerType": "ethereum",
"contentType": "quote",
"timestampVerified": "2025-03-15T14:22:31Z"
}
}
2. Text Quote Detection
Enhanced content scanning to detect:
- Blockquote elements
- Text in quotation marks
- Elements with data attributes referencing YouSeddit blockchain IDs
- Adjacent attribution links with YouSeddit verification URLs
3. Smart Contract Validation
Added validation of domain authorization through:
- Checking the domain against YouSeddit contract registry
- Validating license terms and expiration
- Verifying payment status for quote usage
4. Enhanced User Interface
Improved the user interface with:
- Text-specific validation indicators
- Detailed verification panels showing blockchain status
- Smart contract information display
- Highlighting of differences between quoted and authentic text
Building and Testing
Prerequisites
- Node.js 18+
- pnpm package manager
- Chrome or Edge for development testing
Setup
-
Clone the repository:
git clone https://github.com/Sanmarcsoft/youseddit-c2pa-extension.git cd youseddit-c2pa-extension -
Install dependencies:
pnpm install -
Build the extension:
pnpm build -
Load the extension in Chrome:
- Navigate to
chrome://extensions/ - Enable “Developer mode”
- Click “Load unpacked” and select the
distdirectory
- Navigate to
Testing
The extension includes comprehensive test cases:
# Run all tests
pnpm test
# Run specific test categories
pnpm test:c2pa # C2PA validation tests
pnpm test:blockchain # Blockchain integration tests
pnpm test:text # Text validation tests
pnpm test:e2e # End-to-end browser tests
Deployment
The extension will be packaged for distribution through:
- Chrome Web Store
- Microsoft Edge Add-ons Store
- Firefox Browser Add-ons
Each platform requires specific packaging and review processes, detailed in our deployment guide.
Future Development
Planned enhancements include:
- Offline Validation: Cache verification data for offline use
- API Integration: JavaScript API for website integration
- Browser Coverage: Support for additional browsers
- Performance Optimization: Reduce validation latency
- Expanded Text Detection: Improved algorithms for detecting quoted content