package main
import (
"crypto/x509"
"encoding/pem"
"fmt"
"html/template"
"io/ioutil"
"os"
"sort"
"time"
"./util"
)
func handleErr(err error, str string, a ...interface{}) {
a = append([]interface{}{err}, a...)
if err != nil {
fmt.Fprintf(os.Stderr, str, a...)
os.Exit(1)
}
}
func handleBool(ok bool, str string, a ...interface{}) {
if !ok {
fmt.Fprintf(os.Stderr, str, a...)
os.Exit(1)
}
}
var tmpl = template.Must(template.New("pem2html").
Funcs(template.FuncMap{
"red": red,
"green": green,
"date": util.Date2HTML,
"datetime": util.DateTime2HTML,
"colorDatetime": util.DateTime2ColorHTML,
"htmlcell": util.HTMLCellEscapeString,
}).Parse(`
`))
func getNow() time.Time {
stat, err := os.Stdin.Stat()
if err == nil {
return stat.ModTime()
} else {
return time.Now()
}
}
var now = getNow()
func green(t time.Time) string {
max := byte(0xF3)
// When did we get the cert?
// - 30 days ago => 0 green
// - just now => max green
greenness := util.MapRange(
util.TimeRange{now.AddDate(0, 0, -30), now},
util.ByteRange{0, max},
t)
return fmt.Sprintf("#%02X%02X%02X", max-greenness, max, max-greenness)
}
func red(t time.Time) string {
max := byte(0xF3)
// When with the cert expire?
// - now => max red
// - 30 days from now => 0 red
redness := util.MapRange(
util.TimeRange{now, now.AddDate(0, 0, 30)},
util.ByteRange{max, 0},
t)
return fmt.Sprintf("#%02X%02X%02X", max, max-redness, max-redness)
}
type Cert struct {
Socket string
Error string
X509 *x509.Certificate
}
func (cert Cert) Url() string {
return fmt.Sprintf("https://crt.sh/?serial=%036x", cert.X509.SerialNumber)
}
func (cert Cert) Class() string {
if cert.Error == "" {
return ""
} else {
return "invalid"
}
}
type Certs []Cert
// Len is the number of elements in the collection.
func (l Certs) Len() int {
return len(l)
}
// Less reports whether the element with
// index i should sort before the element with index j.
func (l Certs) Less(i, j int) bool {
return l[i].X509.NotAfter.After(l[j].X509.NotAfter)
}
// Swap swaps the elements with indexes i and j.
func (l Certs) Swap(i, j int) {
tmp := l[i]
l[i] = l[j]
l[j] = tmp
}
func main() {
data, err := ioutil.ReadAll(os.Stdin)
handleErr(err, "Error reading stdin: %v\n")
var certs Certs
for len(data) > 0 {
var certPem *pem.Block
certPem, data = pem.Decode(data)
var ok bool
var cert Cert
cert.Socket, ok = certPem.Headers["X-Socket"]
handleBool(ok, "Did not get X-Socket\n")
cert.Error, ok = certPem.Headers["X-Error"]
cert.X509, err = x509.ParseCertificate(certPem.Bytes)
if err != nil {
cert.X509 = new(x509.Certificate)
}
certs = append(certs, cert)
}
sort.Sort(certs)
handleErr(tmpl.Execute(os.Stdout, map[string]interface{}{"certs": certs, "now": now}), "Could not execute template: %v\n")
}