Extend and adjust the set of user ID designators.
- Rename the `Exact` designator semantics to `By`. By default, the `By` arguments are called `--userid`, `--userid-by-email`, and `--userid-by-name`. - Add a new set of designators called `Exact` for the arguments `--userid`, `--email`, and `--name`. The semantics of `Exact` are: the value must match a self-signed user ID, however, the returned user ID is just the value, not the matching self-signed user ID. That is, if there is a self-signed user ID `Alice <alice@example.org>`, `--email alice@example.org` matches and returns the user ID `<alice@example.org>`, and `--name Alice` returns the user ID `Alice`. - Change the semantics of `Add` user ID designators (by default, `--userid-or-add`, `--email-or-add`, and `--name-or-add`) so that they just return a user ID with just the specified value. That is `--email alice@example.org` returns the user ID `<alice@example.org>`. - The following commands use user ID designators and their semantics are unchanged: - `sq key approvals list`: Unchanged. - `sq key approvals update`: Unchanged. - `sq pki authenticate`: Unchanged. - `sq pki lookup`: Unchanged. - `sq pki path`: Unchanged. - The following commands use user ID designators and their semantics changed as follows: - `sq pki link add`: `--email-or-add` had the old `Add` semantics and now has the new `Add` semantics. - `sq pki link authorize`: `--email-or-add` had the old `Add` semantics and now has the new `Add` semantics. - `sq pki link retract`: `--email` had the old `Add` semantics and now has the new `Add` semantics. - `sq key userid revoke`: `--email-or-add` had the old `Add` semantics and now has the new `Add` semantics. - `sq key vouch add`: `--email-or-add` had the old `Add` semantics and now has the new `Add` semantics. - `sq key vouch authorize --email-or-add` had the old `Add` semantics and now has the new `Add` semantics.
This commit is contained in:
parent
f9d1112735
commit
c0ef0f5dbd
@ -107,7 +107,7 @@ pub struct ListCommand {
|
||||
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<
|
||||
userid_designator::ExactArgs,
|
||||
userid_designator::PlainByArgs,
|
||||
userid_designator::OptionalValue>,
|
||||
|
||||
#[clap(
|
||||
@ -243,7 +243,7 @@ pub struct UpdateCommand {
|
||||
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<
|
||||
userid_designator::ExactArgs,
|
||||
userid_designator::PlainByArgs,
|
||||
userid_designator::OptionalValue>,
|
||||
|
||||
#[clap(
|
||||
|
@ -219,7 +219,7 @@ pub struct RevokeCommand {
|
||||
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<
|
||||
userid_designator::ExactAndAddArgs,
|
||||
userid_designator::PlainByAndAddArgs,
|
||||
userid_designator::OneValue>,
|
||||
|
||||
#[clap(
|
||||
|
@ -180,7 +180,7 @@ pub struct AddCommand {
|
||||
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<
|
||||
userid_designator::AllExactAndAddArgs>,
|
||||
userid_designator::AllPlainByAndAddArgs>,
|
||||
|
||||
#[clap(
|
||||
long = "amount",
|
||||
@ -344,7 +344,7 @@ pub struct AuthorizeCommand {
|
||||
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<
|
||||
userid_designator::AllExactAndAddArgs>,
|
||||
userid_designator::AllPlainByAndAddArgs>,
|
||||
|
||||
#[clap(
|
||||
long = "amount",
|
||||
@ -535,7 +535,7 @@ with the email address alice@example.org.",
|
||||
command: &[
|
||||
"sq", "pki", "link", "add",
|
||||
"--cert=EB28F26E2739A4870ECC47726F0073F60FD0CBF0",
|
||||
"--email=alice@example.org",
|
||||
"--email-or-add=alice@example.org",
|
||||
],
|
||||
hide: &[],
|
||||
}),
|
||||
|
@ -96,7 +96,7 @@ pub struct Command {
|
||||
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<
|
||||
userid_designator::AllExactAndAddArgs>,
|
||||
userid_designator::AllPlainByAndAddArgs>,
|
||||
|
||||
#[clap(
|
||||
long = "amount",
|
||||
|
@ -106,7 +106,7 @@ pub struct Command {
|
||||
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<
|
||||
userid_designator::AllExactAndAddArgs>,
|
||||
userid_designator::AllPlainByAndAddArgs>,
|
||||
|
||||
#[clap(
|
||||
long = "amount",
|
||||
|
@ -14,35 +14,67 @@ pub type AllUserIDsArg = typenum::U1;
|
||||
/// Adds `--userid` `--email`, and `--name` arguments.
|
||||
///
|
||||
/// For `UserIDDesignator::resolve`, the value must match on a
|
||||
/// self-signed user ID, and returns the value as is.
|
||||
/// self-signed user ID, but returns the value as is. That is, if
|
||||
/// there is a self-signed user ID "Alice <alice@example.org>",
|
||||
/// "--email alice@example.org" matches and returns the user ID
|
||||
/// "<alice@example.org>".
|
||||
pub type ExactArgs = typenum::U2;
|
||||
|
||||
/// Adds `--userid`, `--userid-by-email`, and `--userid-by-name`
|
||||
/// arguments.
|
||||
///
|
||||
/// For `UserIDDesignator::resolve`, the value must correspond to a
|
||||
/// self-signed user ID. That is, if there is a self-signed user ID
|
||||
/// "Alice <alice@example.org>", "--email alice@example.org" matches
|
||||
/// and returns the matching user ID, i.e., "Alice
|
||||
/// <alice@example.org>".
|
||||
pub type ByArgs = typenum::U4;
|
||||
|
||||
/// Adds a `--userid-or-add`, `--email-or-add`, and `--name-or-add`
|
||||
/// argument.
|
||||
///
|
||||
/// For `UserIDDesignator::resolve`, acts like `ExactArgs`, but if
|
||||
/// there is no matching self-signed user ID, creates one from the
|
||||
/// value.
|
||||
pub type AddArgs = typenum::U4;
|
||||
pub type AddArgs = typenum::U8;
|
||||
|
||||
|
||||
/// Requires ByArgs, conflicts with ExactArgs. Renames ByArgs'
|
||||
/// arguments to `--userid`, `--email`, and `--name`.
|
||||
pub type PlainIsBy = typenum::U16;
|
||||
|
||||
/// Requires AddArgs, conflicts with ExactArgs. Renames AddArgs'
|
||||
/// arguments to `--userid`, `--email`, and `--name`.
|
||||
pub type PlainIsAdd = typenum::U8;
|
||||
pub type PlainIsAdd = typenum::U32;
|
||||
|
||||
|
||||
pub type PlainByArgs
|
||||
= <ByArgs as std::ops::BitOr<PlainIsBy>>::Output;
|
||||
|
||||
pub type PlainAddArgs
|
||||
= <AddArgs as std::ops::BitOr<PlainIsAdd>>::Output;
|
||||
|
||||
pub type AllPlainAddArgs
|
||||
= <AllUserIDsArg as std::ops::BitOr<PlainAddArgs>>::Output;
|
||||
|
||||
pub type ExactAndAddArgs
|
||||
= <<ExactArgs as std::ops::BitOr<AddArgs>>::Output
|
||||
pub type PlainByAndAddArgs
|
||||
= <<PlainIsBy as std::ops::BitOr<ByArgs>>::Output
|
||||
as std::ops::BitOr<AddArgs>>::Output;
|
||||
|
||||
pub type AllExactAndAddArgs
|
||||
= <<AllUserIDsArg as std::ops::BitOr<ExactAndAddArgs>>::Output
|
||||
as std::ops::BitOr<AddArgs>>::Output;
|
||||
pub type AllPlainByAndAddArgs
|
||||
= <AllUserIDsArg as std::ops::BitOr<PlainByAndAddArgs>>::Output;
|
||||
|
||||
#[cfg(test)]
|
||||
pub type ExactAndAddArgs
|
||||
= <ExactArgs as std::ops::BitOr<AddArgs>>::Output;
|
||||
|
||||
#[cfg(test)]
|
||||
pub type ExactByAndAddArgs
|
||||
= <ByArgs as std::ops::BitOr<ExactAndAddArgs>>::Output;
|
||||
|
||||
#[cfg(test)]
|
||||
pub type AllExactByAndAddArgs
|
||||
= <AllUserIDsArg as std::ops::BitOr<ExactByAndAddArgs>>::Output;
|
||||
|
||||
/// Argument parser options.
|
||||
|
||||
@ -94,7 +126,7 @@ impl Documentation for SelfSignedDocumentation {
|
||||
use UserIDDesignatorType::*;
|
||||
use UserIDDesignatorSemantics::*;
|
||||
match (typ, semantics) {
|
||||
(UserID, Exact) => {
|
||||
(UserID, Exact | By) => {
|
||||
("Use the specified self-signed user ID",
|
||||
Some("\
|
||||
Use the specified self-signed user ID
|
||||
@ -119,36 +151,40 @@ you need to use this option to explicitly opt in.")
|
||||
})
|
||||
}
|
||||
(Email, Exact) => {
|
||||
("\
|
||||
Use a user ID consisting of just the email address, if the email address \
|
||||
occurs in a self-signed user ID",
|
||||
None)
|
||||
}
|
||||
(Email, By) => {
|
||||
("Use the self-signed user ID with the specified email address",
|
||||
None)
|
||||
}
|
||||
(Email, Add) => {
|
||||
("\
|
||||
Use the self-signed user ID with the specified email address or use a \
|
||||
new user ID",
|
||||
("Use a user ID with the specified email address",
|
||||
Some("\
|
||||
Use the self-signed user ID with the specified email address or use a \
|
||||
new user ID
|
||||
Use a user ID with the specified email address
|
||||
|
||||
This first searches for a matching self-signed user ID. If there is \
|
||||
no self-signed user ID with the specified email, it uses \
|
||||
a new user ID with the specified email address, and no display name."))
|
||||
The user ID consists of just the email address. The email address does not \
|
||||
have to appear in a self-signed user ID."))
|
||||
}
|
||||
(Name, Exact) => {
|
||||
("\
|
||||
Use a user ID consisting of just the display name, if the display name \
|
||||
occurs in a self-signed user ID",
|
||||
None)
|
||||
}
|
||||
(Name, By) => {
|
||||
("Use the self-signed user ID with the specified display name",
|
||||
None)
|
||||
}
|
||||
(Name, Add) => {
|
||||
("\
|
||||
Use the self-signed user ID with the specified display name or use a \
|
||||
new user ID",
|
||||
("Use a user ID with the specified display name",
|
||||
Some("\
|
||||
Use the self-signed user ID with the specified display name or use a \
|
||||
new user ID
|
||||
Use a user ID with the specified display name
|
||||
|
||||
This first searches for a matching self-signed user ID. If there is \
|
||||
no self-signed user ID with the specified name, it uses a new user ID \
|
||||
with the specified display name, and no email address."))
|
||||
The user ID consists of just the display named. The display name does not \
|
||||
have to appear in a self-signed user ID."))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,13 +238,20 @@ pub enum UserIDDesignatorType {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum UserIDDesignatorSemantics {
|
||||
/// For `UserIDDesignator::resolve`, the value must match on a
|
||||
/// self-signed user ID and returns the self-signed user ID. That
|
||||
/// is, if there is a self-signed user ID "Alice
|
||||
/// <alice@example.org>", "--email alice@example.org" matches and
|
||||
/// returns the user ID "Alice <alice@example.org>".
|
||||
/// self-signed user ID, but returns the value. That is, if there
|
||||
/// is a self-signed user ID "Alice <alice@example.org>", "--email
|
||||
/// alice@example.org" matches and returns the user ID
|
||||
/// "<alice@example.org>".
|
||||
Exact,
|
||||
|
||||
/// For `UserIDDesignator::resolve`, acts like `ExactArgs`, but if
|
||||
/// For `UserIDDesignator::resolve`, the value must correspond to
|
||||
/// a self-signed user ID. That is, if there is a self-signed
|
||||
/// user ID "Alice <alice@example.org>", "--email
|
||||
/// alice@example.org" matches and returns the matching user ID,
|
||||
/// i.e., "Alice <alice@example.org>".
|
||||
By,
|
||||
|
||||
/// `UserIDDesignator::resolve`, acts like `ExactArgs`, but if
|
||||
/// there is no matching self-signed user ID, creates one from the
|
||||
/// value.
|
||||
Add,
|
||||
@ -221,6 +264,11 @@ impl UserIDDesignatorSemantics {
|
||||
matches!(self, &UserIDDesignatorSemantics::Exact)
|
||||
}
|
||||
|
||||
/// If `self` is `UserIDDesignatorSemantics::By`.
|
||||
fn is_by(&self) -> bool {
|
||||
matches!(self, &UserIDDesignatorSemantics::By)
|
||||
}
|
||||
|
||||
/// If `self` is `UserIDDesignatorSemantics::Add`.
|
||||
fn is_add(&self) -> bool {
|
||||
matches!(self, &UserIDDesignatorSemantics::Add)
|
||||
@ -287,6 +335,11 @@ impl UserIDDesignator {
|
||||
self.semantics().is_exact()
|
||||
}
|
||||
|
||||
/// If `self` is `UserIDDesignatorSemantics::By`.
|
||||
fn is_by(&self) -> bool {
|
||||
self.semantics().is_by()
|
||||
}
|
||||
|
||||
/// If `self` is `UserIDDesignatorSemantics::Add`.
|
||||
pub fn is_add(&self) -> bool {
|
||||
self.semantics().is_add()
|
||||
@ -436,13 +489,21 @@ where
|
||||
let arguments = Arguments::to_usize();
|
||||
let all_arg = (arguments & AllUserIDsArg::to_usize()) > 0;
|
||||
let exact_args = (arguments & ExactArgs::to_usize()) > 0;
|
||||
let by_args = (arguments & ByArgs::to_usize()) > 0;
|
||||
let add_args = (arguments & AddArgs::to_usize()) > 0;
|
||||
|
||||
let plain_is_by = (arguments & PlainIsBy::to_usize()) > 0;
|
||||
let plain_is_add = (arguments & PlainIsAdd::to_usize()) > 0;
|
||||
|
||||
// Can't use PlainIsAdd with ExactArgs.
|
||||
// Can't use PlainIsBy or PlainIsAdd with ExactArgs or with
|
||||
// each other.
|
||||
assert!(! (exact_args && plain_is_by));
|
||||
assert!(! (exact_args && plain_is_add));
|
||||
assert!(! (plain_is_by && plain_is_add));
|
||||
// If plain_is_xxx is set, then by_xxx must be set.
|
||||
if plain_is_by {
|
||||
assert!(by_args);
|
||||
}
|
||||
if plain_is_add {
|
||||
assert!(add_args);
|
||||
}
|
||||
@ -505,10 +566,10 @@ Use all self-signed user IDs"));
|
||||
|
||||
use UserIDDesignatorType::*;
|
||||
use UserIDDesignatorSemantics::*;
|
||||
if exact_args {
|
||||
if exact_args || plain_is_by {
|
||||
let full_name = "userid";
|
||||
let (help, long_help) = Docs::help(
|
||||
UserID, true, Exact);
|
||||
UserID, true, if plain_is_by { By } else { Exact });
|
||||
|
||||
let mut arg = clap::Arg::new(&full_name)
|
||||
.long(&full_name)
|
||||
@ -550,6 +611,65 @@ Use all self-signed user IDs"));
|
||||
arg_group = arg_group.arg(full_name);
|
||||
}
|
||||
|
||||
if by_args {
|
||||
let full_name = if plain_is_by {
|
||||
"email"
|
||||
} else {
|
||||
"userid-by-email"
|
||||
};
|
||||
|
||||
let (help, long_help) = Docs::help(Email, plain_is_by, By);
|
||||
|
||||
let mut arg = clap::Arg::new(&full_name)
|
||||
.long(&full_name)
|
||||
.value_name("EMAIL")
|
||||
.value_parser(parse_as_email)
|
||||
.action(action.clone())
|
||||
.help(help);
|
||||
if let Some(long_help) = long_help {
|
||||
arg = arg.long_help(long_help);
|
||||
}
|
||||
if all_arg {
|
||||
arg = arg.conflicts_with("all");
|
||||
}
|
||||
cmd = cmd.arg(arg);
|
||||
|
||||
arg_group = arg_group.arg(full_name);
|
||||
}
|
||||
|
||||
// plain_is_by is handled below. This improves the ordering.
|
||||
let render_by_name = |mut cmd: clap::Command,
|
||||
mut arg_group: clap::ArgGroup|
|
||||
{
|
||||
let full_name = if plain_is_by {
|
||||
"name"
|
||||
} else {
|
||||
"userid-by-name"
|
||||
};
|
||||
|
||||
let (help, long_help) = Docs::help(Name, plain_is_by, By);
|
||||
|
||||
let mut arg = clap::Arg::new(&full_name)
|
||||
.long(&full_name)
|
||||
.value_name("DISPLAY_NAME")
|
||||
.action(action.clone())
|
||||
.help(help);
|
||||
if let Some(long_help) = long_help {
|
||||
arg = arg.long_help(long_help);
|
||||
}
|
||||
if all_arg {
|
||||
arg = arg.conflicts_with("all");
|
||||
}
|
||||
cmd = cmd.arg(arg);
|
||||
|
||||
arg_group = arg_group.arg(full_name);
|
||||
|
||||
(cmd, arg_group)
|
||||
};
|
||||
if by_args && ! plain_is_by {
|
||||
(cmd, arg_group) = render_by_name(cmd, arg_group);
|
||||
}
|
||||
|
||||
if exact_args {
|
||||
let full_name = "email";
|
||||
let (help, long_help) = Docs::help(Email, true, Exact);
|
||||
@ -613,6 +733,10 @@ Use all self-signed user IDs"));
|
||||
arg_group = arg_group.arg(full_name);
|
||||
}
|
||||
|
||||
if by_args && plain_is_by {
|
||||
(cmd, arg_group) = render_by_name(cmd, arg_group);
|
||||
}
|
||||
|
||||
if add_args {
|
||||
let full_name = if plain_is_add {
|
||||
"name"
|
||||
@ -677,13 +801,21 @@ where
|
||||
let arguments = Arguments::to_usize();
|
||||
let all_arg = (arguments & AllUserIDsArg::to_usize()) > 0;
|
||||
let exact_args = (arguments & ExactArgs::to_usize()) > 0;
|
||||
let by_args = (arguments & ByArgs::to_usize()) > 0;
|
||||
let add_args = (arguments & AddArgs::to_usize()) > 0;
|
||||
|
||||
let plain_is_by = (arguments & PlainIsBy::to_usize()) > 0;
|
||||
let plain_is_add = (arguments & PlainIsAdd::to_usize()) > 0;
|
||||
|
||||
// Can't use PlainIsAdd with ExactArgs or with each other.
|
||||
// Can't use PlainIsBy or PlainIsAdd with ExactArgs or with
|
||||
// each other.
|
||||
assert!(! (exact_args && plain_is_by));
|
||||
assert!(! (exact_args && plain_is_add));
|
||||
assert!(! (plain_is_by && plain_is_add));
|
||||
// If plain_is_xxx is set, then by_xxx must be set.
|
||||
if plain_is_by {
|
||||
assert!(by_args);
|
||||
}
|
||||
if plain_is_add {
|
||||
assert!(add_args);
|
||||
}
|
||||
@ -728,6 +860,35 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if by_args {
|
||||
if plain_is_by {
|
||||
if let Ok(Some(userids)) = matches.try_get_many::<String>("userid") {
|
||||
for userid in userids.cloned() {
|
||||
designators.push(
|
||||
UserIDDesignator::UserID(By, userid));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Ok(Some(emails))
|
||||
= matches.try_get_many::<String>(
|
||||
if plain_is_by { "email" } else { "userid-by-email" })
|
||||
{
|
||||
for email in emails.cloned() {
|
||||
designators.push(
|
||||
UserIDDesignator::Email(By ,email));
|
||||
}
|
||||
}
|
||||
if let Ok(Some(names))
|
||||
= matches.try_get_many::<String>(
|
||||
if plain_is_by { "name" } else { "userid-by-name" })
|
||||
{
|
||||
for name in names.cloned() {
|
||||
designators.push(
|
||||
UserIDDesignator::Name(By, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if add_args {
|
||||
if let Ok(Some(userids))
|
||||
= matches.try_get_many::<String>(
|
||||
@ -866,7 +1027,7 @@ mod test {
|
||||
|
||||
macro_rules! check {
|
||||
($t:ty,
|
||||
$plain:expr, $add:expr) =>
|
||||
$plain:expr, $by:expr, $add:expr) =>
|
||||
{{
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(name = "prog")]
|
||||
@ -930,6 +1091,36 @@ mod test {
|
||||
assert!(m.is_err());
|
||||
}
|
||||
|
||||
// Check if --userid-by-email is recognized.
|
||||
let m = command.clone().try_get_matches_from(vec![
|
||||
"prog",
|
||||
"--userid-by-email", "alice@example.org",
|
||||
"--userid-by-email", "bob@example.org",
|
||||
]);
|
||||
if $by {
|
||||
let m = m.expect("valid arguments");
|
||||
let c = CLI::from_arg_matches(&m).expect("ok");
|
||||
assert_eq!(c.userids.designators.len(), 2);
|
||||
assert!(c.userids.designators.iter().all(|d| d.is_by()));
|
||||
} else {
|
||||
assert!(m.is_err());
|
||||
}
|
||||
|
||||
// Check if --userid-by-name is recognized.
|
||||
let m = command.clone().try_get_matches_from(vec![
|
||||
"prog",
|
||||
"--userid-by-name", "alice",
|
||||
"--userid-by-name", "bob",
|
||||
]);
|
||||
if $by {
|
||||
let m = m.expect("valid arguments");
|
||||
let c = CLI::from_arg_matches(&m).expect("ok");
|
||||
assert_eq!(c.userids.designators.len(), 2);
|
||||
assert!(c.userids.designators.iter().all(|d| d.is_by()));
|
||||
} else {
|
||||
assert!(m.is_err());
|
||||
}
|
||||
|
||||
// Either --email is unknown, or the --email's value
|
||||
// is invalid.
|
||||
let m = command.clone().try_get_matches_from(vec![
|
||||
@ -986,14 +1177,19 @@ mod test {
|
||||
}
|
||||
|
||||
use UserIDDesignatorSemantics::*;
|
||||
// plain, add
|
||||
check!(typenum::U0, None, false);
|
||||
check!(ExactArgs, Exact, false);
|
||||
check!(AddArgs, None, true);
|
||||
check!(PlainAddArgs, Add, false);
|
||||
check!(AllPlainAddArgs, Add, false);
|
||||
check!(ExactAndAddArgs, Exact, true);
|
||||
check!(AllExactAndAddArgs, Exact, true);
|
||||
// plain, by, add
|
||||
check!(typenum::U0, None, false, false);
|
||||
check!(ExactArgs, Exact, false, false);
|
||||
check!(ByArgs, None, true, false);
|
||||
check!(AddArgs, None, false, true);
|
||||
check!(PlainByArgs, By, false, false);
|
||||
check!(PlainAddArgs, Add, false, false);
|
||||
check!(AllPlainAddArgs, Add, false, false);
|
||||
check!(PlainByAndAddArgs, By, false, true);
|
||||
check!(AllPlainByAndAddArgs, By, false, true);
|
||||
check!(ExactAndAddArgs, Exact, false, true);
|
||||
check!(ExactByAndAddArgs, Exact, true, true);
|
||||
check!(AllExactByAndAddArgs, Exact, true, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1107,7 +1303,7 @@ mod test {
|
||||
#[clap(name = "prog")]
|
||||
struct CLI {
|
||||
#[command(flatten)]
|
||||
pub userids: UserIDDesignators<AllExactAndAddArgs>,
|
||||
pub userids: UserIDDesignators<AllExactByAndAddArgs>,
|
||||
}
|
||||
|
||||
let command = CLI::command();
|
||||
@ -1135,6 +1331,8 @@ mod test {
|
||||
// Can't combine --all with any other designator.
|
||||
for (arg, value) in &[
|
||||
("--userid", "foo"),
|
||||
("--userid-by-email", "foo@example.org"),
|
||||
("--userid-by-name", "foo"),
|
||||
("--userid-or-add", "foo"),
|
||||
("--email", "foo@example.org"),
|
||||
("--email-or-add", "foo@example.org"),
|
||||
|
@ -169,20 +169,26 @@ where
|
||||
ambiguous_email = true;
|
||||
}
|
||||
|
||||
if semantics == &Exact || semantics == &Add {
|
||||
found = true;
|
||||
|
||||
if semantics == &By {
|
||||
userids.push(designator.clone()
|
||||
.resolve_to(ua.userid().clone()));
|
||||
} else {
|
||||
userids.push(designator.clone()
|
||||
.resolve_to(email_userid.clone()));
|
||||
// Since we're not returning the
|
||||
// matching self-signed user ID, we
|
||||
// don't need to worry about ambiguous
|
||||
// matches.
|
||||
break;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ! found {
|
||||
match semantics {
|
||||
Exact => {
|
||||
Exact | By => {
|
||||
eprintln!("None of the self-signed user IDs \
|
||||
are for the email address {:?}.",
|
||||
email);
|
||||
@ -221,21 +227,27 @@ where
|
||||
ambiguous_name = true;
|
||||
}
|
||||
|
||||
if semantics == &Exact || semantics == &Add {
|
||||
found = true;
|
||||
|
||||
if semantics == &By {
|
||||
userids.push(designator.clone()
|
||||
.resolve_to(ua.userid().clone()));
|
||||
} else {
|
||||
userids.push(designator.clone()
|
||||
.resolve_to(name_userid.clone()));
|
||||
// Since we're not returning the
|
||||
// matching self-signed user ID, we
|
||||
// don't need to worry about ambiguous
|
||||
// matches.
|
||||
break;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ! found {
|
||||
match semantics {
|
||||
Exact => {
|
||||
Exact | By => {
|
||||
eprintln!("None of the self-signed user IDs \
|
||||
are for the display name {:?}.",
|
||||
name);
|
||||
|
@ -235,6 +235,7 @@ pub enum UserIDArg<'a> {
|
||||
Name(&'a str),
|
||||
AddUserID(&'a str),
|
||||
AddEmail(&'a str),
|
||||
ByEmail(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for UserIDArg<'a> {
|
||||
@ -263,7 +264,8 @@ impl UserIDArg<'_> {
|
||||
| UserIDArg::Email(s)
|
||||
| UserIDArg::Name(s)
|
||||
| UserIDArg::AddUserID(s)
|
||||
| UserIDArg::AddEmail(s) =>
|
||||
| UserIDArg::AddEmail(s)
|
||||
| UserIDArg::ByEmail(s) =>
|
||||
{
|
||||
s
|
||||
}
|
||||
@ -283,6 +285,8 @@ impl UserIDArg<'_> {
|
||||
cmd.arg("--userid-or-add").arg(userid),
|
||||
UserIDArg::AddEmail(email) =>
|
||||
cmd.arg("--email-or-add").arg(email),
|
||||
UserIDArg::ByEmail(email) =>
|
||||
cmd.arg("--userid-by-email").arg(email),
|
||||
};
|
||||
}
|
||||
|
||||
@ -302,6 +306,8 @@ impl UserIDArg<'_> {
|
||||
unreachable!(),
|
||||
UserIDArg::AddEmail(email) =>
|
||||
unreachable!(),
|
||||
UserIDArg::ByEmail(userid) =>
|
||||
unreachable!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -320,9 +320,7 @@ fn userid_designators() {
|
||||
UserIDArg::Email(other_email)).is_err());
|
||||
revocations(&sq, cert.key_handle(), other_userid, 0);
|
||||
|
||||
// 4. --email-or-add: use the self-signed user ID with the
|
||||
// specified email address, or use a user ID with the email
|
||||
// address.
|
||||
// 4. --email-or-add: use a user ID with the email address.
|
||||
let (cert, fpr, sq) = setup();
|
||||
|
||||
// Self-signed and authenticated.
|
||||
@ -330,9 +328,10 @@ fn userid_designators() {
|
||||
&[], &fpr, UserIDArg::UserID(self_signed_userid)).is_ok());
|
||||
assert!(revoke(&sq, cert.key_handle(),
|
||||
UserIDArg::AddEmail(self_signed_email)).is_ok());
|
||||
revocations(&sq, cert.key_handle(), self_signed_userid, 1);
|
||||
revocations(&sq, cert.key_handle(), self_signed_userid, 0);
|
||||
revocations(&sq, cert.key_handle(), &format!("<{}>", self_signed_email), 1);
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID(self_signed_userid)).is_err());
|
||||
&[], &fpr, UserIDArg::UserID(&format!("<{}>", self_signed_email))).is_err());
|
||||
|
||||
// Authenticated, but not self-signed.
|
||||
assert!(sq.pki_authenticate(
|
||||
|
@ -785,15 +785,18 @@ fn no_ambiguous_email() {
|
||||
|
||||
sq.tick(1);
|
||||
|
||||
// Ambiguous.
|
||||
// --email links the matching self-signed user ID: Ambiguous is
|
||||
// not allowed.
|
||||
assert!(
|
||||
sq.pki_link_add_maybe(
|
||||
&[], alice.key_handle(), &[UserIDArg::Email("alice@example.org")])
|
||||
.is_err());
|
||||
// --email-or-add links a user ID with the email address:
|
||||
// Ambiguous is allowed.
|
||||
assert!(
|
||||
sq.pki_link_add_maybe(
|
||||
&[], alice.key_handle(), &[UserIDArg::AddEmail("alice@example.org")])
|
||||
.is_err());
|
||||
.is_ok());
|
||||
|
||||
// Not a self-signed user ID.
|
||||
assert!(
|
||||
@ -806,7 +809,7 @@ fn no_ambiguous_email() {
|
||||
&[], alice.key_handle(),
|
||||
&[UserIDArg::UserID("Alice <alice@example.org>")]);
|
||||
|
||||
// As well as adding as a user ID.
|
||||
// As well as adding a user ID.
|
||||
sq.pki_link_add(
|
||||
&[], alice.key_handle(),
|
||||
&[UserIDArg::AddUserID("<alice@example.org>")]);
|
||||
@ -883,7 +886,12 @@ fn link_userid_designators() {
|
||||
let mut sq = Sq::new();
|
||||
|
||||
let (cert, cert_path, _rev_path) = sq.key_generate(
|
||||
&[], &["Alice <alice@example.org>", "Alice <alice@an.org>" ]);
|
||||
&[],
|
||||
&[
|
||||
"Alice <alice@example.org>",
|
||||
"Alice <alice@an.org>",
|
||||
"Alice <alice@third.org>",
|
||||
]);
|
||||
let fpr = cert.fingerprint().to_string();
|
||||
sq.key_import(cert_path);
|
||||
|
||||
@ -938,6 +946,19 @@ fn link_userid_designators() {
|
||||
cert.key_handle(), UserIDArg::AddEmail("alice@example.com"));
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("<alice@example.com>")).is_ok());
|
||||
|
||||
// Use --email-or-add to link "<alice@third.org>", which is
|
||||
// part of the self signed user ID "Alice <alice@third.org>".
|
||||
// This should link "<alice@third.org>", not the self-signed
|
||||
// user ID.
|
||||
link(&mut sq,
|
||||
cert.key_handle(), UserIDArg::AddEmail("alice@third.org"));
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("<alice@third.org>")).is_ok());
|
||||
if ! authorize {
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("Alice <alice@third.org>")).is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -947,7 +968,11 @@ fn link_retract_userid_designators() {
|
||||
let mut sq = Sq::new();
|
||||
|
||||
let (cert, cert_path, _rev_path) = sq.key_generate(
|
||||
&[], &["Alice <alice@example.org>" ]);
|
||||
&[],
|
||||
&[
|
||||
"Alice <alice@example.org>",
|
||||
"<alice@some.org>",
|
||||
]);
|
||||
let fpr = cert.fingerprint().to_string();
|
||||
sq.key_import(cert_path);
|
||||
|
||||
@ -962,6 +987,12 @@ fn link_retract_userid_designators() {
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("Alice <alice@example.org>")).is_ok());
|
||||
|
||||
// We can't retract using --email: it retracts "<alice@example.org>".
|
||||
sq.tick(1);
|
||||
assert!(sq.pki_link_retract_maybe(
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::Email("alice@example.org") ]).is_err());
|
||||
|
||||
sq.tick(1);
|
||||
sq.pki_link_retract(&[], cert.key_handle(),
|
||||
&[ UserIDArg::UserID("Alice <alice@example.org>") ]);
|
||||
@ -976,16 +1007,20 @@ fn link_retract_userid_designators() {
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("Alice <alice@example.com>")).is_ok());
|
||||
|
||||
// We can't retract using --email: it retracts "<alice@example.com>".
|
||||
sq.tick(1);
|
||||
assert!(sq.pki_link_retract_maybe(
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::Email("alice@example.com") ]).is_err());
|
||||
|
||||
// But we can retract using --user "Alice <alice@example.com>".
|
||||
sq.pki_link_retract(&[], cert.key_handle(),
|
||||
&[ UserIDArg::UserID("Alice <alice@example.com>") ]);
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("Alice <alice@example.com>")).is_err());
|
||||
|
||||
// 2. Retract using "--email". The email address must be part of
|
||||
// a self-signed user ID, but it uses a user ID with just the email
|
||||
// address.
|
||||
// 2. Retract using "--email". It uses a user ID with just the
|
||||
// email address.
|
||||
|
||||
// Link "Alice <alice@example.org>", which is a self signed user
|
||||
// ID.
|
||||
@ -998,12 +1033,38 @@ fn link_retract_userid_designators() {
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("<alice@example.org>")).is_err());
|
||||
|
||||
// We can't unlink it using --email, because that doesn't match on
|
||||
// self-signed user IDs.
|
||||
sq.tick(1);
|
||||
sq.pki_link_retract(&[], cert.key_handle(),
|
||||
&[ UserIDArg::Email("alice@example.org") ]);
|
||||
assert!(sq.pki_link_retract_maybe(
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::Email("alice@example.org") ]).is_err());
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("Alice <alice@example.org>")).is_ok());
|
||||
|
||||
assert!(sq.pki_link_retract_maybe(
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::UserID("Alice <alice@example.org>") ]).is_ok());
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("Alice <alice@example.org>")).is_err());
|
||||
|
||||
// Link "<alice@some.org>", which is a self signed user ID.
|
||||
sq.tick(1);
|
||||
sq.pki_link_add(
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::UserID("<alice@some.org>") ]);
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("<alice@some.org>")).is_ok());
|
||||
|
||||
// We can unlink it using --email: that matchs on self-signed user
|
||||
// IDs.
|
||||
sq.tick(1);
|
||||
assert!(sq.pki_link_retract_maybe(
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::Email("alice@some.org") ]).is_ok());
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("<alice@some.org>")).is_err());
|
||||
|
||||
// Link "<alice@example.com>", which is not part of a self signed
|
||||
// user ID.
|
||||
sq.tick(1);
|
||||
@ -1069,9 +1130,10 @@ fn retract() {
|
||||
&[ UserIDArg::UserID("Alice <alice@example.org>") ]);
|
||||
|
||||
sq.tick(1);
|
||||
sq.pki_link_retract(
|
||||
// --email => "<alice@example.org>", which was not linked.
|
||||
assert!(sq.pki_link_retract_maybe(
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::Email("alice@example.org") ]);
|
||||
&[ UserIDArg::Email("alice@example.org") ]).is_err());
|
||||
}
|
||||
|
||||
sq.pki_link_add(
|
||||
@ -1084,8 +1146,7 @@ fn retract() {
|
||||
&[], cert.key_handle(),
|
||||
&[ UserIDArg::UserID("Alice <alice@example.com>") ]);
|
||||
|
||||
// We can't name "Alice <alice@example.com>" by email, because
|
||||
// it is not self-signed.
|
||||
// --email => "<alice@example.com>", which was not linked.
|
||||
sq.tick(1);
|
||||
assert!(sq.pki_link_retract_maybe(
|
||||
&[], cert.key_handle(),
|
||||
|
@ -545,7 +545,11 @@ fn userid_designators() {
|
||||
};
|
||||
|
||||
let (cert, cert_path, _rev_path) = sq.key_generate(
|
||||
&[], &["Alice <alice@example.org>", "Alice <alice@an.org>" ]);
|
||||
&[], &[
|
||||
"Alice <alice@example.org>",
|
||||
"Alice <alice@an.org>",
|
||||
"Alice <alice@third.org>",
|
||||
]);
|
||||
let fpr = cert.fingerprint().to_string();
|
||||
sq.key_import(cert_path);
|
||||
|
||||
@ -602,5 +606,18 @@ fn userid_designators() {
|
||||
cert.key_handle(), UserIDArg::AddEmail("alice@example.com"));
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("<alice@example.com>")).is_ok());
|
||||
|
||||
// Use --email-or-add to link "<alice@third.org>", which is
|
||||
// part of the self signed user ID "Alice <alice@third.org>".
|
||||
// This should link "<alice@third.org>", not the self-signed
|
||||
// user ID.
|
||||
vouch(&mut sq,
|
||||
cert.key_handle(), UserIDArg::AddEmail("alice@third.org"));
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("<alice@third.org>")).is_ok());
|
||||
if ! authorize {
|
||||
assert!(sq.pki_authenticate(
|
||||
&[], &fpr, UserIDArg::UserID("Alice <alice@third.org>")).is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user