diff --git a/mobile_config/tests/entity_service.rs b/mobile_config/tests/entity_service.rs new file mode 100644 index 000000000..b447ae8c1 --- /dev/null +++ b/mobile_config/tests/entity_service.rs @@ -0,0 +1,81 @@ +use std::vec; + +use helium_crypto::{PublicKey, Sign}; +use helium_proto::services::mobile_config::{self as proto, EntityClient, EntityVerifyReqV1}; +use mobile_config::{ + entity_service::EntityService, + key_cache::{CacheKeys, KeyCache}, + KeyRole, +}; +use prost::Message; +use sqlx::PgPool; +use tokio::net::TcpListener; +use tonic::transport; + +pub mod common; +use common::*; + +async fn spawn_entity_service( + pool: PgPool, + admin_pub_key: PublicKey, +) -> ( + String, + tokio::task::JoinHandle>, +) { + let server_key = make_keypair(); + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + // Start the entity server + let keys = CacheKeys::from_iter([(admin_pub_key.to_owned(), KeyRole::Administrator)]); + let (_key_cache_tx, key_cache) = KeyCache::new(keys); + let gws = EntityService::new(key_cache, pool.clone(), server_key); + let handle = tokio::spawn( + transport::Server::builder() + .add_service(proto::EntityServer::new(gws)) + .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener)), + ); + + (format!("http://{addr}"), handle) +} + +#[sqlx::test(fixtures("key_to_assets_es.sql"))] +async fn entity_service_verify(pool: PgPool) { + let admin_key = make_keypair(); + let (addr, _handle) = spawn_entity_service(pool.clone(), admin_key.public_key().clone()).await; + let mut client = EntityClient::connect(addr).await.unwrap(); + // Case 1: utf8 serialization + let mut req = EntityVerifyReqV1 { + entity_id: "Helium Mobile Mapping Rewards".to_string().into_bytes(), + signer: admin_key.public_key().clone().into(), + signature: vec![], + }; + req.signature = admin_key.sign(&req.encode_to_vec()).unwrap(); + + // Should not fail (return Ok message) + client.verify(req).await.unwrap(); + + // Case 2: b58 serialization + let entity_bytes = bs58::decode("112d6JcLCyi5cs5BCXhK22VAgEAQNRvKkP9KW5XHeRAQpHoHhFyF") + .into_vec() + .unwrap(); + + let mut req = EntityVerifyReqV1 { + entity_id: entity_bytes, + signer: admin_key.public_key().clone().into(), + signature: vec![], + }; + req.signature = admin_key.sign(&req.encode_to_vec()).unwrap(); + // Should not fail (return Ok message) + client.verify(req).await.unwrap(); + + // Case 3: entity doesn't exist + let mut req = EntityVerifyReqV1 { + entity_id: "nonexistent".to_string().into_bytes(), + signer: admin_key.public_key().clone().into(), + signature: vec![], + }; + req.signature = admin_key.sign(&req.encode_to_vec()).unwrap(); + // Should return error + client.verify(req).await.unwrap_err(); +} diff --git a/mobile_config/tests/fixtures/key_to_assets_es.sql b/mobile_config/tests/fixtures/key_to_assets_es.sql new file mode 100644 index 000000000..031f32afa --- /dev/null +++ b/mobile_config/tests/fixtures/key_to_assets_es.sql @@ -0,0 +1,16 @@ +CREATE TABLE public.key_to_assets ( + address character varying(255) NOT NULL, + dao character varying(255), + asset character varying(255), + entity_key bytea, + bump_seed integer, + refreshed_at timestamp with time zone, + created_at timestamp with time zone NOT NULL, + key_serialization jsonb +); + +INSERT INTO "key_to_assets" ("address", "dao", "asset", "entity_key", "bump_seed", "refreshed_at", "created_at", "key_serialization") VALUES +('4TCw73EqhtXbDp19D4WY72vWZo9QWY6gcphRFswzKBNk', 'BQ3MCuTT5zVBhNfQ4SjMh3NPVhFy73MPV8rjfq5d1zie', 'HJtATvtga22LQPViQGoSdwqoHMS8uxirNNsRyGpQK1Nc', 'Helium Mobile Mapping Rewards', 254, '2025-06-12 02:24:01.305+00', '2025-06-12 02:24:01.305+00', '"utf8"'); + +INSERT INTO "key_to_assets" ("address", "dao", "asset", "entity_key", "bump_seed", "refreshed_at", "created_at", "key_serialization") VALUES +('4RsbdRtGNiMEUPPJrmkVpSUswYXLKtZLUKaiyaGFxyd5', 'BQ3MCuTT5zVBhNfQ4SjMh3NPVhFy73MPV8rjfq5d1zie', '4xpWF7KjbcShMt3LnEJmPkbDVyEZ19zrwtJwS1e1e827', decode('0000d5a568ab7b418ba68eabe61b5b042f84afcfa86f1cdfcdba644401b6bcb65c84af622936', 'hex'), 253, '2025-04-30 16:49:26.499+00', '2023-05-04 14:36:16.429+00', '"b58"');