diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 71a000e2..abbfbb50 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,9 +54,9 @@ export TEST_CACHE_DEFAULT= cargo test --test configure_profile_test ``` -- If you already have existing credentials and config files locally, running `cargo test --test configure_profiles_test` with provided `TEST_AUTH_TOKEN_DEFAULT` will overwrite values for token your `default` profile. -- The value for `TEST_CACHE_DEFAULT` needs to match the cache value your `default` profile and the cache needs to exist. However, this cache will be deleted after this test runs successfully. +- If you already have existing credentials and config files locally, running `cargo test --test configure_profiles_test` with provided `TEST_AUTH_TOKEN_DEFAULT` will overwrite the value for token in your `default` profile. +- The value for `TEST_CACHE_DEFAULT` needs to match the cache value in your `default` profile and the cache needs to exist. However, this cache will be deleted after this test runs successfully. ### Deploying -After merge a pr will be created in this repo https://github.com/momentohq/homebrew-tap. Once the pr passes all checks, approve the pr and label is as `pr-pull`. It will then get automatically merged by the homebrew bot, and a release will be created for it. +After merge a pr will be created in this repo https://github.com/momentohq/homebrew-tap. Once the pr passes all checks, approve the pr and label it as `pr-pull`. It will then get automatically merged by the homebrew bot, and a release will be created for it. diff --git a/Cargo.lock b/Cargo.lock index 90b29c0e..d5cd7e4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,15 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64-url" +version = "1.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a99c239d0c7e77c85dddfa9cebce48704b3c49550fcd3b84dd637e4484899f" +dependencies = [ + "base64 0.13.0", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -655,10 +664,12 @@ dependencies = [ name = "momento" version = "0.1.0" dependencies = [ + "base64-url", "jsonwebtoken", "prost", "rustls 0.19.1", "serde", + "serde_json", "tokio", "tonic", "tonic-build", @@ -682,6 +693,7 @@ dependencies = [ "regex", "reqwest", "serde", + "serde_json", "tokio", "toml", "tracing-subscriber", @@ -1245,9 +1257,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ "itoa 1.0.1", "ryu", diff --git a/Cargo.toml b/Cargo.toml index 937c3a72..87c1c070 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,9 @@ features = [ "full",] version = "1.0" features = [ "derive",] +[dependencies.serde_json] +version = "1.0.79" + [dependencies.reqwest] version = "0.11" features = [ "json", "rustls-tls",] diff --git a/client-sdk-rust b/client-sdk-rust index b4772bed..3fc72f8b 160000 --- a/client-sdk-rust +++ b/client-sdk-rust @@ -1 +1 @@ -Subproject commit b4772bed67732762b9f971ca6d35544843b7ca9a +Subproject commit 3fc72f8bfe0d535b26b63f32c0baa2a872e39cf3 diff --git a/src/commands.rs b/src/commands.rs index b0436f7a..f6bccd80 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,3 +1,4 @@ pub mod account; pub mod cache; pub mod configure; +pub mod signingkey; diff --git a/src/commands/cache/cache_cli.rs b/src/commands/cache/cache_cli.rs index 0f568369..2fa27564 100644 --- a/src/commands/cache/cache_cli.rs +++ b/src/commands/cache/cache_cli.rs @@ -1,4 +1,4 @@ -use log::info; +use log::{debug, info}; use momento::simple_cache_client::SimpleCacheClient; use crate::error::CliError; @@ -11,7 +11,7 @@ async fn get_momento_instance(auth_token: String) -> Result Result<(), CliError> { - info!("creating cache..."); + debug!("creating cache..."); let mut momento = get_momento_instance(auth_token).await?; match momento.create_cache(&cache_name).await { Ok(_) => (), @@ -21,7 +21,7 @@ pub async fn create_cache(cache_name: String, auth_token: String) -> Result<(), } pub async fn delete_cache(cache_name: String, auth_token: String) -> Result<(), CliError> { - info!("deleting cache..."); + debug!("deleting cache..."); let mut momento = get_momento_instance(auth_token).await?; match momento.delete_cache(&cache_name).await { Ok(_) => (), @@ -31,7 +31,7 @@ pub async fn delete_cache(cache_name: String, auth_token: String) -> Result<(), } pub async fn list_caches(auth_token: String) -> Result<(), CliError> { - info!("list cache called"); + debug!("list cache called"); let mut momento = get_momento_instance(auth_token).await?; match momento.list_caches(None).await { Ok(res) => { @@ -51,20 +51,20 @@ pub async fn set( value: String, ttl_seconds: u32, ) -> Result<(), CliError> { - info!("setting key: {} into cache: {}", key, cache_name); + debug!("setting key: {} into cache: {}", key, cache_name); let mut momento = get_momento_instance(auth_token).await?; match momento .set(&cache_name, key, value, Some(ttl_seconds)) .await { - Ok(_) => info!("set success"), + Ok(_) => debug!("set success"), Err(e) => return Err(CliError { msg: e.to_string() }), }; Ok(()) } pub async fn get(cache_name: String, auth_token: String, key: String) -> Result<(), CliError> { - info!("getting key: {} from cache: {}", key, cache_name); + debug!("getting key: {} from cache: {}", key, cache_name); let mut momento = get_momento_instance(auth_token).await?; match momento.get(&cache_name, key).await { Ok(r) => { diff --git a/src/commands/signingkey/mod.rs b/src/commands/signingkey/mod.rs new file mode 100644 index 00000000..d93319a0 --- /dev/null +++ b/src/commands/signingkey/mod.rs @@ -0,0 +1 @@ +pub mod signingkey_cli; diff --git a/src/commands/signingkey/signingkey_cli.rs b/src/commands/signingkey/signingkey_cli.rs new file mode 100644 index 00000000..526f5434 --- /dev/null +++ b/src/commands/signingkey/signingkey_cli.rs @@ -0,0 +1,33 @@ +use log::debug; +use momento::simple_cache_client::SimpleCacheClient; + +use crate::error::CliError; + +async fn get_momento_instance(auth_token: String) -> Result { + match SimpleCacheClient::new(auth_token, 100).await { + Ok(m) => Ok(m), + Err(e) => Err(CliError { msg: e.to_string() }), + } +} + +pub async fn create_signing_key(ttl_minutes: u32, auth_token: String) -> Result<(), CliError> { + debug!("creating signing key..."); + let mut momento = get_momento_instance(auth_token).await?; + match momento.create_signing_key(ttl_minutes).await { + Ok(res) => { + println!("{}", serde_json::to_string_pretty(&res).unwrap()); + } + Err(e) => return Err(CliError { msg: e.to_string() }), + }; + Ok(()) +} + +pub async fn revoke_signing_key(key_id: String, auth_token: String) -> Result<(), CliError> { + debug!("revoking signing key..."); + let mut momento = get_momento_instance(auth_token).await?; + match momento.revoke_signing_key(&key_id).await { + Ok(_) => (), + Err(e) => return Err(CliError { msg: e.to_string() }), + }; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index f160cb59..cde4cc05 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::{panic, process::exit}; use clap::StructOpt; use env_logger::Env; use error::CliError; -use log::{error, info}; +use log::{debug, error}; use utils::user::get_creds_and_config; pub mod commands; @@ -24,17 +24,17 @@ struct Momento { #[derive(Debug, StructOpt)] enum Subcommand { - #[structopt(about = "Cache Operations")] + #[structopt(about = "Interact with caches")] Cache { #[structopt(subcommand)] operation: CacheCommand, }, - #[structopt(about = "Configure Momento Credentials")] + #[structopt(about = "Configure credentials")] Configure { - #[structopt(name = "profile", long, short, default_value = "default")] + #[structopt(long, short, default_value = "default")] profile: String, }, - #[structopt(about = "Manage Accounts")] + #[structopt(about = "Manage accounts")] Account { #[structopt(subcommand)] operation: AccountCommand, @@ -45,10 +45,9 @@ enum Subcommand { enum AccountCommand { #[structopt(about = "Sign up for Momento")] Signup { - #[structopt(name = "email", long, short)] + #[structopt(long, short)] email: String, #[structopt( - name = "region", long, short, default_value = "us-west-2", @@ -56,21 +55,42 @@ enum AccountCommand { )] region: String, }, + + #[structopt(about = "Create a signing key")] + CreateSigningKey { + #[structopt( + long = "ttl", + short = 't', + default_value = "86400", + help = "Duration, in minutes, that the signing key will be valid" + )] + ttl_minutes: u32, + #[structopt(long, short, default_value = "default")] + profile: String, + }, + + #[structopt(about = "Revoke the signing key")] + RevokeSigningKey { + #[structopt(long = "key-id", short, help = "Signing Key ID")] + key_id: String, + #[structopt(long, short, default_value = "default")] + profile: String, + }, } #[derive(Debug, StructOpt)] enum CacheCommand { - #[structopt(about = "Creates a Momento Cache")] + #[structopt(about = "Create a cache")] Create { - #[structopt(name = "name", long, short)] + #[structopt(long = "name", short = 'n')] cache_name: String, - #[structopt(name = "profile", long, short, default_value = "default")] + #[structopt(long, short, default_value = "default")] profile: String, }, - #[structopt(about = "Stores a given item in cache")] + #[structopt(about = "Store a given item in the cache")] Set { - #[structopt(name = "name", long, short)] + #[structopt(long = "name", short = 'n')] cache_name: Option, // TODO: Add support for non-string key-value #[structopt(long, short)] @@ -83,32 +103,32 @@ enum CacheCommand { help = "Max time, in seconds, that the item will be stored in cache" )] ttl_seconds: Option, - #[structopt(name = "profile", long, short, default_value = "default")] + #[structopt(long, short, default_value = "default")] profile: String, }, - #[structopt(about = "Gets item from the cache")] + #[structopt(about = "Get an item from the cache")] Get { - #[structopt(name = "name", long, short)] + #[structopt(long = "name", short = 'n')] cache_name: Option, // TODO: Add support for non-string key-value #[structopt(long, short)] key: String, - #[structopt(name = "profile", long, short, default_value = "default")] + #[structopt(long, short, default_value = "default")] profile: String, }, - #[structopt(about = "Deletes the cache")] + #[structopt(about = "Delete the cache")] Delete { - #[structopt(name = "name", long, short)] + #[structopt(long = "name", short = 'n')] cache_name: String, - #[structopt(name = "profile", long, short, default_value = "default")] + #[structopt(long, short, default_value = "default")] profile: String, }, - #[structopt(about = "Lists all momento caches")] + #[structopt(about = "List all caches")] List { - #[structopt(name = "profile", long, short, default_value = "default")] + #[structopt(long, short, default_value = "default")] profile: String, }, } @@ -133,7 +153,7 @@ async fn entrypoint() -> Result<(), CliError> { } => { let (creds, _config) = get_creds_and_config(&profile).await?; commands::cache::cache_cli::create_cache(cache_name.clone(), creds.token).await?; - info!("created cache {cache_name}") + debug!("created cache {cache_name}") } CacheCommand::Set { cache_name, @@ -171,7 +191,7 @@ async fn entrypoint() -> Result<(), CliError> { } => { let (creds, _config) = get_creds_and_config(&profile).await?; commands::cache::cache_cli::delete_cache(cache_name.clone(), creds.token).await?; - info!("deleted cache {}", cache_name) + debug!("deleted cache {}", cache_name) } CacheCommand::List { profile } => { let (creds, _config) = get_creds_and_config(&profile).await?; @@ -185,6 +205,23 @@ async fn entrypoint() -> Result<(), CliError> { AccountCommand::Signup { email, region } => { commands::account::signup_user(email, region).await?; } + AccountCommand::CreateSigningKey { + ttl_minutes, + profile, + } => { + let (creds, _config) = get_creds_and_config(&profile).await?; + commands::signingkey::signingkey_cli::create_signing_key(ttl_minutes, creds.token) + .await?; + } + AccountCommand::RevokeSigningKey { key_id, profile } => { + let (creds, _config) = get_creds_and_config(&profile).await?; + commands::signingkey::signingkey_cli::revoke_signing_key( + key_id.clone(), + creds.token, + ) + .await?; + debug!("revoked signing key {}", key_id) + } }, } Ok(())