softwareAgent in c2pa.actions v1 must be a string (tstr), not an object. Now shows the AI model name prominently, e.g. "Imagen 4 (via C2PA Stamping Tool/1.0.0)" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| backend | ||
| certs | ||
| docker/postgres | ||
| frontend | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.base.json | ||
C2PA Stamping & Verification Tool
A full-stack web application for stamping files with C2PA (Coalition for Content Provenance and Authenticity) content credentials and verifying existing credentials. Built for Oliver Marketing Group (OMG) to manage provenance metadata on creative assets.
Features
- C2PA Signing — Stamp files with C2PA content credentials using X.509 certificates (PS256, ES256, ES384, ES512, Ed25519)
- C2PA Verification — Verify embedded content credentials and inspect manifest data
- Custom OMG Metadata — Attach job numbers, platform, and AI model information to signed assets
- Multi-format Support — JPEG, PNG, TIFF, WebP, AVIF, GIF, SVG, MP4, MOV, MP3, WAV, PDF
- Certificate Management — Upload, manage, and rotate signing certificates with encrypted private key storage (AES-256-GCM)
- Role-based Access — Three user roles: Viewer (verify only), Stamper (upload + sign), Admin (full access)
- Admin Panel — Manage users, platforms, and AI models without code changes
- File Preview — Image, video, and audio preview within the application
- Headless API — All functionality accessible via REST API for integration with other systems
- Dockerised — Full Docker Compose setup with PostgreSQL, Node.js backend, and React frontend
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | React 19, Vite 7, TypeScript, Tailwind CSS 4, Lucide Icons |
| Backend | Node.js 22, Fastify 5, TypeScript |
| C2PA Engine | @contentauth/c2pa-node (Rust bindings via NAPI) |
| ORM | Drizzle ORM |
| Database | PostgreSQL 16 |
| Auth | JWT with bcrypt password hashing |
| Containerisation | Docker Compose v2 |
Quick Start
Prerequisites
- Docker Desktop (or Docker Engine + Compose v2)
- A C2PA signing certificate (X.509 cert + private key in PEM format)
1. Clone and configure
git clone git@bitbucket.org:zlalani/c2pa-2026.git
cd c2pa-2026
cp .env.example .env
Edit .env and set:
CERT_ENCRYPTION_KEY— Generate withopenssl rand -hex 32POSTGRES_PASSWORD— Database password (default works for dev)
2. Add your certificate
Place your signing certificate files in the certs/ directory:
certs/
├── ps256.pem # Private key (PEM format)
└── ps256.pub # X.509 certificate (PEM format)
The filename prefix determines the algorithm: ps256, es256, es384, es512, ed25519.
Certificates are automatically imported on first startup.
3. Start all services
docker compose up --build -d
This starts three services:
| Service | URL | Port |
|---|---|---|
| Frontend | http://localhost:3050 | 3050 |
| Backend API | http://localhost:8050 | 8050 |
| PostgreSQL | — | 5470 |
4. Log in
Three default users are seeded on first startup:
| Password | Role | |
|---|---|---|
| admin@omg.agency | admin123 | Admin (full access) |
| stamper@omg.agency | stamp123 | Stamper (upload + sign) |
| viewer@omg.agency | view123 | Viewer (verify only) |
Architecture
C2PA-2026/
├── docker-compose.yml # Orchestrates all services
├── .env / .env.example # Environment configuration
├── certs/ # Signing certificates (gitignored)
├── backend/
│ ├── Dockerfile
│ └── src/
│ ├── index.ts # Entry point + seed runner
│ ├── app.ts # Fastify app factory
│ ├── config.ts # Zod-validated env config
│ ├── seed.ts # Auto-seed certs, users, platforms, models
│ ├── db/
│ │ ├── schema.ts # Drizzle table definitions
│ │ ├── connection.ts # Database connection
│ │ ├── migrate.ts # Migration runner
│ │ └── migrations/ # SQL migrations
│ ├── routes/
│ │ ├── files.ts # Upload, sign, verify, download, delete
│ │ ├── certificates.ts # Certificate CRUD
│ │ ├── auth.ts # Login, user management
│ │ ├── admin.ts # Platforms + AI models CRUD
│ │ └── health.ts # Health check
│ ├── services/
│ │ ├── c2pa.service.ts # Sign + verify with c2pa-node
│ │ ├── file.service.ts # File storage management
│ │ ├── certificate.service.ts # Cert CRUD + encryption
│ │ ├── crypto.service.ts # AES-256-GCM encryption
│ │ └── auth.service.ts # JWT auth + user management
│ └── middleware/
│ ├── auth.ts # JWT auth + role guards
│ ├── error-handler.ts
│ └── file-validation.ts # MIME + magic byte validation
└── frontend/
├── Dockerfile
├── nginx.conf # Reverse proxy + SPA fallback
└── src/
├── App.tsx # Router + auth provider
├── api/ # API client + typed endpoints
├── contexts/ # Auth context (login, roles)
├── components/
│ ├── layout/ # Sidebar + nav (role-aware)
│ ├── files/ # FileUpload, FileList, SignDialog
│ └── verification/ # ManifestTree, ValidationStatus
└── pages/
├── DashboardPage # Stats, quick upload
├── FilesPage # File list + filters
├── FileDetailPage # Preview, sign, verify, download
├── VerifyPage # Upload-and-verify workflow
├── CertificatesPage
├── AdminUsersPage
├── AdminSettingsPage # Platforms + AI models
└── LoginPage
API Reference
All endpoints require JWT authentication via Authorization: Bearer <token> header (except login and health).
Authentication
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/auth/login |
Login with email/password | None |
| GET | /api/auth/me |
Get current user | Any |
Files
| Method | Path | Description | Role |
|---|---|---|---|
| POST | /api/files/upload |
Upload a file (multipart) | Stamper, Admin |
| GET | /api/files |
List files (paginated, filterable) | Any |
| GET | /api/files/:id |
File details + preview URLs | Any |
| POST | /api/files/:id/sign |
Sign with C2PA credentials | Stamper, Admin |
| GET | /api/files/:id/verify |
Verify C2PA manifest | Any |
| POST | /api/files/verify-upload |
Verify an uploaded file (no save) | Any |
| GET | /api/files/:id/download?version=signed|original |
Download file | Any |
| DELETE | /api/files/:id |
Delete file | Admin |
Sign request body
{
"certificateId": "uuid (optional, uses default)",
"title": "Asset title",
"omgJobNumber": "OMG-2026-001",
"platform": "OMG",
"aiModel": "Imagen 4"
}
Certificates
| Method | Path | Description | Role |
|---|---|---|---|
| GET | /api/certificates |
List certificates | Any |
| GET | /api/certificates/:id |
Certificate details | Any |
| POST | /api/certificates |
Upload cert + key pair (multipart) | Admin |
| PUT | /api/certificates/:id/default |
Set as default signing cert | Admin |
| DELETE | /api/certificates/:id |
Remove certificate | Admin |
Admin
| Method | Path | Description | Role |
|---|---|---|---|
| GET | /api/admin/users |
List all users | Admin |
| POST | /api/admin/users |
Create user | Admin |
| PUT | /api/admin/users/:id/role |
Update user role | Admin |
| DELETE | /api/admin/users/:id |
Delete user | Admin |
| GET | /api/platforms |
List active platforms | Any |
| GET | /api/models |
List active AI models | Any |
| GET | /api/admin/platforms |
List all platforms | Admin |
| POST | /api/admin/platforms |
Create platform | Admin |
| DELETE | /api/admin/platforms/:id |
Delete platform | Admin |
| GET | /api/admin/models |
List all models | Admin |
| POST | /api/admin/models |
Create AI model | Admin |
| PUT | /api/admin/models/:id |
Update model | Admin |
| DELETE | /api/admin/models/:id |
Delete model | Admin |
Health
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/health |
Service status | None |
Headless API Usage (curl examples)
# Login
TOKEN=$(curl -s http://localhost:8050/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"stamper@omg.agency","password":"stamp123"}' \
| jq -r '.token')
# Upload
FILE_ID=$(curl -s http://localhost:8050/api/files/upload \
-H "Authorization: Bearer $TOKEN" \
-F "file=@photo.jpg" | jq -r '.id')
# Sign with OMG metadata
curl -s http://localhost:8050/api/files/$FILE_ID/sign \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Campaign Photo",
"omgJobNumber": "OMG-2026-042",
"platform": "OMG",
"aiModel": "Imagen 4"
}'
# Verify
curl -s http://localhost:8050/api/files/$FILE_ID/verify \
-H "Authorization: Bearer $TOKEN"
# Download signed file
curl -O http://localhost:8050/api/files/$FILE_ID/download?version=signed \
-H "Authorization: Bearer $TOKEN"
C2PA Metadata
When signing, the following C2PA standard fields are set:
- Claim Generator: C2PA Stamping Tool v1.0.0
- Action:
c2pa.createdwithtrainedAlgorithmicMediadigital source type - Manifest Metadata: OMG custom fields stored as key-value pairs (
omg:jobNumber,omg:platform,omg:aiModel,omg:stampedBy,omg:stampedAt)
The signed files can be verified at verify.contentauthenticity.org.
Security
- Private keys encrypted at rest with AES-256-GCM (key from environment variable)
- File MIME validation + magic byte verification to prevent spoofing
- Configurable file size limit (default 100MB)
- JWT authentication with 24-hour token expiry
- Role-based access control on all endpoints
- CORS restricted to frontend origin
- Rate limiting (100 requests/minute)
- No private key data exposed via API responses
- UUID-based file paths (no user input in paths)
User Roles
| Role | Upload | Sign | Verify | Download | Manage Certs | Manage Users | Manage Settings |
|---|---|---|---|---|---|---|---|
| Viewer | - | - | Yes | - | - | - | - |
| Stamper | Yes | Yes | Yes | Yes | - | - | - |
| Admin | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
Development
Local development (without Docker)
# Start PostgreSQL (or use Docker just for the DB)
docker compose up -d postgres
# Backend
cd backend
cp ../.env.example ../.env # configure env
npm install
npm run db:generate
npm run db:migrate
npm run dev # http://localhost:8050
# Frontend
cd frontend
npm install
npm run dev # http://localhost:5173
Database management
# Generate migration after schema changes
cd backend && DATABASE_URL=... npx drizzle-kit generate
# Run migrations
cd backend && DATABASE_URL=... npx tsx src/db/migrate.ts
# Open Drizzle Studio
cd backend && DATABASE_URL=... npx drizzle-kit studio
Seeded Data
On first startup, the application seeds:
- 3 users: admin, stamper, viewer (see login table above)
- Certificates: Auto-imported from
certs/directory - 2 platforms: OMG, Pencil
- 29 AI models: Google (Imagen 3/4, Veo 2/3, Gemini), OpenAI (DALL-E 3, GPT-4o, Sora), Stability AI, Adobe Firefly, Midjourney, Anthropic Claude, Meta, Black Forest Labs FLUX, Runway, Pika, Kuaishou Kling
All platforms and models are manageable through the Admin > Settings page without code changes.
Colour Scheme
- Primary: Black (
#000000) - Accent: Gold (
#FFC407) - Font: Montserrat (Google Fonts)
License
Proprietary — Oliver Marketing Group