repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

pico / tui / pubkeys
Eric Bower · 18 May 24

keyview.go

  1package pubkeys
  2
  3import (
  4	"fmt"
  5	"strings"
  6
  7	"github.com/picosh/pico/db"
  8	"github.com/picosh/pico/tui/common"
  9	"golang.org/x/crypto/ssh"
 10)
 11
 12func algo(keyType string) string {
 13	if idx := strings.Index(keyType, "@"); idx > 0 {
 14		return algo(keyType[0:idx])
 15	}
 16	parts := strings.Split(keyType, "-")
 17	if len(parts) == 2 {
 18		return parts[1]
 19	}
 20	if parts[0] == "sk" {
 21		return algo(strings.TrimPrefix(keyType, "sk-"))
 22	}
 23	return parts[0]
 24}
 25
 26type Fingerprint struct {
 27	Type      string
 28	Value     string
 29	Algorithm string
 30	Styles    common.Styles
 31}
 32
 33// String outputs a string representation of the fingerprint.
 34func (f Fingerprint) String() string {
 35	return fmt.Sprintf(
 36		"%s %s",
 37		f.Styles.ListKey.Render(strings.ToUpper(f.Algorithm)),
 38		f.Styles.ListKey.Render(f.Type+":"+f.Value),
 39	)
 40}
 41
 42// FingerprintSHA256 returns the algorithm and SHA256 fingerprint for the given
 43// key.
 44func FingerprintSHA256(styles common.Styles, k *db.PublicKey) (Fingerprint, error) {
 45	key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(k.Key))
 46	if err != nil {
 47		return Fingerprint{}, fmt.Errorf("failed to parse public key: %w", err)
 48	}
 49
 50	return Fingerprint{
 51		Algorithm: algo(key.Type()),
 52		Type:      "SHA256",
 53		Value:     strings.TrimPrefix(ssh.FingerprintSHA256(key), "SHA256:"),
 54		Styles:    styles,
 55	}, nil
 56}
 57
 58// wrap fingerprint to support additional states.
 59type fingerprint struct {
 60	Fingerprint
 61}
 62
 63func (f fingerprint) state(s keyState, styles common.Styles) string {
 64	if s == keyDeleting {
 65		return fmt.Sprintf(
 66			"%s %s",
 67			styles.Delete.Render(strings.ToUpper(f.Algorithm)),
 68			styles.Delete.Render(f.Type+":"+f.Value),
 69		)
 70	}
 71	return f.String()
 72}
 73
 74type styledKey struct {
 75	styles       common.Styles
 76	date         string
 77	fingerprint  fingerprint
 78	gutter       string
 79	keyLabel     string
 80	dateLabel    string
 81	commentLabel string
 82	commentVal   string
 83	dateVal      string
 84	note         string
 85}
 86
 87func (m Model) newStyledKey(styles common.Styles, key *db.PublicKey, active bool) styledKey {
 88	date := key.CreatedAt.Format(common.DateFormat)
 89	fp, err := FingerprintSHA256(styles, key)
 90	if err != nil {
 91		fp = Fingerprint{Value: "[error generating fingerprint]"}
 92	}
 93
 94	var note string
 95	if active {
 96		note = m.shared.Styles.Note.Render("• Current Key")
 97	}
 98
 99	// Default state
100	return styledKey{
101		styles:       styles,
102		date:         date,
103		fingerprint:  fingerprint{fp},
104		gutter:       " ",
105		keyLabel:     "Key:",
106		dateLabel:    "Added:",
107		commentLabel: "Name:",
108		commentVal:   key.Name,
109		dateVal:      styles.Label.Render(date),
110		note:         note,
111	}
112}
113
114// Selected state.
115func (k *styledKey) selected() {
116	k.gutter = common.VerticalLine(k.styles.Renderer, common.StateSelected)
117	k.keyLabel = k.styles.Label.Render("Key:")
118	k.dateLabel = k.styles.Label.Render("Added:")
119	k.commentLabel = k.styles.Label.Render("Name:")
120}
121
122// Deleting state.
123func (k *styledKey) deleting() {
124	k.gutter = common.VerticalLine(k.styles.Renderer, common.StateDeleting)
125	k.keyLabel = k.styles.Delete.Render("Key:")
126	k.dateLabel = k.styles.Delete.Render("Added:")
127	k.commentLabel = k.styles.Delete.Render("Name:")
128	k.dateVal = k.styles.Delete.Render(k.date)
129}
130
131func (k styledKey) render(state keyState) string {
132	switch state {
133	case keySelected:
134		k.selected()
135	case keyDeleting:
136		k.deleting()
137	}
138	return fmt.Sprintf(
139		"%s %s %s %s\n%s %s %s\n%s %s %s\n\n",
140		k.gutter, k.commentLabel, k.commentVal, k.note,
141		k.gutter, k.keyLabel, k.fingerprint.state(state, k.styles),
142		k.gutter, k.dateLabel, k.dateVal,
143	)
144}