summaryrefslogtreecommitdiff
path: root/bin-src/diff-pem2html.go
blob: c0d3e7dd429c7854491f4d82759ac7913253a57d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//go:build standalone

package main

import (
	"crypto/x509"
	"encoding/pem"
	"errors"
	"fmt"
	"html/template"
	"io"
	"os"

	"git.lukeshu.com/dashboard/bin-src/util"
)

//nolint:gochecknoglobals // would be const
var tmpl = template.Must(template.New("pem2html").
	Funcs(template.FuncMap{
		"htmlcell": util.HTMLCellEscapeString,
	}).Parse(`<table class=diff>
  <tr class="diff-del"><td colspan=4>--- tls.pem</td></tr>
  <tr class="diff-add"><td colspan=4>+++ crtsh.pem</td></tr>
  <tr class="diff-dat"><td colspan=4>@@ -1,{{.nTLS}} +1,{{.nCrtSh}} @@</td></tr>
{{range $cert := .certs}}
  <tr class={{$cert.Class}}>
    <td><a href="{{$cert.Url}}">{{$cert.Pfix | htmlcell}}</a></td>
    <td><a href="{{$cert.Url}}">{{$cert.X509.Subject.CommonName | htmlcell}}</a></td>
    <td><a href="{{$cert.Url}}">{{$cert.X509.NotBefore.Local.Format "2006-01-02 15:04:05"}}</a></td>
    <td><a href="{{$cert.Url}}">{{$cert.X509.NotAfter.Local.Format "2006-01-02 15:04:05"}}</a></td>
  </tr>
{{end}}
</table>
`))

type Cert struct {
	Url    string
	action string
	X509   *x509.Certificate
}

func (cert Cert) Pfix() string {
	return map[string]string{
		"add": "+",
		"del": "-",
		"ctx": " ",
	}[cert.action]
}

func (cert Cert) Class() string {
	return "diff-" + cert.action
}

func main() {
	if err := mainWithError(); err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "%s: error: %v", os.Args[0], err)
		os.Exit(1)
	}
}

func mainWithError() error {
	data, err := io.ReadAll(os.Stdin)
	if err != nil {
		return fmt.Errorf("reading stdin: %w", err)
	}

	var certs []Cert
	a := 0
	b := 0
	for len(data) > 0 {
		var certPem *pem.Block
		certPem, data = pem.Decode(data)

		var ok bool
		var cert Cert

		cert.Url, ok = certPem.Headers["X-Crt-Sh-Url"]
		if !ok {
			return errors.New("did not get X-Crt-Sh-Url")
		}

		cert.action, ok = certPem.Headers["X-Diff-Action"]
		if !ok {
			return errors.New("did not get X-Diff-Action")
		}
		switch cert.action {
		case "add":
			b++
		case "del":
			a++
		case "ctx":
			a++
			b++
		default:
			return fmt.Errorf("unknown X-Diff-Action: %q", cert.action)
		}

		cert.X509, err = x509.ParseCertificate(certPem.Bytes)
		if err != nil {
			cert.X509 = new(x509.Certificate)
		}

		certs = append(certs, cert)
	}

	if err := tmpl.Execute(os.Stdout, map[string]any{
		"certs":  certs,
		"nTLS":   a,
		"nCrtSh": b,
	}); err != nil {
		return fmt.Errorf("could not execute template: %w", err)
	}
	return nil
}