163 lines
4.8 KiB
Diff
163 lines
4.8 KiB
Diff
diff --git a/client/src/cli.rs b/client/src/cli.rs
|
|
index ee86783..e96b1b6 100644
|
|
--- a/client/src/cli.rs
|
|
+++ b/client/src/cli.rs
|
|
@@ -9,6 +9,7 @@ use enum_as_inner::EnumAsInner;
|
|
|
|
use crate::command::cache::{self, Cache};
|
|
use crate::command::get_closure::{self, GetClosure};
|
|
+use crate::command::key::{self, Key};
|
|
use crate::command::login::{self, Login};
|
|
use crate::command::push::{self, Push};
|
|
use crate::command::r#use::{self, Use};
|
|
@@ -30,6 +31,7 @@ pub enum Command {
|
|
Push(Push),
|
|
Cache(Cache),
|
|
WatchStore(WatchStore),
|
|
+ Key(Key),
|
|
|
|
#[clap(hide = true)]
|
|
GetClosure(GetClosure),
|
|
@@ -57,6 +59,7 @@ pub async fn run() -> Result<()> {
|
|
Command::Cache(_) => cache::run(opts).await,
|
|
Command::WatchStore(_) => watch_store::run(opts).await,
|
|
Command::GetClosure(_) => get_closure::run(opts).await,
|
|
+ Command::Key(_) => key::run(opts).await,
|
|
}
|
|
}
|
|
|
|
diff --git a/client/src/command/cache.rs b/client/src/command/cache.rs
|
|
index af01378..af24d8c 100644
|
|
--- a/client/src/command/cache.rs
|
|
+++ b/client/src/command/cache.rs
|
|
@@ -7,8 +7,11 @@ use crate::api::ApiClient;
|
|
use crate::cache::CacheRef;
|
|
use crate::cli::Opts;
|
|
use crate::config::Config;
|
|
-use attic::api::v1::cache_config::{
|
|
- CacheConfig, CreateCacheRequest, KeypairConfig, RetentionPeriodConfig,
|
|
+use attic::{
|
|
+ api::v1::cache_config::{
|
|
+ CacheConfig, CreateCacheRequest, KeypairConfig, RetentionPeriodConfig,
|
|
+ },
|
|
+ signing::NixKeypair,
|
|
};
|
|
|
|
/// Manage caches on an Attic server.
|
|
@@ -72,6 +75,12 @@ struct Create {
|
|
default_value = "cache.nixos.org-1"
|
|
)]
|
|
upstream_cache_key_names: Vec<String>,
|
|
+
|
|
+ /// The signing keypair to use for the cache.
|
|
+ ///
|
|
+ /// If not specified, a new keypair will be generated.
|
|
+ #[clap(long)]
|
|
+ keypair_path: Option<String>,
|
|
}
|
|
|
|
/// Configure a cache.
|
|
@@ -91,6 +100,14 @@ struct Configure {
|
|
#[clap(long)]
|
|
regenerate_keypair: bool,
|
|
|
|
+ /// Set a keypair for the cache.
|
|
+ ///
|
|
+ /// The server-side signing key will be set to the
|
|
+ /// specified keypair. This is useful for setting up
|
|
+ /// a cache with a pre-existing keypair.
|
|
+ #[clap(long, conflicts_with = "regenerate_keypair")]
|
|
+ keypair_path: Option<String>,
|
|
+
|
|
/// Make the cache public.
|
|
///
|
|
/// Use `--private` to make it private.
|
|
@@ -179,9 +196,15 @@ async fn create_cache(sub: Create) -> Result<()> {
|
|
let (server_name, server, cache) = config.resolve_cache(&sub.cache)?;
|
|
let api = ApiClient::from_server_config(server.clone())?;
|
|
|
|
+ let keypair = if let Some(keypair_path) = &sub.keypair_path {
|
|
+ let contents = std::fs::read_to_string(keypair_path)?;
|
|
+ KeypairConfig::Keypair(NixKeypair::from_str(&contents)?)
|
|
+ } else {
|
|
+ KeypairConfig::Generate
|
|
+ };
|
|
+
|
|
let request = CreateCacheRequest {
|
|
- // TODO: Make this configurable?
|
|
- keypair: KeypairConfig::Generate,
|
|
+ keypair,
|
|
is_public: sub.public,
|
|
priority: sub.priority,
|
|
store_dir: sub.store_dir,
|
|
@@ -230,6 +253,10 @@ async fn configure_cache(sub: Configure) -> Result<()> {
|
|
|
|
if sub.regenerate_keypair {
|
|
patch.keypair = Some(KeypairConfig::Generate);
|
|
+ } else if let Some(keypair_path) = &sub.keypair_path {
|
|
+ let contents = std::fs::read_to_string(keypair_path)?;
|
|
+ let keypair = KeypairConfig::Keypair(NixKeypair::from_str(&contents)?);
|
|
+ patch.keypair = Some(keypair);
|
|
}
|
|
|
|
patch.store_dir = sub.store_dir;
|
|
diff --git a/client/src/command/key.rs b/client/src/command/key.rs
|
|
new file mode 100644
|
|
index 0000000..807d8a7
|
|
--- /dev/null
|
|
+++ b/client/src/command/key.rs
|
|
@@ -0,0 +1,42 @@
|
|
+use anyhow::Result;
|
|
+use clap::{Parser, Subcommand};
|
|
+
|
|
+use crate::cli::Opts;
|
|
+use attic::signing::NixKeypair;
|
|
+
|
|
+/// Manage signing keys.
|
|
+#[derive(Debug, Parser)]
|
|
+pub struct Key {
|
|
+ #[clap(subcommand)]
|
|
+ command: KeyCommand,
|
|
+}
|
|
+
|
|
+#[derive(Debug, Subcommand)]
|
|
+enum KeyCommand {
|
|
+ Generate(Generate),
|
|
+}
|
|
+
|
|
+/// Generate a key.
|
|
+#[derive(Debug, Clone, Parser)]
|
|
+pub struct Generate {
|
|
+ /// Name of the key (must not contain colons).
|
|
+ name: String,
|
|
+}
|
|
+
|
|
+pub async fn run(opts: Opts) -> Result<()> {
|
|
+ let sub = opts.command.as_key().unwrap();
|
|
+ match &sub.command {
|
|
+ KeyCommand::Generate(sub) => generate_key(sub).await,
|
|
+ }
|
|
+}
|
|
+
|
|
+async fn generate_key(sub: &Generate) -> Result<()> {
|
|
+ let keypair = NixKeypair::generate(&sub.name)?;
|
|
+
|
|
+ println!("🔑 Generated keypair \"{}\"", sub.name);
|
|
+ println!();
|
|
+ println!(" Private key: {}", keypair.export_keypair());
|
|
+ println!(" Public key: {}", keypair.export_public_key());
|
|
+
|
|
+ Ok(())
|
|
+}
|
|
diff --git a/client/src/command/mod.rs b/client/src/command/mod.rs
|
|
index cca423f..26b105a 100644
|
|
--- a/client/src/command/mod.rs
|
|
+++ b/client/src/command/mod.rs
|
|
@@ -1,5 +1,6 @@
|
|
pub mod cache;
|
|
pub mod get_closure;
|
|
+pub mod key;
|
|
pub mod login;
|
|
pub mod push;
|
|
pub mod r#use;
|