From 6edbe82c3241aa9898f4c3673a17b623429cc200 Mon Sep 17 00:00:00 2001 From: Fico <70634661+fbozic@users.noreply.github.com> Date: Fri, 1 Nov 2024 17:55:15 +0100 Subject: [PATCH] feat: implement context invite & identity new command (#918) --- crates/meroctl/src/cli.rs | 8 +- crates/meroctl/src/cli/context.rs | 4 + crates/meroctl/src/cli/context/invite.rs | 60 ++++ crates/meroctl/src/cli/identity.rs | 37 +++ crates/meroctl/src/cli/identity/generate.rs | 40 +++ crates/server-primitives/src/admin.rs | 310 ++++++++++-------- crates/server/src/admin/handlers.rs | 1 + .../context/get_context_client_keys.rs | 9 +- .../context/get_context_identities.rs | 55 ++-- .../handlers/context/get_context_users.rs | 8 +- .../admin/handlers/context/join_context.rs | 11 +- .../context/update_context_application.rs | 4 +- crates/server/src/admin/handlers/identity.rs | 1 + .../identity/generate_context_identity.rs | 17 + crates/server/src/admin/service.rs | 14 +- 15 files changed, 389 insertions(+), 190 deletions(-) create mode 100644 crates/meroctl/src/cli/context/invite.rs create mode 100644 crates/meroctl/src/cli/identity.rs create mode 100644 crates/meroctl/src/cli/identity/generate.rs create mode 100644 crates/server/src/admin/handlers/identity.rs create mode 100644 crates/server/src/admin/handlers/identity/generate_context_identity.rs diff --git a/crates/meroctl/src/cli.rs b/crates/meroctl/src/cli.rs index a8ef120a6..07a970165 100644 --- a/crates/meroctl/src/cli.rs +++ b/crates/meroctl/src/cli.rs @@ -12,10 +12,12 @@ use crate::output::{Format, Output, Report}; mod app; mod context; +mod identity; mod jsonrpc; use app::AppCommand; use context::ContextCommand; +use identity::IdentityCommand; use jsonrpc::CallCommand; pub const EXAMPLES: &str = r" @@ -44,8 +46,9 @@ pub struct RootCommand { #[derive(Debug, Subcommand)] pub enum SubCommands { - Context(ContextCommand), App(AppCommand), + Context(ContextCommand), + Identity(IdentityCommand), JsonRpc(CallCommand), } @@ -81,8 +84,9 @@ impl RootCommand { let environment = Environment::new(self.args, output); let result = match self.action { - SubCommands::Context(context) => context.run(&environment).await, SubCommands::App(application) => application.run(&environment).await, + SubCommands::Context(context) => context.run(&environment).await, + SubCommands::Identity(identity) => identity.run(&environment).await, SubCommands::JsonRpc(jsonrpc) => jsonrpc.run(&environment).await, }; diff --git a/crates/meroctl/src/cli/context.rs b/crates/meroctl/src/cli/context.rs index 75dfa402a..42ebfde65 100644 --- a/crates/meroctl/src/cli/context.rs +++ b/crates/meroctl/src/cli/context.rs @@ -6,6 +6,7 @@ use eyre::Result as EyreResult; use crate::cli::context::create::CreateCommand; use crate::cli::context::delete::DeleteCommand; use crate::cli::context::get::GetCommand; +use crate::cli::context::invite::InviteCommand; use crate::cli::context::join::JoinCommand; use crate::cli::context::list::ListCommand; use crate::cli::context::watch::WatchCommand; @@ -15,6 +16,7 @@ use crate::output::Report; mod create; mod delete; mod get; +mod invite; mod join; mod list; mod watch; @@ -47,6 +49,7 @@ pub enum ContextSubCommands { List(ListCommand), Create(Box), Join(JoinCommand), + Invite(InviteCommand), Get(GetCommand), #[command(alias = "del")] Delete(DeleteCommand), @@ -68,6 +71,7 @@ impl ContextCommand { ContextSubCommands::Create(create) => create.run(environment).await, ContextSubCommands::Delete(delete) => delete.run(environment).await, ContextSubCommands::Get(get) => get.run(environment).await, + ContextSubCommands::Invite(invite) => invite.run(environment).await, ContextSubCommands::Join(join) => join.run(environment).await, ContextSubCommands::List(list) => list.run(environment).await, ContextSubCommands::Watch(watch) => watch.run(environment).await, diff --git a/crates/meroctl/src/cli/context/invite.rs b/crates/meroctl/src/cli/context/invite.rs new file mode 100644 index 000000000..50babf7d7 --- /dev/null +++ b/crates/meroctl/src/cli/context/invite.rs @@ -0,0 +1,60 @@ +use calimero_primitives::context::ContextId; +use calimero_primitives::identity::PublicKey; +use calimero_server_primitives::admin::{InviteToContextRequest, InviteToContextResponse}; +use clap::Parser; +use eyre::Result as EyreResult; +use reqwest::Client; + +use crate::cli::Environment; +use crate::common::{do_request, fetch_multiaddr, load_config, multiaddr_to_url, RequestType}; +use crate::output::Report; + +#[derive(Debug, Parser)] +#[command(about = "Create invitation to a context for a invitee")] +pub struct InviteCommand { + #[clap( + value_name = "CONTEXT_ID", + help = "The id of the context for which invitation is created" + )] + pub context_id: ContextId, + + #[clap(value_name = "INVITER_ID", help = "The public key of the inviter")] + pub inviter_id: PublicKey, + + #[clap(value_name = "INVITEE_ID", help = "The public key of the invitee")] + pub invitee_id: PublicKey, +} + +impl Report for InviteToContextResponse { + fn report(&self) { + match self.data { + Some(ref payload) => { + println!("{:?}", payload) + } + None => println!("No invitation payload"), + } + } +} + +impl InviteCommand { + pub async fn run(self, environment: &Environment) -> EyreResult<()> { + let config = load_config(&environment.args.home, &environment.args.node_name)?; + + let response: InviteToContextResponse = do_request( + &Client::new(), + multiaddr_to_url(fetch_multiaddr(&config)?, "admin-api/dev/contexts/invite")?, + Some(InviteToContextRequest { + context_id: self.context_id, + inviter_id: self.inviter_id, + invitee_id: self.invitee_id, + }), + &config.identity, + RequestType::Post, + ) + .await?; + + environment.output.write(&response); + + Ok(()) + } +} diff --git a/crates/meroctl/src/cli/identity.rs b/crates/meroctl/src/cli/identity.rs new file mode 100644 index 000000000..59f06a2c9 --- /dev/null +++ b/crates/meroctl/src/cli/identity.rs @@ -0,0 +1,37 @@ +use clap::{Parser, Subcommand}; +use const_format::concatcp; +use eyre::Result as EyreResult; + +use crate::cli::identity::generate::GenerateCommand; +use crate::cli::Environment; + +mod generate; + +pub const EXAMPLES: &str = r" + # + $ meroctl -- --node-name node1 identity generate +"; + +#[derive(Debug, Parser)] +#[command(about = "Command for managing applications")] +#[command(after_help = concatcp!( + "Examples:", + EXAMPLES +))] +pub struct IdentityCommand { + #[command(subcommand)] + pub subcommand: IdentitySubCommands, +} + +#[derive(Debug, Subcommand)] +pub enum IdentitySubCommands { + Generate(GenerateCommand), +} + +impl IdentityCommand { + pub async fn run(self, environment: &Environment) -> EyreResult<()> { + match self.subcommand { + IdentitySubCommands::Generate(generate) => generate.run(environment).await, + } + } +} diff --git a/crates/meroctl/src/cli/identity/generate.rs b/crates/meroctl/src/cli/identity/generate.rs new file mode 100644 index 000000000..ee56424a5 --- /dev/null +++ b/crates/meroctl/src/cli/identity/generate.rs @@ -0,0 +1,40 @@ +use calimero_server_primitives::admin::GenerateContextIdentityResponse; +use clap::Parser; +use eyre::Result as EyreResult; +use reqwest::Client; + +use crate::cli::Environment; +use crate::common::{do_request, fetch_multiaddr, load_config, multiaddr_to_url, RequestType}; +use crate::output::Report; + +#[derive(Debug, Parser)] +#[command(about = "Generate public/private key pair used for context identity")] +pub struct GenerateCommand; + +impl Report for GenerateContextIdentityResponse { + fn report(&self) { + println!("public_key: {}", self.data.public_key); + println!("private_key: {}", self.data.private_key); + } +} + +impl GenerateCommand { + pub async fn run(self, environment: &Environment) -> EyreResult<()> { + let config = load_config(&environment.args.home, &environment.args.node_name)?; + + let url = multiaddr_to_url(fetch_multiaddr(&config)?, "admin-api/dev/identity/context")?; + + let response: GenerateContextIdentityResponse = do_request( + &Client::new(), + url, + None::<()>, + &config.identity, + RequestType::Post, + ) + .await?; + + environment.output.write(&response); + + Ok(()) + } +} diff --git a/crates/server-primitives/src/admin.rs b/crates/server-primitives/src/admin.rs index b8b036b27..3fd690846 100644 --- a/crates/server-primitives/src/admin.rs +++ b/crates/server-primitives/src/admin.rs @@ -8,12 +8,11 @@ use serde_json::Value; use url::Url; #[derive(Clone, Copy, Debug, Deserialize, Serialize)] -#[expect(clippy::exhaustive_structs, reason = "Exhaustive")] pub struct Empty; // -------------------------------------------- Application API -------------------------------------------- #[derive(Clone, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct InstallApplicationRequest { pub url: Url, pub hash: Option, @@ -21,7 +20,6 @@ pub struct InstallApplicationRequest { } impl InstallApplicationRequest { - #[must_use] pub const fn new(url: Url, hash: Option, metadata: Vec) -> Self { Self { url, @@ -32,19 +30,18 @@ impl InstallApplicationRequest { } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct ApplicationInstallResponseData { pub application_id: ApplicationId, } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct InstallApplicationResponse { pub data: ApplicationInstallResponseData, } impl InstallApplicationResponse { - #[must_use] pub const fn new(application_id: ApplicationId) -> Self { Self { data: ApplicationInstallResponseData { application_id }, @@ -53,14 +50,13 @@ impl InstallApplicationResponse { } #[derive(Clone, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct InstallDevApplicationRequest { pub path: Utf8PathBuf, pub metadata: Vec, } impl InstallDevApplicationRequest { - #[must_use] pub const fn new(path: Utf8PathBuf, metadata: Vec) -> Self { Self { path, metadata } } @@ -68,26 +64,29 @@ impl InstallDevApplicationRequest { #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -#[non_exhaustive] pub struct UninstallApplicationRequest { pub application_id: ApplicationId, } +impl UninstallApplicationRequest { + pub const fn new(application_id: ApplicationId) -> Self { + Self { application_id } + } +} + #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -#[non_exhaustive] pub struct UninstallApplicationResponseData { pub application_id: ApplicationId, } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct UninstallApplicationResponse { pub data: UninstallApplicationResponseData, } impl UninstallApplicationResponse { - #[must_use] pub const fn new(application_id: ApplicationId) -> Self { Self { data: UninstallApplicationResponseData { application_id }, @@ -96,19 +95,18 @@ impl UninstallApplicationResponse { } #[derive(Clone, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct ListApplicationResponseData { pub apps: Vec, } #[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct ListApplicationsResponse { pub data: ListApplicationResponseData, } impl ListApplicationsResponse { - #[must_use] pub const fn new(apps: Vec) -> Self { Self { data: ListApplicationResponseData { apps }, @@ -117,64 +115,39 @@ impl ListApplicationsResponse { } #[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct GetApplicationDetailsResponse { pub data: Application, } impl GetApplicationDetailsResponse { - #[must_use] pub const fn new(application: Application) -> Self { Self { data: application } } } #[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] -pub struct GetApplicationResponse { - pub data: GetApplicationResult, -} - -impl GetApplicationResponse { - #[must_use] - pub const fn new(application: Option) -> Self { - Self { - data: GetApplicationResult { application }, - } - } -} - -#[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] -pub struct GetApplicationResult { +#[serde(rename_all = "camelCase")] +pub struct GetApplicationResponseData { pub application: Option, } -// -------------------------------------------- Context API -------------------------------------------- #[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] -pub struct GetContextsResponse { - pub data: ContextList, +#[serde(rename_all = "camelCase")] +pub struct GetApplicationResponse { + pub data: GetApplicationResponseData, } -impl GetContextsResponse { - #[must_use] - pub const fn new(contexts: Vec) -> Self { +impl GetApplicationResponse { + pub const fn new(application: Option) -> Self { Self { - data: ContextList { contexts }, + data: GetApplicationResponseData { application }, } } } - -#[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] -pub struct ContextList { - pub contexts: Vec, -} - +// -------------------------------------------- Context API -------------------------------------------- #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -#[non_exhaustive] pub struct CreateContextRequest { pub application_id: ApplicationId, pub context_seed: Option, @@ -182,7 +155,6 @@ pub struct CreateContextRequest { } impl CreateContextRequest { - #[must_use] pub const fn new( application_id: ApplicationId, context_seed: Option, @@ -196,21 +168,20 @@ impl CreateContextRequest { } } -#[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct CreateContextResponseData { pub context_id: ContextId, pub member_public_key: PublicKey, } -#[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct CreateContextResponse { pub data: CreateContextResponseData, } impl CreateContextResponse { - #[must_use] pub const fn new(context_id: ContextId, member_public_key: PublicKey) -> Self { Self { data: CreateContextResponseData { @@ -228,12 +199,127 @@ pub struct DeletedContextResponseData { } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct DeleteContextResponse { pub data: DeletedContextResponseData, } +impl DeleteContextResponse { + pub const fn new(is_deleted: bool) -> Self { + Self { + data: DeletedContextResponseData { is_deleted }, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextResponse { + pub data: Context, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextStorageResponseData { + pub size_in_bytes: u64, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextStorageResponse { + pub data: GetContextStorageResponseData, +} + +impl GetContextStorageResponse { + pub const fn new(size_in_bytes: u64) -> Self { + Self { + data: GetContextStorageResponseData { size_in_bytes }, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ContextIdentitiesResponseData { + pub identities: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextIdentitiesResponse { + pub data: ContextIdentitiesResponseData, +} + +impl GetContextIdentitiesResponse { + pub const fn new(identities: Vec) -> Self { + Self { + data: ContextIdentitiesResponseData { identities }, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextClientKeysResponseData { + pub client_keys: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextClientKeysResponse { + pub data: GetContextClientKeysResponseData, +} + +impl GetContextClientKeysResponse { + pub const fn new(client_keys: Vec) -> Self { + Self { + data: GetContextClientKeysResponseData { client_keys }, + } + } +} + #[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] +pub struct GetContextUsersResponseData { + pub context_users: Vec, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextUsersResponse { + pub data: GetContextUsersResponseData, +} + +impl GetContextUsersResponse { + pub const fn new(context_users: Vec) -> Self { + Self { + data: GetContextUsersResponseData { context_users }, + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextsResponseData { + pub contexts: Vec, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetContextsResponse { + pub data: GetContextsResponseData, +} + +impl GetContextsResponse { + pub const fn new(contexts: Vec) -> Self { + Self { + data: GetContextsResponseData { contexts }, + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct InviteToContextRequest { pub context_id: ContextId, pub inviter_id: PublicKey, @@ -241,8 +327,6 @@ pub struct InviteToContextRequest { } impl InviteToContextRequest { - #[expect(clippy::similar_names, reason = "Acceptable here")] - #[must_use] pub const fn new(context_id: ContextId, inviter_id: PublicKey, invitee_id: PublicKey) -> Self { Self { context_id, @@ -253,27 +337,25 @@ impl InviteToContextRequest { } #[derive(Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct InviteToContextResponse { - pub invitation_payload: Option, + pub data: Option, } impl InviteToContextResponse { - #[must_use] - pub const fn new(invitation_payload: Option) -> Self { - Self { invitation_payload } + pub const fn new(payload: Option) -> Self { + Self { data: payload } } } #[derive(Clone, Debug, Serialize, Deserialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct JoinContextRequest { pub private_key: PrivateKey, pub invitation_payload: ContextInvitationPayload, } impl JoinContextRequest { - #[must_use] pub const fn new( private_key: PrivateKey, invitation_payload: ContextInvitationPayload, @@ -286,116 +368,78 @@ impl JoinContextRequest { } #[derive(Copy, Clone, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct JoinContextResponseData { pub context_id: ContextId, pub member_public_key: PublicKey, } -impl JoinContextResponseData { - #[must_use] - pub const fn new(context_id: ContextId, member_public_key: PublicKey) -> Self { - Self { - context_id, - member_public_key, - } - } -} - #[derive(Copy, Clone, Debug, Deserialize, Serialize)] -#[non_exhaustive] +#[serde(rename_all = "camelCase")] pub struct JoinContextResponse { pub data: Option, } impl JoinContextResponse { - #[must_use] - pub const fn new(data: Option) -> Self { - Self { data } + pub fn new(data: Option<(ContextId, PublicKey)>) -> Self { + Self { + data: data.map(|(context_id, member_public_key)| JoinContextResponseData { + context_id, + member_public_key, + }), + } } } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -#[non_exhaustive] pub struct UpdateContextApplicationRequest { pub application_id: ApplicationId, } impl UpdateContextApplicationRequest { - #[must_use] pub const fn new(application_id: ApplicationId) -> Self { Self { application_id } } } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct UpdateContextApplicationResponse { pub data: Empty, } +impl UpdateContextApplicationResponse { + pub const fn new() -> Self { + Self { data: Empty {} } + } +} + +// -------------------------------------------- Identity API ---------------------------------------- #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct GetContextStorageResponseData { - pub size_in_bytes: u64, +pub struct GenerateContextIdentityResponseData { + pub public_key: PublicKey, + pub private_key: PrivateKey, } #[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct GetContextStorageResponse { - pub data: GetContextStorageResponseData, +pub struct GenerateContextIdentityResponse { + pub data: GenerateContextIdentityResponseData, } -impl GetContextStorageResponse { - #[must_use] - pub const fn new(size_in_bytes: u64) -> Self { +impl GenerateContextIdentityResponse { + pub const fn new(public_key: PublicKey, private_key: PrivateKey) -> Self { Self { - data: GetContextStorageResponseData { size_in_bytes }, + data: GenerateContextIdentityResponseData { + public_key, + private_key, + }, } } } -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GetContextResponse { - pub data: Context, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ContextIdentitiesResponseData { - pub identities: Vec, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GetContextIdentitiesResponse { - pub data: ContextIdentitiesResponseData, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GetContextClientKeysResponseData { - pub client_keys: Vec, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct GetContextClientKeysResponse { - pub data: GetContextClientKeysResponseData, -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GetContextUsersResponseData { - pub context_users: Vec, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct GetContextUsersResponse { - pub data: GetContextUsersResponseData, -} - // -------------------------------------------- Misc API -------------------------------------------- #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] @@ -561,10 +605,10 @@ pub struct JwtRefreshRequest { } #[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct StarknetPayload { pub signature: Vec, - #[serde(rename = "messageHash")] pub message_hash: String, } diff --git a/crates/server/src/admin/handlers.rs b/crates/server/src/admin/handlers.rs index 6f2ffaf77..a084bff81 100644 --- a/crates/server/src/admin/handlers.rs +++ b/crates/server/src/admin/handlers.rs @@ -3,4 +3,5 @@ pub mod applications; pub mod challenge; pub mod context; pub mod did; +pub mod identity; pub mod root_keys; diff --git a/crates/server/src/admin/handlers/context/get_context_client_keys.rs b/crates/server/src/admin/handlers/context/get_context_client_keys.rs index 4ff1b19be..22b2097c9 100644 --- a/crates/server/src/admin/handlers/context/get_context_client_keys.rs +++ b/crates/server/src/admin/handlers/context/get_context_client_keys.rs @@ -4,9 +4,7 @@ use axum::extract::Path; use axum::response::IntoResponse; use axum::Extension; use calimero_primitives::context::ContextId; -use calimero_server_primitives::admin::{ - GetContextClientKeysResponse, GetContextClientKeysResponseData, -}; +use calimero_server_primitives::admin::GetContextClientKeysResponse; use crate::admin::service::{parse_api_error, ApiResponse}; use crate::admin::storage::client_keys::get_context_client_key; @@ -19,11 +17,10 @@ pub async fn handler( // todo! experiment with Interior: WriteLayer let client_keys_result = get_context_client_key(&state.store.clone(), &context_id) .map_err(|err| parse_api_error(err).into_response()); + match client_keys_result { Ok(client_keys) => ApiResponse { - payload: GetContextClientKeysResponse { - data: GetContextClientKeysResponseData { client_keys }, - }, + payload: GetContextClientKeysResponse::new(client_keys), } .into_response(), Err(err) => err.into_response(), diff --git a/crates/server/src/admin/handlers/context/get_context_identities.rs b/crates/server/src/admin/handlers/context/get_context_identities.rs index 670c8972d..22e4e71af 100644 --- a/crates/server/src/admin/handlers/context/get_context_identities.rs +++ b/crates/server/src/admin/handlers/context/get_context_identities.rs @@ -4,11 +4,8 @@ use axum::extract::Path; use axum::response::IntoResponse; use axum::Extension; use calimero_primitives::context::ContextId; -use calimero_server_primitives::admin::{ - ContextIdentitiesResponseData, GetContextIdentitiesResponse, -}; +use calimero_server_primitives::admin::GetContextIdentitiesResponse; use reqwest::StatusCode; -use tracing::error; use crate::admin::service::{parse_api_error, ApiError, ApiResponse}; use crate::AdminState; @@ -22,38 +19,32 @@ pub async fn handler( .get_context(&context_id) .map_err(|err| parse_api_error(err).into_response()); - match context { - #[expect(clippy::option_if_let_else, reason = "Clearer here")] - Ok(ctx) => match ctx { - Some(context) => { - let context_identities = state - .ctx_manager - .get_context_owned_identities(context.id) - .map_err(|err| parse_api_error(err).into_response()); + let context = match context { + Ok(context) => context, + Err(err) => return err.into_response(), + }; - match context_identities { - Ok(identities) => ApiResponse { - payload: GetContextIdentitiesResponse { - data: ContextIdentitiesResponseData { identities }, - }, - } - .into_response(), - Err(err) => { - error!("Error getting context identities: {:?}", err); - ApiError { - status_code: StatusCode::INTERNAL_SERVER_ERROR, - message: "Something went wrong".into(), - } - .into_response() - } - } - } - None => ApiError { + let context = match context { + Some(context) => context, + None => { + return ApiError { status_code: StatusCode::NOT_FOUND, message: "Context not found".into(), } - .into_response(), - }, + .into_response() + } + }; + + let context_identities = state + .ctx_manager + .get_context_owned_identities(context.id) + .map_err(|err| parse_api_error(err).into_response()); + + match context_identities { + Ok(identities) => ApiResponse { + payload: GetContextIdentitiesResponse::new(identities), + } + .into_response(), Err(err) => err.into_response(), } } diff --git a/crates/server/src/admin/handlers/context/get_context_users.rs b/crates/server/src/admin/handlers/context/get_context_users.rs index 2351c85b7..eab41c72b 100644 --- a/crates/server/src/admin/handlers/context/get_context_users.rs +++ b/crates/server/src/admin/handlers/context/get_context_users.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use axum::extract::Path; use axum::response::IntoResponse; use axum::Extension; -use calimero_server_primitives::admin::{GetContextUsersResponse, GetContextUsersResponseData}; +use calimero_server_primitives::admin::GetContextUsersResponse; use crate::admin::service::ApiResponse; use crate::AdminState; @@ -13,11 +13,7 @@ pub async fn handler( Extension(_state): Extension>, ) -> impl IntoResponse { ApiResponse { - payload: GetContextUsersResponse { - data: GetContextUsersResponseData { - context_users: vec![], - }, - }, + payload: GetContextUsersResponse::new(vec![]), } .into_response() } diff --git a/crates/server/src/admin/handlers/context/join_context.rs b/crates/server/src/admin/handlers/context/join_context.rs index 27d591870..3aca588e2 100644 --- a/crates/server/src/admin/handlers/context/join_context.rs +++ b/crates/server/src/admin/handlers/context/join_context.rs @@ -2,9 +2,7 @@ use std::sync::Arc; use axum::response::IntoResponse; use axum::{Extension, Json}; -use calimero_server_primitives::admin::{ - JoinContextRequest, JoinContextResponse, JoinContextResponseData, -}; +use calimero_server_primitives::admin::{JoinContextRequest, JoinContextResponse}; use crate::admin::service::{parse_api_error, ApiResponse}; use crate::AdminState; @@ -14,7 +12,6 @@ pub async fn handler( Json(JoinContextRequest { private_key, invitation_payload, - .. }): Json, ) -> impl IntoResponse { let result = state @@ -24,10 +21,8 @@ pub async fn handler( .map_err(parse_api_error); match result { - Ok(r) => ApiResponse { - payload: JoinContextResponse::new(r.map(|(context_id, member_public_key)| { - JoinContextResponseData::new(context_id, member_public_key) - })), + Ok(result) => ApiResponse { + payload: JoinContextResponse::new(result), } .into_response(), Err(err) => err.into_response(), diff --git a/crates/server/src/admin/handlers/context/update_context_application.rs b/crates/server/src/admin/handlers/context/update_context_application.rs index 8b33e92c1..d21acf916 100644 --- a/crates/server/src/admin/handlers/context/update_context_application.rs +++ b/crates/server/src/admin/handlers/context/update_context_application.rs @@ -6,7 +6,7 @@ use axum::response::IntoResponse; use axum::{Extension, Json}; use calimero_primitives::context::ContextId; use calimero_server_primitives::admin::{ - Empty, UpdateContextApplicationRequest, UpdateContextApplicationResponse, + UpdateContextApplicationRequest, UpdateContextApplicationResponse, }; use reqwest::StatusCode; @@ -33,7 +33,7 @@ pub async fn handler( match result { Ok(()) => ApiResponse { - payload: UpdateContextApplicationResponse { data: Empty {} }, + payload: UpdateContextApplicationResponse::new(), } .into_response(), Err(err) => err.into_response(), diff --git a/crates/server/src/admin/handlers/identity.rs b/crates/server/src/admin/handlers/identity.rs new file mode 100644 index 000000000..fa0072727 --- /dev/null +++ b/crates/server/src/admin/handlers/identity.rs @@ -0,0 +1 @@ +pub mod generate_context_identity; diff --git a/crates/server/src/admin/handlers/identity/generate_context_identity.rs b/crates/server/src/admin/handlers/identity/generate_context_identity.rs new file mode 100644 index 000000000..3226045fc --- /dev/null +++ b/crates/server/src/admin/handlers/identity/generate_context_identity.rs @@ -0,0 +1,17 @@ +use std::sync::Arc; + +use axum::response::IntoResponse; +use axum::Extension; +use calimero_server_primitives::admin::GenerateContextIdentityResponse; + +use crate::admin::service::ApiResponse; +use crate::AdminState; + +pub async fn handler(Extension(state): Extension>) -> impl IntoResponse { + let private_key = state.ctx_manager.new_identity(); + + ApiResponse { + payload: GenerateContextIdentityResponse::new(private_key.public_key(), private_key), + } + .into_response() +} diff --git a/crates/server/src/admin/service.rs b/crates/server/src/admin/service.rs index 8a171e6e0..6ffe926b0 100644 --- a/crates/server/src/admin/service.rs +++ b/crates/server/src/admin/service.rs @@ -30,9 +30,11 @@ use crate::admin::handlers::applications::{ use crate::admin::handlers::challenge::request_challenge_handler; use crate::admin::handlers::context::{ create_context, delete_context, get_context, get_context_client_keys, get_context_identities, - get_context_storage, get_context_users, get_contexts, join_context, update_context_application, + get_context_storage, get_context_users, get_contexts, invite_to_context, join_context, + update_context_application, }; use crate::admin::handlers::did::fetch_did_handler; +use crate::admin::handlers::identity::generate_context_identity; use crate::admin::handlers::root_keys::{create_root_key_handler, delete_auth_keys_handler}; use crate::config::ServerConfig; use crate::middleware::auth::AuthSignatureLayer; @@ -121,8 +123,13 @@ pub(crate) fn setup( "/contexts/:context_id/identities", get(get_context_identities::handler), ) + .route("/contexts/invite", post(invite_to_context::handler)) .route("/contexts/join", post(join_context::handler)) .route("/contexts", get(get_contexts::handler)) + .route( + "/identity/context", + post(generate_context_identity::handler), + ) .route("/identity/keys", delete(delete_auth_keys_handler)) .route("/generate-jwt-token", post(generate_jwt_token_handler)) .layer(AuthSignatureLayer::new(store)) @@ -156,6 +163,7 @@ pub(crate) fn setup( "/dev/contexts", get(get_contexts::handler).post(create_context::handler), ) + .route("/dev/contexts/invite", post(invite_to_context::handler)) .route("/dev/contexts/join", post(join_context::handler)) .route( "/dev/contexts/:context_id/application", @@ -180,6 +188,10 @@ pub(crate) fn setup( get(get_context_identities::handler), ) .route("/dev/contexts/:context_id", delete(delete_context::handler)) + .route( + "/dev/identity/context", + post(generate_context_identity::handler), + ) .route_layer(from_fn(dev_mode_auth)); let admin_router = Router::new()