11//! Command line and environment variable settings for the Catalyst Signed Docs
22
3- use std:: time:: Duration ;
3+ use std:: { collections:: HashMap , str:: FromStr , time:: Duration } ;
4+
5+ use hex:: FromHex ;
6+ use itertools:: Itertools ;
47
58use super :: str_env_var:: StringEnvVar ;
69
@@ -18,6 +21,11 @@ pub(crate) struct EnvVars {
1821
1922 /// The Catalyst Signed Document threshold, document cannot be too far behind.
2023 past_threshold : Duration ,
24+
25+ /// The Catalyst Signed Document Admin keys map from the `SIGNED_DOC_ADMIN_KEYS` env
26+ /// var. Each Admin key entry is a pair of `CatalystId` string and hex encoded
27+ /// `VerifyingKey` separated by ';' character.
28+ admin_keys : HashMap < catalyst_signed_doc:: CatalystId , ed25519_dalek:: VerifyingKey > ,
2129}
2230
2331impl EnvVars {
@@ -29,9 +37,16 @@ impl EnvVars {
2937 let past_threshold =
3038 StringEnvVar :: new_as_duration ( "SIGNED_DOC_PAST_THRESHOLD" , DEFAULT_PAST_THRESHOLD ) ;
3139
40+ let admin_keys = string_to_admin_keys (
41+ & StringEnvVar :: new_optional ( "SIGNED_DOC_ADMIN_KEYS" , false )
42+ . map ( |v| v. as_string ( ) )
43+ . unwrap_or_default ( ) ,
44+ ) ;
45+
3246 Self {
3347 future_threshold,
3448 past_threshold,
49+ admin_keys,
3550 }
3651 }
3752
@@ -46,4 +61,59 @@ impl EnvVars {
4661 pub ( crate ) fn past_threshold ( & self ) -> Duration {
4762 self . past_threshold
4863 }
64+
65+ /// The Catalyst Signed Document Admin keys map.
66+ #[ allow( dead_code) ]
67+ pub ( crate ) fn admin_keys (
68+ & self
69+ ) -> & HashMap < catalyst_signed_doc:: CatalystId , ed25519_dalek:: VerifyingKey > {
70+ & self . admin_keys
71+ }
72+ }
73+
74+ /// Transform a string list of admin keys into a map.
75+ /// Each Admin key entry is a pair of `CatalystId` string and hex encoded
76+ /// `VerifyingKey` separated by ';' character.
77+ fn string_to_admin_keys (
78+ admin_keys : & str
79+ ) -> HashMap < catalyst_signed_doc:: CatalystId , ed25519_dalek:: VerifyingKey > {
80+ admin_keys
81+ . split ( ',' )
82+ // filters out at the beginning all empty entries, because they all would be invalid and
83+ // filtered out anyway
84+ . filter ( |s| !s. is_empty ( ) )
85+ . filter_map ( |s| {
86+ // split `CatalystId` and `VerifyingKey` by `;` character.
87+ let Some ( ( id, key) ) = s. split ( ';' ) . collect_tuple ( ) else {
88+ tracing:: error!( entry = s, "Invalid admin key entry" ) ;
89+ return None ;
90+ } ;
91+
92+ let id = catalyst_signed_doc:: CatalystId :: from_str ( id)
93+ . inspect_err ( |err| {
94+ tracing:: error!(
95+ err = ?err,
96+ "Cannot parse Admin CatalystId entry, skipping the value..."
97+ ) ;
98+ } )
99+ . ok ( ) ?;
100+
101+ // Strip the prefix and convert to 32 bytes array
102+ let key = key
103+ . strip_prefix ( "0x" )
104+ . ok_or ( anyhow:: anyhow!(
105+ "Admin key hex value does not start with '0x'"
106+ ) )
107+ . and_then ( |s| Ok ( Vec :: from_hex ( s) ?) )
108+ . and_then ( |bytes| Ok ( bytes. as_slice ( ) . try_into ( ) ?) )
109+ . inspect_err ( |err| {
110+ tracing:: error!(
111+ err = ?err,
112+ "Cannot parse Admin VerifyingKey entry, skipping the value..."
113+ ) ;
114+ } )
115+ . ok ( ) ?;
116+ Some ( ( id, key) )
117+ } )
118+ . collect ( )
49119}
0 commit comments