1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package web
4
5import (
6 "bnema.dev/ermite/internal/domain"
7)
8
9// SignatureBadge is the pill of a signed commit. Label is the verdict, Proto
10// the protocol ("SSH", "GPG", "X.509", empty when unknown), Class the style
11// (sig-ok, sig-warn, sig-bad, sig-none) and Title the tooltip that says why.
12type SignatureBadge struct {
13 Label, Proto, Class, Title string
14}
15
16// signatureProto is the display name of a signature format.
17func signatureProto(f domain.SignatureFormat) string {
18 switch f {
19 case domain.FormatSSH:
20 return "SSH"
21 case domain.FormatGPG:
22 return "GPG"
23 case domain.FormatX509:
24 return "X.509"
25 }
26 return ""
27}
28
29// signatureBadge is the badge of a verification, nil when there is nothing to
30// show: the commit was not checked, or (unless long, the commit page) it is
31// not signed.
32func signatureBadge(v domain.CommitVerification, long bool) *SignatureBadge {
33 switch v.Status {
34 case domain.StatusUnchecked:
35 return nil
36 case domain.StatusUnsigned:
37 if !long {
38 return nil
39 }
40 return &SignatureBadge{Label: "unsigned", Class: "sig-none", Title: "This commit is not signed"}
41 }
42 b := &SignatureBadge{Proto: signatureProto(v.Format)}
43 key := keyPhrase(v)
44 switch v.Status {
45 case domain.StatusVerified:
46 b.Label, b.Class = "Verified", "sig-ok"
47 b.Title = "Signed with " + key + " — verified for the committer email"
48 case domain.StatusUnknownKey:
49 b.Label, b.Class = "Unverified", "sig-warn"
50 b.Title = unknownKeyTitle(v)
51 case domain.StatusEmailMismatch:
52 b.Label, b.Class = "Unverified", "sig-warn"
53 b.Title = "Signed with " + key + " — this key is not trusted for the committer email"
54 case domain.StatusExpired:
55 b.Label, b.Class = "Unverified", "sig-warn"
56 b.Title = "Signed with " + key + " — the key or the signature expired"
57 case domain.StatusRevoked:
58 b.Label, b.Class = "Unverified", "sig-warn"
59 b.Title = "Signed with " + key + " — the key is revoked"
60 case domain.StatusBadSignature:
61 b.Label, b.Class = "Bad signature", "sig-bad"
62 b.Title = "The signature does not match the commit"
63 case domain.StatusUnsupported:
64 b.Label, b.Class = "Unverified", "sig-warn"
65 if proto := signatureProto(v.Format); proto != "" {
66 b.Title = proto + " signatures are not checked"
67 } else {
68 b.Title = "This kind of signature is not checked"
69 }
70 default:
71 return nil
72 }
73 return b
74}
75
76// keyPhrase names the signing key for a tooltip: "SSH key SHA256:… (title)".
77func keyPhrase(v domain.CommitVerification) string {
78 s := "a key"
79 if p := signatureProto(v.Format); p != "" {
80 s = p + " key"
81 }
82 if v.Fingerprint != "" {
83 s += " " + v.Fingerprint
84 }
85 if v.KeyTitle != "" {
86 s += " (" + visibleText(v.KeyTitle) + ")"
87 }
88 return s
89}
90
91// unknownKeyTitle is the tooltip of a signature by a key that is not trusted.
92func unknownKeyTitle(v domain.CommitVerification) string {
93 s := "Signed with an unknown "
94 if p := signatureProto(v.Format); p != "" {
95 s += p + " "
96 }
97 s += "key"
98 if v.Fingerprint != "" {
99 s += " " + v.Fingerprint
100 }
101 return s
102}