fix: match Verae Timestamping.app registration PDF and receipt fields

Parse completedAt/certificate/result from Verae API; enrich merkle via
POST /api/verify (blockIndex). Generate certificate with the same jsPDF
layout as register.html export. Preserve original filename (e.g. .html).
This commit is contained in:
George Lambert 2026-10-03 04:26:45 -04:00
commit c6d998a16d
2 changed files with 1110 additions and 198 deletions

View file

@ -100,7 +100,18 @@ func Run(opt Options) (Result, error) {
}
stem := StemFromPath(opt.SourcePDF, opt.DocumentName)
origPath := filepath.Join(outDir, stem+".pdf")
// Preserve original basename (e.g. .html) for the proven artifact + certificate label.
origBase := filepath.Base(opt.SourcePDF)
if opt.DocumentName != "" {
origBase = filepath.Base(opt.DocumentName)
if filepath.Ext(origBase) == "" {
origBase = origBase + filepath.Ext(opt.SourcePDF)
}
}
if origBase == "" || origBase == "." {
origBase = stem + ".pdf"
}
origPath := filepath.Join(outDir, origBase)
srcBytes, err := os.ReadFile(opt.SourcePDF)
if err != nil {
return Result{}, err
@ -116,7 +127,7 @@ func Run(opt Options) (Result, error) {
client := *opt.Client
client.Channel = opt.Channel
rec, err := client.Stamp(digest, stem+".pdf")
rec, err := client.Stamp(digest, origBase)
if err != nil {
return Result{}, err
}
@ -130,7 +141,7 @@ func Run(opt Options) (Result, error) {
// Always prefer the branded Registration Document (digests-only wording,
// no mcp.verae.ai). Edge attachPdf is optional and may still say MCP.
pdfBytes, err := pdfcert.Build(pdfcert.Input{
DocumentName: stem + ".pdf",
DocumentName: origBase,
SHA256: digest,
ReceiptID: rec.ReceiptID,
CreatedAt: rec.CreatedAt,
@ -148,18 +159,19 @@ func Run(opt Options) (Result, error) {
}
sidecar := map[string]any{
"helper_version": HelperVersion,
"document_name": stem + ".pdf",
"sha256": digest,
"receipt_id": rec.ReceiptID,
"created_at": rec.CreatedAt,
"merkle": rec.Merkle,
"channel": string(opt.Channel),
"base_url": rec.BaseURL,
"original_pdf": filepath.Base(origPath),
"helper_version": HelperVersion,
"document_name": origBase,
"sha256": digest,
"receipt_id": rec.ReceiptID,
"created_at": rec.CreatedAt,
"merkle": rec.Merkle,
"channel": string(opt.Channel),
"base_url": rec.BaseURL,
"original_file": filepath.Base(origPath),
"certificate_pdf": filepath.Base(certPath),
"byte_length": len(srcBytes),
"saved_at": time.Now().UTC().Format(time.RFC3339),
"byte_length": len(srcBytes),
"status": "ok",
"saved_at": time.Now().UTC().Format(time.RFC3339),
}
jsonPath := filepath.Join(outDir, stem+".verae.json")
jb, err := json.MarshalIndent(sidecar, "", " ")

View file

@ -84,7 +84,10 @@ func TestRunVeraeRendersLocalCert(t *testing.T) {
VeraeBase: "https://api.test",
VeraeToken: "jwt",
HTTPDo: func(req *http.Request) (*http.Response, error) {
body := `{"certificate":"cidLocal1","timestamp":"2026-10-03T12:00:00Z","existing":true}`
body := `{"existing":true,"certificate":"cidLocal1","receipts":[{"certificate":"cidLocal1","completedAt":"2026-10-03T12:00:00Z","blockIndex":"99"}]}`
if strings.HasPrefix(req.URL.Path, "/api/hash/") {
body = `{"receipts":[{"certificate":"cidLocal1","completedAt":"2026-10-03T12:00:00Z","blockIndex":"99"}]}`
}
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil
},
}