mirror of
https://codeberg.org/tyy/aspm
synced 2024-12-22 15:59:29 -07:00
Formatting, tests
This commit is contained in:
parent
afa8eb79b3
commit
61baa8f52f
10 changed files with 141 additions and 22 deletions
|
@ -166,4 +166,10 @@ mod tests {
|
|||
let result = AspeServer::new(Host::Domain(String::from("keyoxide.org"))).await;
|
||||
assert!(result.is_ok(), "Constructing an AspeServer should succeed")
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn building_invalid_aspe_server_fails() {
|
||||
let result = AspeServer::new(Host::Domain(String::from("example.com"))).await;
|
||||
assert!(result.is_err(), "Constructing an AspeServer with an invalid domain should fail")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@ use anyhow::{anyhow, bail, Context};
|
|||
use argon2::{password_hash::SaltString, Argon2, PasswordHasher as _};
|
||||
use asp::{
|
||||
aspe::{
|
||||
requests::{AspeRequest, AspeRequestType, AspeRequestVariant}, AspeRequestFailure, AspeServer
|
||||
requests::{AspeRequest, AspeRequestType, AspeRequestVariant},
|
||||
AspeRequestFailure, AspeServer,
|
||||
},
|
||||
hex_color::HexColor,
|
||||
keys::AspKey,
|
||||
|
@ -130,14 +131,20 @@ impl AspmSubcommand for AspeCreateCommand {
|
|||
.context("Unable to encode the profile as a JWT and sign it")?;
|
||||
|
||||
match server.post_request(encoded_request).await {
|
||||
Ok(_) => {
|
||||
Ok(_) => {
|
||||
println!("Successfully uploaded profile!");
|
||||
Ok(())
|
||||
},
|
||||
Err(AspeRequestFailure::BadRequest) => bail!("The ASPE server rejected the request due to invalid data"),
|
||||
Err(AspeRequestFailure::TooLarge) => bail!("The ASPE server rejected the request as being too large"),
|
||||
Err(AspeRequestFailure::RateLimited) => bail!("The ASPE server rejected the request due to a ratelimit"),
|
||||
Err(AspeRequestFailure::Unknown(e)) => Err(e.into())
|
||||
}
|
||||
}
|
||||
Err(AspeRequestFailure::BadRequest) => {
|
||||
bail!("The ASPE server rejected the request due to invalid data")
|
||||
}
|
||||
Err(AspeRequestFailure::TooLarge) => {
|
||||
bail!("The ASPE server rejected the request as being too large")
|
||||
}
|
||||
Err(AspeRequestFailure::RateLimited) => {
|
||||
bail!("The ASPE server rejected the request due to a ratelimit")
|
||||
}
|
||||
Err(AspeRequestFailure::Unknown(e)) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,5 +11,5 @@ pub struct AspeSubcommand {
|
|||
|
||||
#[derive(Subcommand)]
|
||||
pub enum AspeSubcommands {
|
||||
Create(create::AspeCreateCommand),
|
||||
Create(create::AspeCreateCommand),
|
||||
}
|
||||
|
|
|
@ -8,10 +8,7 @@ use sea_orm::ModelTrait as _;
|
|||
|
||||
use std::io::Write;
|
||||
|
||||
use crate::{
|
||||
commands::AspmSubcommand,
|
||||
utils,
|
||||
};
|
||||
use crate::{commands::AspmSubcommand, utils};
|
||||
|
||||
/// Deletes a saved key, after asking for confirmation.
|
||||
#[derive(Parser, Debug)]
|
||||
|
|
|
@ -45,7 +45,7 @@ pub enum KeyExportFormat {
|
|||
Jwk,
|
||||
}
|
||||
|
||||
/// Exports a saved key, specified by its fingerprint, into multiple formats. Run this command with `--help` in order to see a list of the possible formats, and explanations for all of them.
|
||||
/// Exports a saved key, specified by its fingerprint, into multiple formats. Run this command with `--help` in order to see a list of the possible formats, and explanations for all of them. This command will by default interactively prompt for the key's password in order to be decrypted, unless the KEY_PASSWORD environment variable is present.
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct KeysExportCommand {
|
||||
/// The format to export the key into. All of these formats can then be correctly imported back into this tool, but only some are encrypted, so keep that in mind when handling the exported keys.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
pub mod aspe;
|
||||
pub mod keys;
|
||||
pub mod profiles;
|
||||
pub mod aspe;
|
||||
|
||||
use clap::Parser;
|
||||
use tokio::runtime::Runtime;
|
||||
|
|
|
@ -32,7 +32,8 @@ impl AspmSubcommand for ProfilesImportCommand {
|
|||
(host.to_string(), fingerprint.to_string())
|
||||
})
|
||||
}) {
|
||||
Some((host, fingerprint)) => match aspe::AspeServer::new(Host::parse(&host).unwrap()).await?
|
||||
Some((host, fingerprint)) => match aspe::AspeServer::new(Host::parse(&host).unwrap())
|
||||
.await?
|
||||
.fetch_profile(&fingerprint)
|
||||
.await
|
||||
{
|
||||
|
|
|
@ -7,7 +7,9 @@ use anstyle::{AnsiColor, Color as AnstyleColor, Style as Anstyle};
|
|||
use anyhow::Context;
|
||||
use app_dirs2::{AppDataType, AppInfo};
|
||||
use clap::{Parser, Subcommand};
|
||||
use commands::{aspe::AspeSubcommands, keys::KeysSubcommands, profiles::ProfilesSubcommands, AspmSubcommand};
|
||||
use commands::{
|
||||
aspe::AspeSubcommands, keys::KeysSubcommands, profiles::ProfilesSubcommands, AspmSubcommand,
|
||||
};
|
||||
use migrations::{Migrator, MigratorTrait, SchemaManager};
|
||||
use sea_orm::{Database, DatabaseConnection};
|
||||
use thiserror::Error;
|
||||
|
@ -173,7 +175,7 @@ fn cli(parsed: AspmCommand) -> Result<(), anyhow::Error> {
|
|||
},
|
||||
AspmSubcommands::Aspe(subcommand) => match subcommand.subcommand {
|
||||
AspeSubcommands::Create(subcommand) => subcommand.execute_sync(state, runtime),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@ pub mod keys {
|
|||
fingerprint: S,
|
||||
password: P,
|
||||
) -> anyhow::Result<Vec<u8>> {
|
||||
let argon_salt =
|
||||
SaltString::from_b64(&BASE64_NOPAD.encode(fingerprint.as_ref().to_uppercase().as_bytes()))
|
||||
.context("Unable to derive argon2 salt")?;
|
||||
let argon_salt = SaltString::from_b64(
|
||||
&BASE64_NOPAD.encode(fingerprint.as_ref().to_uppercase().as_bytes()),
|
||||
)
|
||||
.context("Unable to derive argon2 salt")?;
|
||||
let argon2 = Argon2::default();
|
||||
let hash = argon2
|
||||
.hash_password(password.as_ref(), &argon_salt)
|
||||
|
|
|
@ -4,8 +4,28 @@ use predicates::prelude::*;
|
|||
use tempfile::TempDir;
|
||||
use std::process::Command;
|
||||
|
||||
static KEY_ALIAS: &str = "TESTKEY";
|
||||
static KEY_PASSWORD: &str = "TESTKEYPASSWORD";
|
||||
|
||||
// TODO: Also test ed25519 key generation
|
||||
fn assert_key_generated(datadir: &str) -> Result<(), anyhow::Error> {
|
||||
Command::cargo_bin("aspm")?
|
||||
.env("ASPM_DATA_DIR", datadir)
|
||||
.arg("keys")
|
||||
.arg("generate")
|
||||
.env("KEY_PASSWORD", KEY_PASSWORD)
|
||||
.arg("es256")
|
||||
.arg("--key-alias")
|
||||
.arg(KEY_ALIAS)
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::starts_with("Successfully generated a new key!"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_prints_correctly() -> Result<(), anyhow::Error> {
|
||||
fn help_works() -> Result<(), anyhow::Error> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let datadir = tempdir.path().to_str().context("Tempdir path was not valid utf8")?;
|
||||
|
||||
|
@ -23,6 +43,13 @@ fn help_prints_correctly() -> Result<(), anyhow::Error> {
|
|||
.success()
|
||||
.stdout(predicate::str::starts_with(env!("CARGO_PKG_DESCRIPTION")));
|
||||
|
||||
Command::cargo_bin("aspm")?
|
||||
.env("ASPM_DATA_DIR", datadir)
|
||||
.arg("help")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::starts_with(env!("CARGO_PKG_DESCRIPTION")));
|
||||
|
||||
Command::cargo_bin("aspm")?
|
||||
.env("ASPM_DATA_DIR", datadir)
|
||||
.assert()
|
||||
|
@ -31,3 +58,81 @@ fn help_prints_correctly() -> Result<(), anyhow::Error> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keys_generate_works() -> Result<(), anyhow::Error> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let datadir = tempdir.path().to_str().context("Tempdir path was not valid utf8")?;
|
||||
|
||||
assert_key_generated(datadir)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keys_list_works() -> Result<(), anyhow::Error> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let datadir = tempdir.path().to_str().context("Tempdir path was not valid utf8")?;
|
||||
|
||||
assert_key_generated(datadir)?;
|
||||
|
||||
Command::cargo_bin("aspm")?
|
||||
.env("ASPM_DATA_DIR", datadir)
|
||||
.arg("keys")
|
||||
.arg("list")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains(KEY_ALIAS));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This test takes a bit due to testing each export format individually, causing the password to be hashed multiple times
|
||||
#[test]
|
||||
fn keys_export_works() -> Result<(), anyhow::Error> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let datadir = tempdir.path().to_str().context("Tempdir path was not valid utf8")?;
|
||||
|
||||
assert_key_generated(datadir)?;
|
||||
|
||||
for export_format in ["pkcs8", "asp-tool", "jwk"] {
|
||||
Command::cargo_bin("aspm")?
|
||||
.env("ASPM_DATA_DIR", datadir)
|
||||
.arg("keys")
|
||||
.arg("export")
|
||||
.env("KEY_PASSWORD", KEY_PASSWORD)
|
||||
.arg(export_format)
|
||||
.arg(KEY_ALIAS)
|
||||
.assert()
|
||||
.success()
|
||||
.stderr(predicate::str::contains("Exported key \""));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keys_delete_works() -> Result<(), anyhow::Error> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let datadir = tempdir.path().to_str().context("Tempdir path was not valid utf8")?;
|
||||
|
||||
assert_key_generated(datadir)?;
|
||||
|
||||
Command::cargo_bin("aspm")?
|
||||
.env("ASPM_DATA_DIR", datadir)
|
||||
.arg("keys")
|
||||
.arg("delete")
|
||||
.arg("--no-confirm")
|
||||
.arg(KEY_ALIAS)
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("Successfully deleted key with fingerprint "));
|
||||
|
||||
Command::cargo_bin("aspm")?
|
||||
.env("ASPM_DATA_DIR", datadir)
|
||||
.arg("keys")
|
||||
.arg("list")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("Saved keys (0 total):"));
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue