docs: initial spec and implementation plan for PrintToVeraeTimeStamp

This commit is contained in:
George Lambert 2026-10-03 02:59:16 -04:00
commit e91275a67c
4 changed files with 243 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
/bin/
/dist/
*.exe
*.dmg
*.pkg
*.msi
.DS_Store

27
README.md Normal file
View file

@ -0,0 +1,27 @@
# PrintToVeraeTimeStamp
A virtual printer for macOS, Linux, and Windows. Instead of (or in addition to) printing, it captures the print job as PDF, computes its SHA-256, timestamps that digest with the Verae Timestamping service, and lets you save or print the document together with its Verae timestamp certificate.
Only the digest is sent to Verae. The document never leaves your machine.
## Status
Design stage. See:
- [Spec](docs/superpowers/specs/2026-10-03-print-to-verae-timestamp.md)
- [Implementation plan](docs/superpowers/plans/2026-10-03-print-to-verae-timestamp.md)
## How it works (short)
```
Any app → Print → "Verae Timestamp" printer
→ job captured as PDF (CUPS on macOS/Linux, IPP/PDF port on Windows)
→ per-user helper: SHA-256 (whole document + per page)
→ Verae Timestamp API (digest only) → receipt JSON / certificate
→ Save: original PDF + receipt (+ optional certificate page / embedded receipt)
→ Optional: forward to a real printer with certificate page
```
## License
TBD.

View file

@ -0,0 +1,84 @@
# PrintToVeraeTimeStamp — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Ship a "Verae Timestamp" virtual printer for macOS, Linux, and Windows per `docs/superpowers/specs/2026-10-03-print-to-verae-timestamp.md`.
**Tech stack:** Go 1.26 (core + helper + CLI), `pdfcpu` (page split, incremental update, attachments), `skip2/go-qrcode`, Fyne or Wails for cross-platform helper UI (decide in Task 1), CUPS backend in Go (static binary), Windows port monitor in C/C++ (minimal) or IPP service in Go.
## Global constraints
- Digests only to Verae. Never document bytes.
- Backend/port-monitor code does no networking; it only spools.
- Canonical JSON (fixed struct tags) for manifests so digests are reproducible.
- All binaries signed per platform before release.
## Repository layout
| Path | Role |
|---|---|
| `cmd/verae-print/` | CLI: `stamp`, `verify`, `login`, `spool-watch` |
| `cmd/verae-print-helper/` | Per-user helper (tray/menu-bar UI) |
| `cmd/cups-backend-verae/` | CUPS backend (macOS + Linux) |
| `internal/hash/` | Doc + per-page + manifest hashing |
| `internal/veraeapi/` | Client: `/api/timestamp`, `/api/status`, `/api/hash`, `/api/verify` |
| `internal/receipt/` | Receipt JSON, offline queue |
| `internal/pdfout/` | Certificate page render, incremental-update embedding |
| `internal/spool/` | Spool protocol (job.pdf + job.json), watcher |
| `platform/macos/` | PDF Service app, LaunchAgent, pkg scripts, PPD |
| `platform/linux/` | PPD/lpadmin scripts, systemd user unit, deb/rpm |
| `platform/windows/` | Port monitor or IPP service, MSI (WiX) |
---
### Task 1: Spike & decisions
- [ ] Confirm Verae API certificate PDF availability (open question 1); record in spec.
- [ ] Prove incremental update with pdfcpu keeps original byte prefix intact (hash test).
- [ ] Decide helper UI toolkit (Fyne vs Wails) and Windows path (port monitor vs local IPP).
- [ ] Commit `docs: spike results`.
### Task 2: Core library (`internal/hash`, `internal/veraeapi`, `internal/receipt`)
- [ ] Tests: deterministic page hashes; API client against httptest (immediate certificate, existing, job polling, 401); offline queue retry.
- [ ] Implement; reuse request/response shapes from Datacube-Fuse `internal/stamp/global.go`.
- [ ] Commit `feat(core): hashing, Verae client, receipts`.
### Task 3: CLI `verae-print stamp|verify|login`
- [ ] `stamp file.pdf` → `.verae.json` (+ `--embed`, `--cert`).
- [ ] `verify file.pdf|file.stamped.pdf`.
- [ ] Commit `feat(cli): stamp and verify`.
### Task 4: PDF outputs (`internal/pdfout`)
- [ ] Certificate page (name, digest, time UTC + local, id, verify URL, QR, page-hash list).
- [ ] Incremental-update embed + attachment; verify prefix hash in tests.
- [ ] Commit `feat(pdf): certificate page and embedded receipt`.
### Task 5: macOS v0 — PDF Services
- [ ] App bundle in `~/Library/PDF Services/` calling the core; Save/Print/Both dialog.
- [ ] Commit `feat(macos): PDF Services entry`.
### Task 6: Spool protocol + helper
- [ ] `internal/spool`: job dir format, atomic hand-off, per-user dirs 0700.
- [ ] Helper: watch spool, process, dialog, settings, forward printing (`lp` / Windows print API), keychain token storage.
- [ ] Commit `feat(helper): spool watcher and UI`.
### Task 7: CUPS backend (macOS v1 + Linux)
- [ ] Go backend: read job from stdin/file arg, write to spool for job user, exit 0; `lpadmin` install scripts and PPD.
- [ ] Linux packaging (deb/rpm), systemd user unit; macOS LaunchAgent + signed/notarized pkg.
- [ ] Commit `feat(cups): verae backend and installers`.
### Task 8: Windows
- [ ] Per Task 1 decision: Print-to-PDF driver + port monitor writing to spool, or local IPP service.
- [ ] Tray helper build, WiX MSI, Authenticode signing.
- [ ] Commit `feat(windows): virtual printer and installer`.
### Task 9: Docs + release
- [ ] User guide per OS, verification guide, screenshots.
- [ ] CI builds for all three platforms; release artifacts.
- [ ] Commit `docs: user guide and release`.
## Order
```
Task 1 → Task 2 → Task 3 → Task 4 → Task 5 (macOS quick win)
└→ Task 6 → Task 7 (macOS v1 + Linux) → Task 8 (Windows) → Task 9
```

View file

@ -0,0 +1,125 @@
# PrintToVeraeTimeStamp — Design Spec
**Date:** 2026-10-03
**Owner:** George Lambert / Verae
**Status:** Draft
## 1. Goal
Provide a "Verae Timestamp" printer on macOS, Linux, and Windows. Printing to it:
1. Captures the exact print output as a PDF.
2. Computes SHA-256 of the whole PDF and of each page.
3. Submits the digest(s) to the Verae Timestamping service (digest only).
4. Receives the receipt (JSON, and certificate PDF if the API provides one).
5. Lets the user **Save**, **Print**, or **Both**: the original PDF, the receipt, and optionally a combined "PDF + certificate page" or a PDF with the receipt embedded without altering the original bytes.
## 2. Non-goals
- Sending document content to Verae (never).
- Proving the *source* document (Word/Pages/etc.) — the proof is over the printed PDF bytes.
- Acting as a general PDF editor.
## 3. Key design facts
- **The proof is over exact bytes.** Printing the same document twice produces different PDFs (timestamps, IDs, fonts). Therefore the captured PDF must always be saved alongside the receipt; that file is the verifiable artifact.
- **Embedding without breaking the hash.** If the receipt is embedded, it is appended as a PDF *incremental update* (attachment + annotation/certificate page). The original byte range is unchanged, so `sha256(first N bytes)` still matches. The receipt records `N`.
- **Per-page hashes.** Each page is extracted as a single-page PDF (deterministic extraction via the same library/version) and hashed; the list is included in a canonical manifest whose SHA-256 is also stamped. This allows proving individual pages.
## 4. Verae Timestamp API (as used today by Datacube-Fuse)
| Call | Purpose |
|---|---|
| `POST {base}/api/timestamp` body `{"data":<hex>,"digest":<hex>,"hashAlg":"SHA256","restamp":false}` | Stamp a digest. 200 with `certificate` or `existing` = done; otherwise returns a job id |
| `GET {base}/api/status/{jobId}` | Poll until completed |
| `GET {base}/api/hash/{digest}` | Look up existing stamp |
| `POST {base}/api/verify` | Verify |
- Default base: `https://api.veraetime.net`; `Authorization: Bearer <token>` from `~/.verae/auth.json` (keys `access_token` / `auth_token` / `id_token`).
- **Open question:** endpoint/format for a downloadable certificate PDF. Until confirmed, the helper renders its own certificate page from the receipt JSON (digest, time, certificate id, verify URL, QR code).
## 5. Architecture
```
┌──────────── OS print system ────────────┐
App ──▶ Print │ macOS/Linux: CUPS queue "Verae Timestamp" │
│ backend: verae (runs as lp, sandboxed) │──▶ spool dir (per job: job.pdf + job.json)
│ Windows: virtual printer → PDF port │
└──────────────────────────────────────────┘
│
▼
verae-print-helper (per-user, tray/menu-bar)
- watch spool, pick up job
- sha256 (doc + pages + manifest)
- stamp via API (queue offline → retry)
- dialog: Save / Print / Both / Cancel
- write: <name>.pdf, <name>.verae.json,
optional <name>.stamped.pdf
- optional: forward to real printer (+ cert page)
```
### 5.1 macOS
- **v0 (fast path):** PDF Services entry — "Timestamp with Verae" in the Print dialog's PDF menu. Installed to `~/Library/PDF Services/` as an app that receives the PDF path. No driver needed.
- **v1:** CUPS queue with custom backend `/usr/libexec/cups/backend/verae` + PPD (or IPP Everywhere). The backend is sandboxed and cannot show UI, so it writes to `/Library/Application Support/Verae/spool/<user>/` and exits; the menu-bar helper (LaunchAgent) picks it up.
- Signed + notarized `.pkg`.
### 5.2 Linux
- CUPS queue `Verae-Timestamp`, backend `/usr/lib/cups/backend/verae`, PDF input via the standard filter chain (`pdftopdf`). Spool to `/var/spool/verae/<user>/`; user helper runs as systemd user service (+ tray icon via StatusNotifier, or desktop notification with actions). Headless mode: auto-save to `~/Documents/Verae Timestamps/` with no dialog.
- Packages: `.deb`, `.rpm`; optional Flatpak for the helper only.
### 5.3 Windows
Options, in order of preference:
1. **Microsoft Print to PDF driver + custom port monitor** writing to the spool folder (port monitor DLL, installed by MSI). Proven and simple.
2. **Local IPP printer service** (helper exposes IPP Everywhere on 127.0.0.1); Windows 10/11 IPP class driver sends PDF or PWG raster. Same code as macOS/Linux option below.
3. Print Support App (UWP/MSIX) for the modern print path — later, if enterprise deployment needs it.
Helper is a tray app; MSI signed with Authenticode.
### 5.4 Optional unified path
A single local **IPP Everywhere printer service** (e.g. built on PAPPL or a Go IPP server) advertised via DNS-SD on loopback. macOS and Linux discover it driverlessly; Windows adds it with the IPP class driver. Reduces per-OS driver code; evaluate in the spike.
## 6. Outputs
For a job named `Contract.pdf`:
| File | Content |
|---|---|
| `Contract.pdf` | Exact captured bytes (the proven artifact) |
| `Contract.verae.json` | Receipt: doc sha256, page sha256 list, manifest sha256, Verae response(s), time, base URL, helper version, original byte length |
| `Contract.stamped.pdf` (optional) | Original bytes + incremental update containing certificate page and `Contract.verae.json` as attachment |
| `Contract.certificate.pdf` (optional) | Certificate page alone (from API if available, else rendered) |
Certificate page: document name, SHA-256, Verae timestamp time (UTC + local), certificate/receipt id, verify URL + QR code, page-hash list (first N, rest in attachment).
## 7. Settings
- Default action: ask / save / print / both.
- Save folder; filename pattern.
- Forward printer (real printer) for "Print" and "Both".
- Embed receipt (on/off); add certificate page when printing (on/off).
- Per-page hashing (on/off).
- Verae base URL + login (reuse `~/.verae/auth.json`; login via browser flow).
- Offline queue: if API unreachable, save locally, mark "pending", stamp later, update receipt.
## 8. Security & privacy
- Digest only over TLS; never the document.
- Spool dirs per user, mode 0700; jobs deleted after handling.
- Backend never runs network code (keeps the root/lp component tiny); all network in the user helper.
- Code signing on all platforms; installer verifies helper signature.
- Token stored in OS keychain where available (Keychain, libsecret, Credential Manager), falling back to `~/.verae/auth.json`.
## 9. Verification
`verae-print verify Contract.pdf [Contract.verae.json]` recomputes digests (and for `.stamped.pdf`, the original byte range) and checks them against the Verae API (`/api/hash/{digest}` or `/api/verify`).
## 10. Open questions
1. Certificate PDF endpoint/format in the Verae API.
2. Batch stamping (doc + pages + manifest in one call) vs stamping only the manifest digest.
3. Licensing and distribution channel (direct download vs App Store/Microsoft Store).