Add an option to sq link add to temporarily accept a binding
- Add an option to `sq link add`, `--temporary`, to temporarily accept a binding. - This creates a fully trusted certification that expires after a week, and a second certification that is one second older, which doesn't expire, but is only partially trusted (trust amount = 40) so that the user remembers this decision.
This commit is contained in:
parent
96a65b4b97
commit
4ae448cef8
@ -1,5 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use std::time::SystemTime;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use anyhow::Context;
|
||||
|
||||
@ -445,30 +445,6 @@ pub fn add(mut config: Config, c: link::AddCommand)
|
||||
// Creation time.
|
||||
builder = builder.set_signature_creation_time(config.time)?;
|
||||
|
||||
match (expires, expires_in) {
|
||||
(None, None) =>
|
||||
// Default expiration: never.
|
||||
(),
|
||||
(Some(t), None) if t == "never" =>
|
||||
// The default is no expiration; there is nothing to do.
|
||||
(),
|
||||
(Some(t), None) => {
|
||||
let expiration = SystemTime::from(
|
||||
crate::parse_iso8601(
|
||||
&t, chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())?);
|
||||
let validity = expiration.duration_since(config.time)?;
|
||||
builder = builder.set_signature_validity_period(validity)?;
|
||||
},
|
||||
(None, Some(d)) if d == "never" =>
|
||||
// The default is no expiration; there is nothing to do.
|
||||
(),
|
||||
(None, Some(d)) => {
|
||||
let d = parse_duration(&d)?;
|
||||
builder = builder.set_signature_validity_period(d)?;
|
||||
},
|
||||
(Some(_), Some(_)) => unreachable!("conflicting args"),
|
||||
}
|
||||
|
||||
let notations = parse_notations(c.notation)?;
|
||||
for (critical, n) in notations {
|
||||
builder = builder.add_notation(
|
||||
@ -478,6 +454,45 @@ pub fn add(mut config: Config, c: link::AddCommand)
|
||||
critical)?;
|
||||
};
|
||||
|
||||
let builders: Vec<SignatureBuilder> = if c.temporary {
|
||||
// Make the partially trusted link one second younger. When
|
||||
// the fully trusted link expired, then this link will come
|
||||
// into effect. If the user has fully linked the binding in
|
||||
// the meantime, then this won't override that, which is
|
||||
// exactly what we want.
|
||||
let mut partial = builder.clone();
|
||||
partial = partial.set_signature_creation_time(
|
||||
config.time - Duration::new(1, 0))?;
|
||||
partial = partial.set_trust_signature(trust_depth, 40)?;
|
||||
|
||||
builder = builder.set_signature_validity_period(
|
||||
Duration::new(7 * 24 * 60 * 60, 0))?;
|
||||
|
||||
vec![ builder, partial ]
|
||||
} else if let Some(t) = expires {
|
||||
if t == "never" {
|
||||
// The default is no expiration; there is nothing to do.
|
||||
} else {
|
||||
let expiration = SystemTime::from(
|
||||
crate::parse_iso8601(
|
||||
&t, chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())?);
|
||||
let validity = expiration.duration_since(config.time)?;
|
||||
builder = builder.set_signature_validity_period(validity)?;
|
||||
}
|
||||
vec![ builder ]
|
||||
} else if let Some(d) = expires_in {
|
||||
if d == "never" {
|
||||
// The default is no expiration; there is nothing to do.
|
||||
} else {
|
||||
let d = parse_duration(&d)?;
|
||||
builder = builder.set_signature_validity_period(d)?;
|
||||
}
|
||||
vec![ builder ]
|
||||
} else {
|
||||
// The default is no expiration; there is nothing to do.
|
||||
vec![ builder ]
|
||||
};
|
||||
|
||||
// Sign it.
|
||||
let signers = get_certification_keys(
|
||||
&[trust_root], &config.policy, None, Some(config.time), None)
|
||||
@ -535,11 +550,14 @@ pub fn add(mut config: Config, c: link::AddCommand)
|
||||
|
||||
let changed = diff_link(
|
||||
&active_certification,
|
||||
&builder, config.time);
|
||||
&builders[0], config.time);
|
||||
|
||||
if ! changed && config.force {
|
||||
eprintln!(" Link parameters are unchanged, but \
|
||||
updating anyway as \"--force\" was specified.");
|
||||
} else if c.temporary {
|
||||
eprintln!(" Creating a temporary link, \
|
||||
which expires in a week.");
|
||||
} else if ! changed {
|
||||
eprintln!(" Link parameters are unchanged, no update \
|
||||
needed (specify \"--force\" to update anyway).");
|
||||
@ -556,16 +574,25 @@ pub fn add(mut config: Config, c: link::AddCommand)
|
||||
eprintln!("Linking {} and {:?}.",
|
||||
cert.fingerprint(), userid_str());
|
||||
|
||||
let sig = builder.clone().sign_userid_binding(
|
||||
let mut sigs = builders.iter()
|
||||
.map(|builder| {
|
||||
builder.clone().sign_userid_binding(
|
||||
&mut signer,
|
||||
cert.primary_key().key(),
|
||||
&userid)
|
||||
.with_context(|| {
|
||||
format!("Creating certification for {:?}", userid_str())
|
||||
})?;
|
||||
format!("Creating certification for {:?}",
|
||||
userid_str())
|
||||
})
|
||||
.map(Into::into)
|
||||
})
|
||||
.collect::<Result<Vec<Packet>>>()?;
|
||||
|
||||
eprintln!();
|
||||
Ok(vec![ Packet::from(userid.clone()), Packet::from(sig) ])
|
||||
|
||||
let mut packets = vec![ Packet::from(userid.clone()) ];
|
||||
packets.append(&mut sigs);
|
||||
Ok(packets)
|
||||
})
|
||||
.collect::<Result<Vec<Vec<Packet>>>>()?
|
||||
.into_iter()
|
||||
|
@ -131,7 +131,8 @@ $ sq link add --ca --amount 60 0123456789ABCDEF
|
||||
$ sq link retract 0123456789ABCDEF
|
||||
",
|
||||
)]
|
||||
#[clap(group(ArgGroup::new("expiration-group").args(&["expires", "expires_in"])))]
|
||||
#[clap(group(ArgGroup::new("expiration-group")
|
||||
.args(&["expires", "expires_in", "temporary"])))]
|
||||
pub struct AddCommand {
|
||||
#[clap(
|
||||
short = 'd',
|
||||
@ -203,6 +204,19 @@ pub struct AddCommand {
|
||||
being human readable."
|
||||
)]
|
||||
pub notation: Vec<String>,
|
||||
|
||||
#[clap(
|
||||
long = "temporary",
|
||||
conflicts_with_all = &[ "amount" ],
|
||||
help = "Temporarily accepts the binding",
|
||||
long_help =
|
||||
"Temporarily accepts the binding. Creates a fully
|
||||
trust link between a certificate and one or more
|
||||
User IDs for a week. After that, the link is
|
||||
automatically downgraded to a partially trusted link
|
||||
(trust = 40).",
|
||||
)]
|
||||
pub temporary: bool,
|
||||
#[clap(
|
||||
long = "expires",
|
||||
value_name = "TIME",
|
||||
|
204
tests/sq-link.rs
204
tests/sq-link.rs
@ -29,10 +29,15 @@ static TIME: OnceCell<Mutex<chrono::DateTime<chrono::Utc>>> = OnceCell::new();
|
||||
fn tick() -> String {
|
||||
let t = TIME.get_or_init(|| Mutex::new(chrono::Utc::now()));
|
||||
let mut t = t.lock().unwrap();
|
||||
*t = *t + chrono::Duration::seconds(1);
|
||||
*t = *t + chrono::Duration::seconds(10);
|
||||
t.format("%Y-%m-%dT%H:%M:%SZ").to_string()
|
||||
}
|
||||
|
||||
// Returns the "current" time.
|
||||
fn now() -> chrono::DateTime<chrono::Utc> {
|
||||
*TIME.get_or_init(|| Mutex::new(chrono::Utc::now())).lock().unwrap()
|
||||
}
|
||||
|
||||
// Imports a certificate.
|
||||
fn sq_import(cert_store: &str, files: &[&str], stdin: Option<&str>)
|
||||
{
|
||||
@ -75,6 +80,7 @@ fn sq_gen_key(cert_store: Option<&str>, userids: &[&str], file: &str) -> Cert
|
||||
|
||||
// Verifies a signed message.
|
||||
fn sq_verify(cert_store: Option<&str>,
|
||||
time: Option<chrono::DateTime<chrono::Utc>>,
|
||||
trust_roots: &[&str],
|
||||
signer_files: &[&str],
|
||||
msg_pgp: &str,
|
||||
@ -89,7 +95,12 @@ fn sq_verify(cert_store: Option<&str>,
|
||||
for trust_root in trust_roots {
|
||||
cmd.args(&["--trust-root", trust_root]);
|
||||
}
|
||||
cmd.args(["verify", "--time", &tick()]);
|
||||
let time = if let Some(time) = time {
|
||||
time.format("%Y-%m-%dT%H:%M:%SZ").to_string()
|
||||
} else {
|
||||
tick()
|
||||
};
|
||||
cmd.args(["verify", "--time", &time]);
|
||||
for signer_file in signer_files {
|
||||
cmd.args(&["--signer-file", signer_file]);
|
||||
}
|
||||
@ -272,7 +283,7 @@ fn sq_link_add_retract() -> Result<()> {
|
||||
// None of the certificates can be authenticated so verifying the
|
||||
// messages should fail.
|
||||
for data in data.iter() {
|
||||
sq_verify(Some(&certd), &[], &[], &data.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &data.sig_file, 0, 1);
|
||||
}
|
||||
|
||||
// Have Alice certify Bob as a trusted introducer and have Bob
|
||||
@ -288,58 +299,58 @@ fn sq_link_add_retract() -> Result<()> {
|
||||
// signatures Alice as the trust root. And Bob's and Carols' with
|
||||
// Bob as the trust root.
|
||||
|
||||
sq_verify(Some(&certd), &[&alice_fpr], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[&alice_fpr], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[&alice_fpr], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[&alice_fpr], &[], &dave.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&alice_fpr], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[&alice_fpr], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[&alice_fpr], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[&alice_fpr], &[], &dave.sig_file, 0, 1);
|
||||
|
||||
sq_verify(Some(&certd), &[&bob_fpr], &[], &alice.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[&bob_fpr], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[&bob_fpr], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[&bob_fpr], &[], &dave.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&bob_fpr], &[], &alice.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&bob_fpr], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[&bob_fpr], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[&bob_fpr], &[], &dave.sig_file, 0, 1);
|
||||
|
||||
sq_verify(Some(&certd), &[&carol_fpr], &[], &alice.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[&carol_fpr], &[], &bob.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[&carol_fpr], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[&carol_fpr], &[], &dave.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&carol_fpr], &[], &alice.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&carol_fpr], &[], &bob.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&carol_fpr], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[&carol_fpr], &[], &dave.sig_file, 0, 1);
|
||||
|
||||
sq_verify(Some(&certd), &[&dave_fpr], &[], &alice.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[&dave_fpr], &[], &bob.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[&dave_fpr], &[], &carol.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[&dave_fpr], &[], &dave.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[&dave_fpr], &[], &alice.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&dave_fpr], &[], &bob.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&dave_fpr], &[], &carol.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[&dave_fpr], &[], &dave.sig_file, 1, 0);
|
||||
|
||||
// Let's accept Alice, but not (yet) as a trusted introducer. We
|
||||
// should now be able to verify Alice's signature, but not Bob's.
|
||||
sq_link(&certd, &alice_fpr, &[ &alice_userid ], &[], true);
|
||||
|
||||
sq_verify(Some(&certd), &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &bob.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &bob.sig_file, 0, 1);
|
||||
|
||||
// Accept Alice as a trusted introducer. We should be able to
|
||||
// verify Alice, Bob, and Carol's signatures.
|
||||
sq_link(&certd, &alice_fpr, &[ &alice_userid ], &["--ca", "*"], true);
|
||||
|
||||
sq_verify(Some(&certd), &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &dave.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &dave.sig_file, 0, 1);
|
||||
|
||||
// Retract the acceptance for Alice. If we don't specify a trust
|
||||
// root, none of the signatures should verify.
|
||||
sq_retract(&certd, &alice_fpr, &[ &alice_userid ]);
|
||||
|
||||
for data in data.iter() {
|
||||
sq_verify(Some(&certd), &[], &[], &data.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &data.sig_file, 0, 1);
|
||||
}
|
||||
|
||||
// Accept Alice as a trusted introducer again. We should be able
|
||||
// to verify Alice, Bob, and Carol's signatures.
|
||||
sq_link(&certd, &alice_fpr, &[ &alice_userid ], &["--ca", "*"], true);
|
||||
|
||||
sq_verify(Some(&certd), &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &dave.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &dave.sig_file, 0, 1);
|
||||
|
||||
// Have Bob certify Dave. Now Dave's signature should also
|
||||
// verify.
|
||||
@ -347,29 +358,29 @@ fn sq_link_add_retract() -> Result<()> {
|
||||
&dave.cert.fingerprint().to_string(), dave_userid,
|
||||
None, None);
|
||||
|
||||
sq_verify(Some(&certd), &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &dave.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &dave.sig_file, 1, 0);
|
||||
|
||||
// Change Alice's acceptance to just be a normal certification.
|
||||
// We should only be able to verify her signature.
|
||||
sq_link(&certd, &alice_fpr, &[ &alice_userid ], &[], true);
|
||||
|
||||
sq_verify(Some(&certd), &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &bob.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[], &[], &carol.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), &[], &[], &dave.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &bob.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &carol.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &dave.sig_file, 0, 1);
|
||||
|
||||
// Change Alice's acceptance to be a ca, but only for example.org,
|
||||
// i.e., not for Dave.
|
||||
sq_link(&certd, &alice_fpr, &[ &alice_userid ], &["--ca", "example.org"],
|
||||
true);
|
||||
|
||||
sq_verify(Some(&certd), &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), &[], &[], &dave.sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &bob.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &carol.sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &dave.sig_file, 0, 1);
|
||||
|
||||
|
||||
|
||||
@ -404,37 +415,37 @@ fn sq_link_add_retract() -> Result<()> {
|
||||
// If we don't use --petname, than a self-signed User ID must
|
||||
// exist.
|
||||
sq_link(&certd, &ed_fpr, &[ "--userid", "bob@example.com" ], &[], false);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
sq_link(&certd, &ed_fpr, &[ "--email", "bob@example.com" ], &[], false);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
sq_link(&certd, &ed_fpr, &[ "bob@example.com" ], &[], false);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
// We should only create links if all the supplied User IDs are
|
||||
// valid.
|
||||
sq_link(&certd, &ed_fpr, &[
|
||||
"--userid", "ed@some.org", "--userid", "bob@example.com"
|
||||
], &[], false);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
sq_link(&certd, &ed_fpr, &[
|
||||
"--userid", "ed@some.org", "--email", "bob@example.com"
|
||||
], &[], false);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
sq_link(&certd, &ed_fpr, &[
|
||||
"--userid", "ed@some.org", "bob@example.com"
|
||||
], &[], false);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
// Pass an email address to --userid. This shouldn't match
|
||||
// either.
|
||||
sq_link(&certd, &ed_fpr, &[
|
||||
"--userid", "ed@other.org"
|
||||
], &[], false);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
// Link all User IDs individually.
|
||||
sq_link(&certd, &ed_fpr, &[
|
||||
@ -442,21 +453,21 @@ fn sq_link_add_retract() -> Result<()> {
|
||||
"--email", "ed@example.org",
|
||||
"--userid", "ed@some.org",
|
||||
], &[], true);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 1, 0);
|
||||
|
||||
// Retract the links one at a time.
|
||||
sq_retract(&certd, &ed_fpr, &[ "ed@other.org" ]);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 1, 0);
|
||||
|
||||
sq_retract(&certd, &ed_fpr, &[ "Ed <ed@example.org>" ]);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 1, 0);
|
||||
|
||||
sq_retract(&certd, &ed_fpr, &[ "Eddie <ed@example.org>" ]);
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 1, 0);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 1, 0);
|
||||
|
||||
sq_retract(&certd, &ed_fpr, &[ "ed@some.org" ]);
|
||||
// Now the certificate should no longer be authenticated.
|
||||
sq_verify(Some(&certd), &[], &[], &ed_sig_file, 0, 1);
|
||||
sq_verify(Some(&certd), None, &[], &[], &ed_sig_file, 0, 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -587,3 +598,88 @@ fn sq_link_update_detection() -> Result<()> {
|
||||
let _ = bytes;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Check that sq link add --temporary works.
|
||||
#[test]
|
||||
fn sq_link_add_temporary() -> Result<()> {
|
||||
let dir = TempDir::new()?;
|
||||
|
||||
let certd = dir.path().join("cert.d").display().to_string();
|
||||
std::fs::create_dir(&certd).expect("mkdir works");
|
||||
|
||||
let alice_pgp = dir.path().join("alice.pgp").display().to_string();
|
||||
let alice_userid = "<alice@example.org>";
|
||||
let alice = sq_gen_key(Some(&certd), &[ alice_userid ], &alice_pgp);
|
||||
let alice_fpr = alice.fingerprint().to_string();
|
||||
let alice_cert_pgp = dir.path().join("cert.d")
|
||||
.join(&alice_fpr[0..2].to_ascii_lowercase())
|
||||
.join(&alice_fpr[2..].to_ascii_lowercase());
|
||||
|
||||
let alice_sig_file = dir.path().join("alice.sig").display().to_string();
|
||||
Command::cargo_bin("sq")
|
||||
.unwrap()
|
||||
.arg("--no-cert-store")
|
||||
.arg("sign")
|
||||
.args(["--signer-file", &alice_pgp])
|
||||
.args(["--output", &alice_sig_file])
|
||||
.args(["--time", &tick()])
|
||||
.arg(&artifact("messages/a-cypherpunks-manifesto.txt"))
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
// Reads and returns file. Asserts that old and the new contexts
|
||||
// are the same (or not).
|
||||
let compare = |old: Vec<u8>, file: &Path, same: bool| -> Vec<u8> {
|
||||
let new = std::fs::read(file).unwrap();
|
||||
if same {
|
||||
assert_eq!(old, new, "file unexpectedly changed");
|
||||
} else {
|
||||
assert_ne!(old, new, "file unexpectedly stayed the same");
|
||||
}
|
||||
new
|
||||
};
|
||||
let bytes = std::fs::read(&alice_cert_pgp).unwrap();
|
||||
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice_sig_file, 0, 1);
|
||||
|
||||
let output = sq_link(&certd, &alice_fpr, &[], &["--temporary", "--all"], true);
|
||||
assert!(output.2.contains("Linking "),
|
||||
"stdout:\n{}\nstderr:\n{}", output.1, output.2);
|
||||
let bytes = compare(bytes, &alice_cert_pgp, false);
|
||||
|
||||
// Now it is fully trusted.
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice_sig_file, 1, 0);
|
||||
|
||||
// In 6 days, too.
|
||||
sq_verify(Some(&certd),
|
||||
Some(now() + chrono::Duration::seconds(6 * 24 * 60 * 60)),
|
||||
&[], &[], &alice_sig_file, 1, 0);
|
||||
|
||||
// But in 8 days it will only be partially trusted.
|
||||
sq_verify(Some(&certd),
|
||||
Some(now() + chrono::Duration::seconds(8 * 24 * 60 * 60)),
|
||||
&[], &[], &alice_sig_file, 0, 1);
|
||||
|
||||
|
||||
// Now mark it as fully trusted. It should be trusted now, in 6
|
||||
// days and in 8 days.
|
||||
let output = sq_link(&certd, &alice_fpr, &[], &["--all"], true);
|
||||
assert!(output.2.contains("was already linked"),
|
||||
"stdout:\n{}\nstderr:\n{}", output.1, output.2);
|
||||
eprintln!("{:?}", output);
|
||||
let bytes = compare(bytes, &alice_cert_pgp, false);
|
||||
|
||||
sq_verify(Some(&certd), None, &[], &[], &alice_sig_file, 1, 0);
|
||||
|
||||
sq_verify(Some(&certd),
|
||||
Some(now() + chrono::Duration::seconds(6 * 24 * 60 * 60)),
|
||||
&[], &[], &alice_sig_file, 1, 0);
|
||||
|
||||
sq_verify(Some(&certd),
|
||||
Some(now() + chrono::Duration::seconds(8 * 24 * 60 * 60)),
|
||||
&[], &[], &alice_sig_file, 1, 0);
|
||||
|
||||
let _bytes = bytes;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user