feat: a key that can't be used is explained in the picker
CI / Checks (pull_request) Successful in 40s
PR title / Conventional title (pull_request) Successful in 1s

The key picker stays open until the link is made, saying "encrypting
with …" meanwhile. A key that can't be read, or doesn't keep to
share.keyRules, is shown in it in red with which rule it misses
("its value has 28 characters; share.keyRules needs 32
(minLength)"), to pick another.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kebandClaude Opus 5.5 committed 2026-10-13 13:24:21 +02:00
1 parent 166790d825
commit 027e748c92
6 files changed
+73 -16

No files matched your search

+23 -6
View File
@@ -137,8 +137,14 @@ func (m *Model) confirmShare(s sharing) {
func (m *Model) pickShareKey(s sharing) tea.Cmd {
cmd := m.openGoTo(tabSearch, true)
m.search.pick = func(m *Model, key ref.Ref) tea.Cmd {
// The picker showed what's shared: no need to ask again. It
// stays open until the link is made, to say why a key can't be
// used.
s.key = key
return m.seal(s) // the picker showed what's shared
m.search.pickErr, m.search.pickBusy = "", "encrypting with "+key.Name+"…"
cmd := m.seal(s)
m.flash = flash{}
return cmd
}
m.search.pickTitle = shareTitle(s)
m.search.pickLines = m.sharedFiles(s)
@@ -159,9 +165,7 @@ func (m *Model) pickPasted(text string) tea.Cmd {
m.flash = flash{text: "share: " + err.Error(), isErr: true}
return nil
}
pick := m.search.pick
m.search = nil
return pick(m, key)
return m.search.pick(m, key)
}
// seal reads the key and encrypts the files with it.
@@ -171,7 +175,7 @@ func (m *Model) seal(s sharing) tea.Cmd {
return func() tea.Msg {
v, version, err := read(s.key)
if err != nil {
return sealedMsg{err: fmt.Errorf("reading the key %s: %w", s.key.Name, err)}
return sealedMsg{err: &share.KeyError{Name: s.key.Name, Err: err}}
}
link, err := share.Seal(share.Header{Key: share.Pin(s.key, version), Repo: s.repo.Detail}, []byte(v.Reveal()), s.files, rules)
return sealedMsg{link: link, n: len(s.files), err: err}
@@ -179,11 +183,24 @@ func (m *Model) seal(s sharing) tea.Cmd {
}
func (m *Model) handleSealed(msg sealedMsg) tea.Cmd {
if msg.err != nil {
picking := m.search != nil && m.search.pick != nil
if picking {
m.search.pickBusy = ""
}
var bad *share.KeyError
switch {
case msg.err != nil && picking && errors.As(msg.err, &bad):
// Picked: say why in the picker, to pick another.
m.search.pickErr = "✗ " + strings.ToUpper(bad.Error()[:1]) + bad.Error()[1:]
return nil
case msg.err != nil:
m.noteErr(msg.err)
m.flash = flash{text: "share: " + msg.err.Error(), isErr: true}
return nil
}
if picking {
m.search = nil
}
m.dismissedLink = msg.link.String() // not offered back on focus
return m.copyText("encrypted link to "+plural(msg.n, "file"), msg.link.String(), false)
}