age-plugin: Add Callbacks::confirm

This commit is contained in:
Jack Grigg 2022-03-21 02:29:00 +00:00
parent abc2d978db
commit 753c0c1ca1
6 changed files with 84 additions and 0 deletions

1
Cargo.lock generated
View file

@ -107,6 +107,7 @@ name = "age-plugin"
version = "0.2.1"
dependencies = [
"age-core",
"base64",
"bech32",
"chrono",
"gumdrop",

View file

@ -9,6 +9,9 @@ and this project adheres to Rust's notion of
to 1.0.0 are beta releases.
## [Unreleased]
### Added
- `age_plugin::Callbacks::confirm`
### Changed
- MSRV is now 1.56.0.

View file

@ -10,6 +10,7 @@ edition = "2021"
[dependencies]
age-core = { version = "0.7.1", path = "../age-core", features = ["plugin"] }
base64 = "0.13"
bech32 = "0.8"
chrono = "0.4"

View file

@ -62,6 +62,34 @@ impl<'a, 'b, R: io::Read, W: io::Write> Callbacks<Error> for BidirCallbacks<'a,
.map(|res| res.map(|_| ()))
}
fn confirm(
&mut self,
message: &str,
yes_string: &str,
no_string: Option<&str>,
) -> age_core::plugin::Result<bool> {
let metadata: Vec<_> = Some(yes_string)
.into_iter()
.chain(no_string)
.map(|s| base64::encode_config(s, base64::STANDARD_NO_PAD))
.collect();
let metadata: Vec<_> = metadata.iter().map(|s| s.as_str()).collect();
self.0
.send("confirm", &metadata, message.as_bytes())
.and_then(|res| match res {
Ok(s) => match &s.args[..] {
[x] if x == "yes" => Ok(Ok(true)),
[x] if x == "no" => Ok(Ok(false)),
_ => Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid response to confirm command",
)),
},
Err(e) => Ok(Err(e)),
})
}
fn request_public(&mut self, message: &str) -> plugin::Result<String> {
self.0
.send("request-public", &[], message.as_bytes())

View file

@ -236,6 +236,29 @@ pub trait Callbacks<E> {
/// inserting a hardware key.
fn message(&mut self, message: &str) -> age_core::plugin::Result<()>;
/// Requests that the user provides confirmation for some action.
///
/// This can be used to, for example, request that a hardware key the plugin wants to
/// try either be plugged in, or skipped.
///
/// - `message` is the request or call-to-action to be displayed to the user.
/// - `yes_string` and (optionally) `no_string` will be displayed on buttons or next
/// to selection options in the user's UI.
///
/// Returns:
/// - `Ok(true)` if the user selected the option marked with `yes_string`.
/// - `Ok(false)` if the user selected the option marked with `no_string` (or the
/// default negative confirmation label).
/// - `Err(Error::Fail)` if the confirmation request could not be given to the user
/// (for example, if there is no UI for displaying messages).
/// - `Err(Error::Unsupported)` if the user's client does not support this callback.
fn confirm(
&mut self,
message: &str,
yes_string: &str,
no_string: Option<&str>,
) -> age_core::plugin::Result<bool>;
/// Requests a non-secret value from the user.
///
/// `message` will be displayed to the user, providing context for the request.

View file

@ -61,6 +61,34 @@ impl<'a, 'b, R: io::Read, W: io::Write> Callbacks<Error> for BidirCallbacks<'a,
.map(|res| res.map(|_| ()))
}
fn confirm(
&mut self,
message: &str,
yes_string: &str,
no_string: Option<&str>,
) -> age_core::plugin::Result<bool> {
let metadata: Vec<_> = Some(yes_string)
.into_iter()
.chain(no_string)
.map(|s| base64::encode_config(s, base64::STANDARD_NO_PAD))
.collect();
let metadata: Vec<_> = metadata.iter().map(|s| s.as_str()).collect();
self.0
.send("confirm", &metadata, message.as_bytes())
.and_then(|res| match res {
Ok(s) => match &s.args[..] {
[x] if x == "yes" => Ok(Ok(true)),
[x] if x == "no" => Ok(Ok(false)),
_ => Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid response to confirm command",
)),
},
Err(e) => Ok(Err(e)),
})
}
fn request_public(&mut self, message: &str) -> plugin::Result<String> {
self.0
.send("request-public", &[], message.as_bytes())