package pdfcert import ( "fmt" "strings" "time" ) // Input for a simple one-page Verae registration certificate PDF. type Input struct { DocumentName string SHA256 string ReceiptID string CreatedAt string Merkle string VerifyURL string Channel string } // Build returns a minimal PDF (no external deps) describing the stamp. func Build(in Input) ([]byte, error) { created := in.CreatedAt if created == "" { created = time.Now().UTC().Format(time.RFC3339) } local := "" if t, err := time.Parse(time.RFC3339, created); err == nil { local = t.Local().Format(time.RFC1123) } verify := in.VerifyURL if verify == "" && in.SHA256 != "" { verify = fmt.Sprintf("https://mcp.verae.ai/register.html?sha256=%s&receipt=%s", in.SHA256, in.ReceiptID) } lines := []string{ "Verae Timestamp Registration", "", "Document: " + sanitize(in.DocumentName), "SHA-256: " + in.SHA256, "Receipt ID: " + in.ReceiptID, "UTC: " + created, } if local != "" { lines = append(lines, "Local: "+local) } if in.Merkle != "" { lines = append(lines, "Merkle/block: "+in.Merkle) } if in.Channel != "" { lines = append(lines, "Channel: "+in.Channel) } lines = append(lines, "Verify: "+verify) lines = append(lines, "", "Digests only — document bytes were not uploaded.") return buildTextPDF(lines) } func sanitize(s string) string { s = strings.ReplaceAll(s, "(", "\\(") s = strings.ReplaceAll(s, ")", "\\)") s = strings.ReplaceAll(s, "\\", "\\\\") return s } // Minimal PDF 1.4 with Helvetica text lines. func buildTextPDF(lines []string) ([]byte, error) { var content strings.Builder content.WriteString("BT /F1 12 Tf 50 750 Td 14 TL\n") for i, line := range lines { if i > 0 { content.WriteString("T*\n") } content.WriteString("(") content.WriteString(sanitize(line)) content.WriteString(") Tj\n") } content.WriteString("ET\n") stream := content.String() objects := []string{ "<< /Type /Catalog /Pages 2 0 R >>", "<< /Type /Pages /Kids [3 0 R] /Count 1 >>", "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>", fmt.Sprintf("<< /Length %d >>\nstream\n%s\nendstream", len(stream), stream), "<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>", } var body strings.Builder body.WriteString("%PDF-1.4\n") offsets := make([]int, len(objects)+1) for i, obj := range objects { offsets[i+1] = body.Len() fmt.Fprintf(&body, "%d 0 obj\n%s\nendobj\n", i+1, obj) } xrefStart := body.Len() fmt.Fprintf(&body, "xref\n0 %d\n", len(objects)+1) body.WriteString("0000000000 65535 f \n") for i := 1; i <= len(objects); i++ { fmt.Fprintf(&body, "%010d 00000 n \n", offsets[i]) } fmt.Fprintf(&body, "trailer << /Size %d /Root 1 0 R >>\nstartxref\n%d\n%%%%EOF\n", len(objects)+1, xrefStart) return []byte(body.String()), nil }