krz/gitbay
A CLI-first git forge.
clone: git clone https://gitbay.org/krz/gitbay.git
main: internal/sig/keys.go · raw
1package sig
2
3import (
4 "bytes"
5 "encoding/hex"
6 "fmt"
7 "time"
8
9 "github.com/ProtonMail/go-crypto/openpgp"
10)
11
12func keyIDHex(id uint64) string {
13 var b [8]byte
14 for i := 7; i >= 0; i-- {
15 b[i] = byte(id)
16 id >>= 8
17 }
18 return hex.EncodeToString(b[:])
19}
20
21// PGPKeyMeta is what `pgp add` needs to persist about an imported key.
22type PGPKeyMeta struct {
23 Fingerprint string // primary key, lowercase hex
24 Emails []string
25 ExpiresAt *time.Time
26 RevokedAt *time.Time
27}
28
29// ParsePGPKey extracts registration metadata from an armored public key.
30func ParsePGPKey(armored []byte) (PGPKeyMeta, error) {
31 ring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(armored))
32 if err != nil {
33 return PGPKeyMeta{}, fmt.Errorf("not a valid armored OpenPGP key: %w", err)
34 }
35 if len(ring) != 1 {
36 return PGPKeyMeta{}, fmt.Errorf("expected exactly one key, got %d", len(ring))
37 }
38 e := ring[0]
39 meta := PGPKeyMeta{
40 Fingerprint: hex.EncodeToString(e.PrimaryKey.Fingerprint),
41 }
42 for _, id := range e.Identities {
43 if id.UserId != nil && id.UserId.Email != "" {
44 meta.Emails = append(meta.Emails, id.UserId.Email)
45 }
46 }
47 // Primary key expiry from the self-signature.
48 if selfSig, _ := e.PrimarySelfSignature(); selfSig != nil && selfSig.KeyLifetimeSecs != nil && *selfSig.KeyLifetimeSecs > 0 {
49 t := e.PrimaryKey.CreationTime.Add(time.Duration(*selfSig.KeyLifetimeSecs) * time.Second)
50 meta.ExpiresAt = &t
51 }
52 for _, rev := range e.Revocations {
53 t := rev.CreationTime
54 if meta.RevokedAt == nil || t.Before(*meta.RevokedAt) {
55 meta.RevokedAt = &t
56 }
57 }
58 return meta, nil
59}