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}