docs: initial spec and implementation plan for PrintToVeraeTimeStamp
This commit is contained in:
commit
e91275a67c
4 changed files with 243 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
/bin/
|
||||||
|
/dist/
|
||||||
|
*.exe
|
||||||
|
*.dmg
|
||||||
|
*.pkg
|
||||||
|
*.msi
|
||||||
|
.DS_Store
|
||||||
27
README.md
Normal file
27
README.md
Normal 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.
|
||||||
|
|
@ -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
|
||||||
|
```
|
||||||
125
docs/superpowers/specs/2026-10-03-print-to-verae-timestamp.md
Normal file
125
docs/superpowers/specs/2026-10-03-print-to-verae-timestamp.md
Normal 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).
|
||||||
Loading…
Reference in a new issue