kms_secp256k1_api/services/mocks/
mock_kms_client_service.rs

1#[cfg(test)]
2use crate::constants::{
3    CASPER_PUBLIC_KEY_BASE64, CASPER_PUBLIC_KEY_PREFIXED, COSMOS_ADDRESS, COSMOS_PUBLIC_KEY,
4    COSMOS_PUBLIC_KEY_BASE64, COSMOS_SIGNATURE_BASE64, COSMOS_TRANSACTION_HASH, ETH_ADDRESS,
5    ETH_PUBLIC_KEY_BASE64, ETH_SIGNATURE_BASE64, ETH_TRANSACTION_HASH, RANDOM_PUBLIC_KEY_BASE64,
6    SIGNATURE_BASE64, TRANSACTION_HASH,
7};
8#[cfg(test)]
9use crate::services::keys_service::KeyEntry;
10#[cfg(test)]
11use crate::services::kms_client_service::KmsClientService;
12#[cfg(test)]
13use base64::Engine;
14#[cfg(test)]
15use base64::engine::general_purpose::STANDARD;
16#[cfg(test)]
17use k256::{
18    EncodedPoint, Secp256k1,
19    ecdsa::SigningKey,
20    elliptic_curve::{PublicKey, pkcs8::EncodePublicKey, rand_core::OsRng, sec1::FromEncodedPoint},
21};
22
23#[cfg(test)]
24pub struct MockKmsClientService;
25
26#[cfg(test)]
27#[async_trait::async_trait]
28impl KmsClientService for MockKmsClientService {
29    async fn create_key(&self) -> Result<(String, String), String> {
30        let signing_key = SigningKey::random(&mut OsRng);
31        let verifying_key = signing_key.verifying_key();
32        let encoded_point: EncodedPoint = verifying_key.to_encoded_point(false);
33
34        let public_key: PublicKey<Secp256k1> = PublicKey::from_encoded_point(&encoded_point)
35            .into_option()
36            .ok_or_else(|| "Failed to create PublicKey from encoded point".to_string())?;
37
38        let der = public_key
39            .to_public_key_der()
40            .map_err(|e| format!("DER encode error: {e}"))?;
41
42        let der_base64 = STANDARD.encode(der.as_bytes());
43
44        Ok(("mock-key_id".to_string(), der_base64))
45    }
46
47    async fn create_alias(&self, _key_id: &str, _alias: &str) -> Result<(), String> {
48        Ok(())
49    }
50
51    async fn sign(&self, _transaction_hash_hex: &str, address: &str) -> Result<String, String> {
52        if address.eq(CASPER_PUBLIC_KEY_PREFIXED) {
53            Ok(SIGNATURE_BASE64.to_string())
54        } else if address.eq(ETH_ADDRESS) {
55            Ok(ETH_SIGNATURE_BASE64.to_string())
56        } else if address.eq(COSMOS_ADDRESS) {
57            Ok(COSMOS_SIGNATURE_BASE64.to_string())
58        } else {
59            unimplemented!("Mock KMS Client signature type unimplemented for sign")
60        }
61    }
62
63    async fn verify(
64        &self,
65        transaction_hash_hex: &str,
66        signature_base64: &str,
67        key: &str,
68    ) -> Result<bool, String> {
69        let expected_cases = [
70            ExpectedMatch {
71                tx_hash: TRANSACTION_HASH,
72                signature: SIGNATURE_BASE64,
73                key: CASPER_PUBLIC_KEY_PREFIXED,
74            },
75            ExpectedMatch {
76                tx_hash: ETH_TRANSACTION_HASH,
77                signature: ETH_SIGNATURE_BASE64,
78                key: ETH_ADDRESS,
79            },
80            ExpectedMatch {
81                tx_hash: COSMOS_TRANSACTION_HASH,
82                signature: COSMOS_SIGNATURE_BASE64,
83                key: COSMOS_PUBLIC_KEY,
84            },
85        ];
86
87        let matches = expected_cases.iter().any(|case| {
88            transaction_hash_hex.contains(case.tx_hash)
89                && signature_base64 == case.signature
90                && key.contains(case.key)
91                || key == case.key
92        });
93
94        Ok(matches)
95    }
96
97    async fn delete_key(&self, key: &str) -> Result<bool, String> {
98        if key.contains("known_public_key") {
99            Ok(true)
100        } else {
101            Ok(false)
102        }
103    }
104
105    async fn list_keys(&self) -> Result<Vec<KeyEntry>, String> {
106        Ok(vec![
107            KeyEntry {
108                address: "address_1".to_string().into(),
109                public_key_base64: STANDARD.encode("public_key_1_base64").into(),
110                public_key: Some("public_key_1".to_string()).into(),
111                key_id: "key_id_1".to_string().into(),
112            },
113            KeyEntry {
114                address: "address_2".to_string().into(),
115                public_key_base64: STANDARD.encode("public_key_2_base64").into(),
116                public_key: Some("public_key_2".to_string()).into(),
117                key_id: "key_id_2".to_string().into(),
118            },
119        ])
120    }
121
122    async fn get_public_key(&self, alias: &str) -> Result<String, String> {
123        if CASPER_PUBLIC_KEY_PREFIXED.contains(alias) {
124            Ok(CASPER_PUBLIC_KEY_BASE64.to_string())
125        } else if alias.eq(ETH_ADDRESS) {
126            Ok(ETH_PUBLIC_KEY_BASE64.to_string())
127        } else if alias.eq(COSMOS_ADDRESS) {
128            Ok(COSMOS_PUBLIC_KEY_BASE64.to_string())
129        } else if alias.eq("bad_key") {
130            Ok(
131                RANDOM_PUBLIC_KEY_BASE64.to_string(), // random key
132            )
133        } else {
134            unimplemented!("Mock KMS Client signature type unimplemented for get_public_key")
135        }
136    }
137}
138
139#[allow(dead_code)]
140struct ExpectedMatch<'a> {
141    tx_hash: &'a str,
142    signature: &'a str,
143    key: &'a str,
144}