kms_secp256k1_api/
config.rs

1use crate::constants::{
2    AWS_KMS_ENDPOINT_PATTERN, DEFAULT_APP_ADDR, DEFAULT_APP_PORT, DEFAULT_AWS_REGION,
3    DEFAULT_COSMOS_CHAIN_ID, DEFAULT_COSMOS_HRP, DEFAULT_COSMOS_REST_URL, DEFAULT_ETH_CHAIN_ID,
4};
5use std::env;
6use tracing::{error, info};
7
8#[derive(Debug, Clone, Default)]
9pub struct AwsCreds {
10    pub access_key_id: String,
11    pub secret_access_key: String,
12}
13
14#[derive(Debug, Clone, Default)]
15pub struct AwsConfig {
16    pub region: String,
17    pub endpoint: String,
18    pub sign: AwsCreds,
19    pub create: AwsCreds,
20    pub delete: Option<AwsCreds>,
21    pub list: Option<AwsCreds>,
22    pub hash_type: HashType,
23}
24
25#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
26pub enum HashType {
27    #[default]
28    Sha256,
29    Keccak256,
30    // Sha3_256,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Default)]
34#[non_exhaustive]
35pub enum BlockchainMode {
36    #[default]
37    Casper,
38    Ethereum,
39    Cosmos,
40}
41
42#[allow(clippy::struct_excessive_bools)]
43#[derive(Debug, Clone)]
44pub struct Config {
45    blockchain_mode: BlockchainMode,
46    addr: String,
47    port: u16,
48    aws: AwsConfig,
49    testing_mode: bool,
50    aws_mode: bool,
51    delete_mode: bool,
52    list_mode: bool,
53    eth_chain_id: u8,
54    cosmos_hrp: String,
55    cosmos_rest_url: String,
56    cosmos_chain_id: String,
57}
58
59impl Default for Config {
60    fn default() -> Self {
61        Self {
62            blockchain_mode: BlockchainMode::default(), // CASPER MODE by default
63            port: DEFAULT_APP_PORT,
64            addr: DEFAULT_APP_ADDR.to_string(),
65            aws: AwsConfig::default(),
66            testing_mode: true, // TESTING_MODE true by default
67            aws_mode: false,
68            delete_mode: false,
69            list_mode: false,
70            eth_chain_id: DEFAULT_ETH_CHAIN_ID,
71            cosmos_hrp: DEFAULT_COSMOS_HRP.to_string(),
72            cosmos_rest_url: DEFAULT_COSMOS_REST_URL.to_string(),
73            cosmos_chain_id: DEFAULT_COSMOS_CHAIN_ID.to_string(),
74        }
75    }
76}
77
78impl Config {
79    #[must_use]
80    pub fn from_env() -> Self {
81        dotenvy::dotenv().ok();
82
83        let testing_mode = env::var("TESTING_MODE")
84            .map(|v| v == "true")
85            .unwrap_or(true);
86
87        let delete_mode = env::var("DELETE_MODE")
88            .map(|v| v == "true")
89            .unwrap_or(false);
90        let list_mode = env::var("LIST_MODE").map(|v| v == "true").unwrap_or(false);
91
92        let sign = get_creds("KMS_SIGN_ID", "KMS_SIGN_KEY");
93        let create = get_creds("KMS_CREATE_ID", "KMS_CREATE_KEY");
94        let delete = delete_mode.then(|| get_creds("KMS_DELETE_ID", "KMS_DELETE_KEY"));
95        let list = list_mode.then(|| get_creds("KMS_LIST_ID", "KMS_LIST_KEY"));
96        let aws_mode = env::var("AWS_MODE").map(|v| v == "true").unwrap_or(true);
97
98        let blockchain_mode = match env::var("BLOCKCHAIN_MODE")
99            .unwrap_or_else(|_| format!("{:?}", BlockchainMode::default()))
100            .to_lowercase()
101            .as_str()
102        {
103            "casper" => BlockchainMode::Casper,
104            "ethereum" => BlockchainMode::Ethereum,
105            "cosmos" => BlockchainMode::Cosmos,
106            _ => BlockchainMode::default(),
107        };
108
109        let hash_type = match blockchain_mode {
110            BlockchainMode::Casper | BlockchainMode::Cosmos => HashType::Sha256,
111            BlockchainMode::Ethereum => HashType::Keccak256,
112        };
113
114        log_modes(&Modes {
115            delete_mode,
116            list_mode,
117            aws_mode,
118            testing_mode,
119            blockchain_mode: blockchain_mode.clone(),
120            hash_type,
121        });
122
123        let region = env::var("AWS_REGION").unwrap_or_else(|_| DEFAULT_AWS_REGION.into());
124        let endpoint = env::var("AWS_ENDPOINT").unwrap_or_else(|_| {
125            // If AWS_ENDPOINT is not set, construct it from the region using the standard pattern
126            AWS_KMS_ENDPOINT_PATTERN.replace("{}", &region)
127        });
128
129        Self {
130            blockchain_mode,
131            port: env::var("APP_PORT")
132                .ok()
133                .and_then(|v| v.parse().ok())
134                .unwrap_or(DEFAULT_APP_PORT),
135            addr: env::var("APP_ADDR")
136                .ok()
137                .unwrap_or_else(|| DEFAULT_APP_ADDR.to_string()),
138            aws: AwsConfig {
139                region,
140                endpoint,
141                sign,
142                create,
143                delete,
144                list,
145                hash_type,
146            },
147            aws_mode,
148            testing_mode,
149            delete_mode,
150            list_mode,
151            eth_chain_id: env::var("ETH_CHAIN_ID")
152                .ok()
153                .and_then(|v| v.parse().ok())
154                .unwrap_or(DEFAULT_ETH_CHAIN_ID),
155            cosmos_hrp: env::var("COSMOS_HRP")
156                .ok()
157                .and_then(|v| v.parse().ok())
158                .unwrap_or_else(|| DEFAULT_COSMOS_HRP.to_string()),
159            cosmos_rest_url: env::var("COSMOS_REST_URL")
160                .ok()
161                .and_then(|v| v.parse().ok())
162                .unwrap_or_else(|| DEFAULT_COSMOS_REST_URL.to_string()),
163            cosmos_chain_id: env::var("COSMOS_CHAIN_ID")
164                .ok()
165                .and_then(|v| v.parse().ok())
166                .unwrap_or_else(|| DEFAULT_COSMOS_CHAIN_ID.to_string()),
167        }
168    }
169
170    #[must_use]
171    pub const fn is_testing_mode(&self) -> bool {
172        self.testing_mode
173    }
174
175    #[must_use]
176    pub fn is_ethereum_mode(&self) -> bool {
177        self.blockchain_mode == BlockchainMode::Ethereum
178    }
179
180    #[must_use]
181    pub fn is_casper_mode(&self) -> bool {
182        self.blockchain_mode == BlockchainMode::Casper
183    }
184
185    #[must_use]
186    pub fn is_cosmos_mode(&self) -> bool {
187        self.blockchain_mode == BlockchainMode::Cosmos
188    }
189
190    #[must_use]
191    pub const fn is_delete_mode(&self) -> bool {
192        self.delete_mode
193    }
194
195    #[must_use]
196    pub const fn is_list_mode(&self) -> bool {
197        self.list_mode
198    }
199
200    #[must_use]
201    pub const fn is_aws_mode(&self) -> bool {
202        self.aws_mode
203    }
204
205    #[must_use]
206    pub fn get_aws_config(&self) -> AwsConfig {
207        self.aws.clone()
208    }
209
210    #[must_use]
211    pub const fn get_port(&self) -> u16 {
212        self.port
213    }
214
215    #[must_use]
216    pub fn get_addr(&self) -> String {
217        self.addr.clone()
218    }
219
220    #[must_use]
221    pub const fn get_eth_chain_id(&self) -> u8 {
222        self.eth_chain_id
223    }
224
225    #[must_use]
226    pub fn get_cosmos_hrp(&self) -> String {
227        self.cosmos_hrp.clone()
228    }
229
230    #[must_use]
231    pub fn get_cosmos_rest_url(&self) -> String {
232        self.cosmos_rest_url.clone()
233    }
234
235    #[must_use]
236    pub fn get_cosmos_chain_id(&self) -> String {
237        self.cosmos_chain_id.clone()
238    }
239}
240
241fn get_creds(id_key: &str, secret_key: &str) -> AwsCreds {
242    let id = env::var(id_key).unwrap_or_default();
243    let secret = env::var(secret_key).unwrap_or_default();
244
245    if id.is_empty() {
246        error!("{id_key} env var is empty");
247    }
248    if secret.is_empty() {
249        error!("{secret_key} env var is empty");
250    }
251
252    AwsCreds {
253        access_key_id: id,
254        secret_access_key: secret,
255    }
256}
257
258#[allow(clippy::struct_excessive_bools)]
259struct Modes {
260    delete_mode: bool,
261    list_mode: bool,
262    aws_mode: bool,
263    testing_mode: bool,
264    blockchain_mode: BlockchainMode,
265    hash_type: HashType,
266}
267
268#[allow(clippy::cognitive_complexity)]
269fn log_modes(modes: &Modes) {
270    info!("testing_mode: {}", modes.testing_mode);
271    info!("aws_mode: {}", modes.aws_mode);
272    info!("delete_mode: {}", modes.delete_mode);
273    info!("list_mode: {}", modes.list_mode);
274    info!("blockchain_mode: {:?}", modes.blockchain_mode);
275    info!("hash_type: {:?}", modes.hash_type);
276}
277
278#[derive(Debug, Default)]
279pub struct ConfigBuilder {
280    config: Config,
281}
282
283impl ConfigBuilder {
284    #[must_use]
285    pub fn new() -> Self {
286        Self::default()
287    }
288
289    #[must_use]
290    pub const fn with_blockchain_mode(mut self, mode: BlockchainMode) -> Self {
291        self.config.blockchain_mode = mode;
292        self
293    }
294
295    #[must_use]
296    pub const fn with_casper_mode(mut self) -> Self {
297        self.config.blockchain_mode = BlockchainMode::Casper;
298        self
299    }
300
301    #[must_use]
302    pub const fn with_ethereum_mode(mut self) -> Self {
303        self.config.blockchain_mode = BlockchainMode::Ethereum;
304        self
305    }
306
307    #[must_use]
308    pub const fn with_cosmos_mode(mut self) -> Self {
309        self.config.blockchain_mode = BlockchainMode::Cosmos;
310        self
311    }
312
313    #[must_use]
314    pub const fn with_testing_mode(mut self, enabled: bool) -> Self {
315        self.config.testing_mode = enabled;
316        self
317    }
318
319    #[must_use]
320    pub const fn with_delete_mode(mut self, enabled: bool) -> Self {
321        self.config.delete_mode = enabled;
322        self
323    }
324
325    #[must_use]
326    pub const fn with_list_mode(mut self, enabled: bool) -> Self {
327        self.config.list_mode = enabled;
328        self
329    }
330
331    #[must_use]
332    pub const fn with_aws_mode(mut self, enabled: bool) -> Self {
333        self.config.aws_mode = enabled;
334        self
335    }
336
337    #[must_use]
338    pub const fn with_port(mut self, port: u16) -> Self {
339        self.config.port = port;
340        self
341    }
342
343    #[must_use]
344    pub const fn with_eth_chain_id(mut self, id: u8) -> Self {
345        self.config.eth_chain_id = id;
346        self
347    }
348
349    #[must_use]
350    pub fn with_aws_config(mut self, aws: AwsConfig) -> Self {
351        self.config.aws = aws;
352        self
353    }
354
355    #[must_use]
356    pub fn build(self) -> Config {
357        self.config
358    }
359}