mirror of
https://github.com/FiloSottile/age.git
synced 2026-01-08 04:55:12 +00:00
internal/plugin,cmd/age: implement confirm protocol verb
This commit is contained in:
@@ -37,6 +37,7 @@ func parseRecipient(arg string) (age.Recipient, error) {
|
||||
}
|
||||
r.DisplayMessage = pluginDisplayMessage(r.Name())
|
||||
r.RequestValue = pluginRequestSecret(r.Name())
|
||||
r.Confirm = pluginConfirm(r.Name())
|
||||
return r, nil
|
||||
case strings.HasPrefix(arg, "age1"):
|
||||
return age.ParseX25519Recipient(arg)
|
||||
@@ -210,6 +211,7 @@ func parseIdentity(s string) (age.Identity, error) {
|
||||
}
|
||||
i.DisplayMessage = pluginDisplayMessage(i.Name())
|
||||
i.RequestValue = pluginRequestSecret(i.Name())
|
||||
i.Confirm = pluginConfirm(i.Name())
|
||||
return i, nil
|
||||
case strings.HasPrefix(s, "AGE-SECRET-KEY-1"):
|
||||
return age.ParseX25519Identity(s)
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
@@ -111,3 +112,30 @@ func pluginRequestSecret(name string) func(string, bool) (string, error) {
|
||||
return string(secret), nil
|
||||
}
|
||||
}
|
||||
|
||||
func pluginConfirm(name string) func(msg, yes, no string) (bool, error) {
|
||||
return func(message, yes, no string) (bool, error) {
|
||||
if no != "" {
|
||||
message += fmt.Sprintf(" (1 for %q, 2 for %q)", yes, no)
|
||||
selection, err := readSecret(message)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("could not read value for age-plugin-%s: %v", name, err)
|
||||
}
|
||||
switch strings.TrimSpace(string(selection)) {
|
||||
case "1":
|
||||
return true, nil
|
||||
case "2":
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("invalid selection %q", selection)
|
||||
}
|
||||
} else {
|
||||
message += fmt.Sprintf(" (press enter for %q)", yes)
|
||||
_, err := readSecret(message)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("could not read value for age-plugin-%s: %v", name, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ type Recipient struct {
|
||||
// wishes to request a value from the user. If RequestValue is nil or
|
||||
// returns an error, failure will be reported to the plugin.
|
||||
RequestValue func(message string, secret bool) (string, error)
|
||||
// Confirm is a callback that will be invoked by Unwrap if the plugin wishes
|
||||
// to request a confirmation from the user. If Confirm is nil or returns an
|
||||
// error, failure will be reported to the plugin.
|
||||
Confirm func(message, yes, no string) (bool, error)
|
||||
}
|
||||
|
||||
var _ age.Recipient = &Recipient{}
|
||||
@@ -152,6 +156,45 @@ ReadLoop:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "confirm":
|
||||
if len(s.Args) != 1 && len(s.Args) != 2 {
|
||||
return nil, fmt.Errorf("received malformed confirm stanza")
|
||||
}
|
||||
if r.Confirm == nil {
|
||||
ss := &format.Stanza{Type: "fail"}
|
||||
if err := ss.Marshal(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
yes, err := format.DecodeString(s.Args[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("received malformed confirm stanza")
|
||||
}
|
||||
var no []byte
|
||||
if len(s.Args) == 2 {
|
||||
no, err = format.DecodeString(s.Args[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("received malformed confirm stanza")
|
||||
}
|
||||
}
|
||||
msg := string(s.Body)
|
||||
if selection, err := r.Confirm(msg, string(yes), string(no)); err != nil {
|
||||
ss := &format.Stanza{Type: "fail"}
|
||||
if err := ss.Marshal(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ss := &format.Stanza{Type: "ok"}
|
||||
if selection {
|
||||
ss.Args = append(ss.Args, "yes")
|
||||
} else {
|
||||
ss.Args = append(ss.Args, "no")
|
||||
}
|
||||
if err := ss.Marshal(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "recipient-stanza":
|
||||
if len(s.Args) < 2 {
|
||||
return nil, fmt.Errorf("received malformed recipient stanza")
|
||||
@@ -211,6 +254,10 @@ type Identity struct {
|
||||
// wishes to request a value from the user. If RequestValue is nil or
|
||||
// returns an error, failure will be reported to the plugin.
|
||||
RequestValue func(message string, secret bool) (string, error)
|
||||
// Confirm is a callback that will be invoked by Unwrap if the plugin wishes
|
||||
// to request a confirmation from the user. If Confirm is nil or returns an
|
||||
// error, failure will be reported to the plugin.
|
||||
Confirm func(message, yes, no string) (bool, error)
|
||||
}
|
||||
|
||||
var _ age.Identity = &Identity{}
|
||||
@@ -248,6 +295,7 @@ func (i *Identity) Recipient() *Recipient {
|
||||
|
||||
DisplayMessage: i.DisplayMessage,
|
||||
RequestValue: i.RequestValue,
|
||||
Confirm: i.Confirm,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,6 +388,45 @@ ReadLoop:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "confirm":
|
||||
if len(s.Args) != 1 && len(s.Args) != 2 {
|
||||
return nil, fmt.Errorf("received malformed confirm stanza")
|
||||
}
|
||||
if i.Confirm == nil {
|
||||
ss := &format.Stanza{Type: "fail"}
|
||||
if err := ss.Marshal(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
yes, err := format.DecodeString(s.Args[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("received malformed confirm stanza")
|
||||
}
|
||||
var no []byte
|
||||
if len(s.Args) == 2 {
|
||||
no, err = format.DecodeString(s.Args[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("received malformed confirm stanza")
|
||||
}
|
||||
}
|
||||
msg := string(s.Body)
|
||||
if selection, err := i.Confirm(msg, string(yes), string(no)); err != nil {
|
||||
ss := &format.Stanza{Type: "fail"}
|
||||
if err := ss.Marshal(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ss := &format.Stanza{Type: "ok"}
|
||||
if selection {
|
||||
ss.Args = append(ss.Args, "yes")
|
||||
} else {
|
||||
ss.Args = append(ss.Args, "no")
|
||||
}
|
||||
if err := ss.Marshal(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "file-key":
|
||||
if len(s.Args) != 1 {
|
||||
return nil, fmt.Errorf("received malformed file-key stanza")
|
||||
|
||||
Reference in New Issue
Block a user