diff --git a/Cargo.lock b/Cargo.lock index 74097002..4da05d0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1354,6 +1354,7 @@ dependencies = [ "clap_complete", "futures-util", "g3keymess-proto", + "hex", "thiserror", "tokio", "tokio-util", diff --git a/g3keymess/proto/schema/proc.capnp b/g3keymess/proto/schema/proc.capnp index f6096111..2d5f353c 100644 --- a/g3keymess/proto/schema/proc.capnp +++ b/g3keymess/proto/schema/proc.capnp @@ -14,4 +14,5 @@ interface ProcControl { getServer @3 (name: Text) -> (server :Types.FetchResult(Server.ServerControl)); publishKey @4 (pem: Text) -> (result :Types.OperationResult); + listKeys @5 () -> (result :List(Data)); } diff --git a/g3keymess/src/control/bridge/mod.rs b/g3keymess/src/control/bridge/mod.rs index 952bea2a..b922ddca 100644 --- a/g3keymess/src/control/bridge/mod.rs +++ b/g3keymess/src/control/bridge/mod.rs @@ -35,3 +35,11 @@ pub(crate) async fn add_key(pem: &str) -> anyhow::Result<()> { .await .map_err(|e| anyhow!("failed to spawn reload task: {e}"))? } + +pub(crate) async fn list_keys() -> anyhow::Result>> { + g3_daemon::control::bridge::main_runtime_handle() + .ok_or(anyhow!("unable to get main runtime handle"))? + .spawn(async move { Ok(crate::store::get_all_ski()) }) + .await + .map_err(|e| anyhow!("failed to spawn reload task: {e}"))? +} diff --git a/g3keymess/src/control/capnp/proc.rs b/g3keymess/src/control/capnp/proc.rs index 9948b466..c42f11fe 100644 --- a/g3keymess/src/control/capnp/proc.rs +++ b/g3keymess/src/control/capnp/proc.rs @@ -85,6 +85,23 @@ impl proc_control::Server for ProcControlImpl { Ok(()) }) } + + fn list_keys( + &mut self, + _params: proc_control::ListKeysParams, + mut results: proc_control::ListKeysResults, + ) -> Promise<(), capnp::Error> { + Promise::from_future(async move { + let r = crate::control::bridge::list_keys() + .await + .unwrap_or_default(); + let mut builder = results.get().init_result(r.len() as u32); + for (i, ski) in r.iter().enumerate() { + builder.set(i as u32, ski.as_slice()); + } + Ok(()) + }) + } } fn set_fetch_result<'a, T>( diff --git a/g3keymess/src/store/mod.rs b/g3keymess/src/store/mod.rs index 888afebf..980c1380 100644 --- a/g3keymess/src/store/mod.rs +++ b/g3keymess/src/store/mod.rs @@ -42,6 +42,13 @@ pub(crate) fn add_global(key: PKey) -> anyhow::Result<()> { Ok(()) } +pub(crate) fn get_all_ski() -> Vec> { + GLOBAL_SKI_MAP.with(|cell| { + let map = cell.borrow(); + map.keys().map(|v| v.to_vec()).collect() + }) +} + pub(crate) fn get_by_ski(ski: &[u8]) -> Option> { GLOBAL_SKI_MAP.with(|cell| { let map = cell.borrow(); diff --git a/g3keymess/utils/ctl/Cargo.toml b/g3keymess/utils/ctl/Cargo.toml index c64fbcdc..4d23bbd5 100644 --- a/g3keymess/utils/ctl/Cargo.toml +++ b/g3keymess/utils/ctl/Cargo.toml @@ -16,4 +16,5 @@ tokio-util = { workspace = true, features = ["compat"] } futures-util.workspace = true capnp-rpc.workspace = true capnp.workspace = true +hex.workspace = true g3keymess-proto = { path = "../../proto" } diff --git a/g3keymess/utils/ctl/src/common.rs b/g3keymess/utils/ctl/src/common.rs index fb7b7c8f..d0c61dc6 100644 --- a/g3keymess/utils/ctl/src/common.rs +++ b/g3keymess/utils/ctl/src/common.rs @@ -25,6 +25,13 @@ pub(crate) fn print_list_text(list: capnp::text_list::Reader<'_>) -> CommandResu Ok(()) } +pub(crate) fn print_list_data(list: capnp::data_list::Reader<'_>) -> CommandResult<()> { + for text in list.iter() { + println!("{}", hex::encode(text?)); + } + Ok(()) +} + pub(crate) fn parse_operation_result(r: operation_result::Reader<'_>) -> CommandResult<()> { match r.which().unwrap() { operation_result::Which::Ok(ok) => { diff --git a/g3keymess/utils/ctl/src/proc.rs b/g3keymess/utils/ctl/src/proc.rs index 9c604115..8873043d 100644 --- a/g3keymess/utils/ctl/src/proc.rs +++ b/g3keymess/utils/ctl/src/proc.rs @@ -23,7 +23,7 @@ use g3keymess_proto::proc_capnp::proc_control; use g3keymess_proto::server_capnp::server_control; use super::{CommandError, CommandResult}; -use crate::common::{parse_fetch_result, parse_operation_result, print_list_text}; +use crate::common::{parse_fetch_result, parse_operation_result, print_list_data, print_list_text}; pub const COMMAND_VERSION: &str = "version"; pub const COMMAND_OFFLINE: &str = "offline"; @@ -32,6 +32,7 @@ pub const COMMAND_PUBLISH_KEY: &str = "publish-key"; const COMMAND_LIST_ARG_RESOURCE: &str = "resource"; const RESOURCE_VALUE_SERVER: &str = "server"; +const RESOURCE_VALUE_KEY: &str = "key"; const COMMAND_ARG_FILE: &str = "file"; @@ -52,7 +53,7 @@ pub mod commands { Arg::new(COMMAND_LIST_ARG_RESOURCE) .required(true) .num_args(1) - .value_parser([RESOURCE_VALUE_SERVER]) + .value_parser([RESOURCE_VALUE_SERVER, RESOURCE_VALUE_KEY]) .ignore_case(true), ) } @@ -90,6 +91,7 @@ pub async fn list(client: &proc_control::Client, args: &ArgMatches) -> CommandRe .as_str() { RESOURCE_VALUE_SERVER => list_server(client).await, + RESOURCE_VALUE_KEY => list_key(client).await, _ => unreachable!(), } } @@ -100,6 +102,12 @@ async fn list_server(client: &proc_control::Client) -> CommandResult<()> { print_list_text(rsp.get()?.get_result()?) } +async fn list_key(client: &proc_control::Client) -> CommandResult<()> { + let req = client.list_keys_request(); + let rsp = req.send().promise.await?; + print_list_data(rsp.get()?.get_result()?) +} + pub(crate) async fn get_server( client: &proc_control::Client, name: &str,