From 04673f42d01307f1592b08179750ec8ee05483d6 Mon Sep 17 00:00:00 2001 From: Michael Jeffrey Date: Tue, 29 Oct 2024 14:24:22 -0700 Subject: [PATCH] mobile config list programs fix (#883) * verify the correct field fo the request * add carrier service to mobile-config-cli * verify response * cast start_ts and stop_ts to bigint from numeric for promotion list --- mobile_config/src/carrier_service.rs | 9 +++-- mobile_config_cli/src/client.rs | 52 ++++++++++++++++++++++++--- mobile_config_cli/src/cmds/carrier.rs | 11 ++++++ mobile_config_cli/src/cmds/mod.rs | 20 +++++++++++ mobile_config_cli/src/main.rs | 7 +++- 5 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 mobile_config_cli/src/cmds/carrier.rs diff --git a/mobile_config/src/carrier_service.rs b/mobile_config/src/carrier_service.rs index 5bc96c7ec..4ffd9b6a7 100644 --- a/mobile_config/src/carrier_service.rs +++ b/mobile_config/src/carrier_service.rs @@ -83,7 +83,7 @@ impl CarrierService { r#" SELECT c.name as carrier_name, c.incentive_escrow_fund_bps, - iep.carrier, iep.start_ts, iep.stop_ts, iep.shares, iep.name as promo_name + iep.carrier, iep.start_ts::bigint, iep.stop_ts::bigint, iep.shares, iep.name as promo_name FROM carriers c JOIN incentive_escrow_programs iep on c.address = iep.carrier @@ -95,7 +95,10 @@ impl CarrierService { .bind(timestamp) .fetch_all(&self.metadata_db) .await - .map_err(|_| Status::internal("could not fetch incentive programs"))?; + .map_err(|err| { + tracing::error!(?err, "fetching incentive programs"); + Status::internal("could not fetch incentive programs") + })?; let mut sp_promotions: HashMap = HashMap::new(); for row in rows { @@ -149,7 +152,7 @@ impl mobile_config::CarrierService for CarrierService { telemetry::count_request("carrier_service", "list_incentive_promotions"); custom_tracing::record_b58("signer", &request.signer); - let signer = verify_public_key(&request.signature)?; + let signer = verify_public_key(&request.signer)?; self.verify_request_signature(&signer, &request)?; let timestamp = request.timestamp; diff --git a/mobile_config_cli/src/client.rs b/mobile_config_cli/src/client.rs index 97d0d3284..10fca6c14 100644 --- a/mobile_config_cli/src/client.rs +++ b/mobile_config_cli/src/client.rs @@ -8,15 +8,20 @@ use futures::{stream, StreamExt}; use helium_crypto::{Keypair, PublicKey, Sign, Verify}; use helium_proto::{ services::mobile_config::{ - admin_client, authorization_client, entity_client, gateway_client, AdminAddKeyReqV1, - AdminKeyResV1, AdminRemoveKeyReqV1, AuthorizationListReqV1, AuthorizationListResV1, - AuthorizationVerifyReqV1, AuthorizationVerifyResV1, EntityVerifyReqV1, EntityVerifyResV1, - GatewayInfoBatchReqV1, GatewayInfoReqV1, GatewayInfoResV1, GatewayInfoStreamResV1, + admin_client, authorization_client, carrier_service_client, entity_client, gateway_client, + AdminAddKeyReqV1, AdminKeyResV1, AdminRemoveKeyReqV1, AuthorizationListReqV1, + AuthorizationListResV1, AuthorizationVerifyReqV1, AuthorizationVerifyResV1, + CarrierIncentivePromotionListReqV1, CarrierIncentivePromotionListResV1, EntityVerifyReqV1, + EntityVerifyResV1, GatewayInfoBatchReqV1, GatewayInfoReqV1, GatewayInfoResV1, + GatewayInfoStreamResV1, }, Message, }; use mobile_config::KeyRole; -use std::str::FromStr; +use std::{ + str::FromStr, + time::{SystemTime, UNIX_EPOCH}, +}; pub struct AdminClient { client: admin_client::AdminClient, @@ -28,6 +33,11 @@ pub struct AuthClient { server_pubkey: PublicKey, } +pub struct CarrierClient { + client: carrier_service_client::CarrierServiceClient, + server_pubkey: PublicKey, +} + pub struct EntityClient { client: entity_client::EntityClient, server_pubkey: PublicKey, @@ -142,6 +152,36 @@ impl AuthClient { } } +impl CarrierClient { + pub async fn new(host: &str, server_pubkey: &str) -> Result { + Ok(Self { + client: carrier_service_client::CarrierServiceClient::connect(host.to_owned()).await?, + server_pubkey: PublicKey::from_str(server_pubkey)?, + }) + } + + pub async fn list_incentive_promotions( + &mut self, + keypair: &Keypair, + ) -> Result { + let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs(); + let mut request = CarrierIncentivePromotionListReqV1 { + timestamp, + signer: keypair.public_key().into(), + signature: vec![], + }; + request.signature = request.sign(keypair)?; + match self.client.list_incentive_promotions(request).await { + Ok(response) => { + let res = response.into_inner(); + res.verify(&self.server_pubkey)?; + Ok(res) + } + Err(error) => Err(error)?, + } + } +} + impl EntityClient { pub async fn new(host: &str, server_pubkey: &str) -> Result { Ok(Self { @@ -252,6 +292,7 @@ impl_sign!(AuthorizationListReqV1, signature); impl_sign!(EntityVerifyReqV1, signature); impl_sign!(GatewayInfoReqV1, signature); impl_sign!(GatewayInfoBatchReqV1, signature); +impl_sign!(CarrierIncentivePromotionListReqV1, signature); pub trait MsgVerify: Message + std::clone::Clone { fn verify(&self, verifier: &PublicKey) -> Result @@ -281,3 +322,4 @@ impl_verify!(AuthorizationListResV1, signature); impl_verify!(EntityVerifyResV1, signature); impl_verify!(GatewayInfoResV1, signature); impl_verify!(GatewayInfoStreamResV1, signature); +impl_verify!(CarrierIncentivePromotionListResV1, signature); diff --git a/mobile_config_cli/src/cmds/carrier.rs b/mobile_config_cli/src/cmds/carrier.rs new file mode 100644 index 000000000..66e799832 --- /dev/null +++ b/mobile_config_cli/src/cmds/carrier.rs @@ -0,0 +1,11 @@ +use crate::{client, Msg, PrettyJson, Result}; + +use super::{ListIncentivePromotions, PathBufKeypair}; + +pub async fn list_incentive_promotions(args: ListIncentivePromotions) -> Result { + let mut client = client::CarrierClient::new(&args.config_host, &args.config_pubkey).await?; + let list = client + .list_incentive_promotions(&args.keypair.to_keypair()?) + .await?; + Msg::ok(list.pretty_json()?) +} diff --git a/mobile_config_cli/src/cmds/mod.rs b/mobile_config_cli/src/cmds/mod.rs index 889a15e73..04d4b1f61 100644 --- a/mobile_config_cli/src/cmds/mod.rs +++ b/mobile_config_cli/src/cmds/mod.rs @@ -7,6 +7,7 @@ use std::path::PathBuf; pub mod admin; pub mod authorization; +pub mod carrier; pub mod entity; pub mod env; pub mod gateway; @@ -67,6 +68,10 @@ pub enum Commands { #[command(subcommand)] command: AuthCommands, }, + Carrier { + #[command(subcommand)] + command: CarrierCommands, + }, /// Entity Entity { #[command(subcommand)] @@ -113,6 +118,21 @@ pub struct ListNetKeys { pub config_pubkey: String, } +#[derive(Debug, Subcommand)] +pub enum CarrierCommands { + ListIncentivePromotions(ListIncentivePromotions), +} + +#[derive(Debug, Args)] +pub struct ListIncentivePromotions { + #[arg(from_global)] + pub keypair: PathBuf, + #[arg(from_global)] + pub config_host: String, + #[arg(from_global)] + pub config_pubkey: String, +} + #[derive(Debug, Subcommand)] pub enum EntityCommands { /// Verify the rewardable entity on-chain diff --git a/mobile_config_cli/src/main.rs b/mobile_config_cli/src/main.rs index 18d9ef638..dcb6b3fbd 100644 --- a/mobile_config_cli/src/main.rs +++ b/mobile_config_cli/src/main.rs @@ -1,6 +1,6 @@ use clap::Parser; use mobile_config_cli::{ - cmds::{self, admin, authorization, entity, env, gateway, Cli, Commands}, + cmds::{self, admin, authorization, carrier, entity, env, gateway, Cli, Commands}, Msg, Result, }; @@ -33,6 +33,11 @@ pub async fn handle_cli(cli: Cli) -> Result { cmds::AuthCommands::VerifyKey(args) => authorization::verify_key_role(args).await, cmds::AuthCommands::ListKeys(args) => authorization::list_keys_role(args).await, }, + Commands::Carrier { command } => match command { + cmds::CarrierCommands::ListIncentivePromotions(args) => { + carrier::list_incentive_promotions(args).await + } + }, Commands::Entity { command } => match command { cmds::EntityCommands::VerifyEntity(args) => entity::verify_entity(args).await, },