11use arrayref:: array_ref;
22use ed25519_dalek:: { Digest , Sha512 , SigningKey , VerifyingKey } ;
3- use failure:: Error ;
3+ use failure:: { bail , Error } ;
44use serde:: * ;
5+ use strum:: { EnumDiscriminants , EnumString , VariantNames } ;
56
67use crate :: public_key;
78pub const SEED_SIZE : usize = 32 ;
@@ -43,6 +44,7 @@ const ARGON2_ADDITIONAL_DATA: &[u8] = b"hpos-config admin ed25519 key v1";
4344
4445pub type Seed = [ u8 ; SEED_SIZE ] ;
4546
47+ #[ cfg_attr( test, derive( Clone , PartialEq ) ) ]
4648#[ derive( Debug , Deserialize , Serialize ) ]
4749pub struct Admin {
4850 pub email : String ,
@@ -53,12 +55,18 @@ pub struct Admin {
5355 pub public_key : VerifyingKey ,
5456}
5557
58+ #[ cfg_attr( test, derive( Clone , PartialEq ) ) ]
5659#[ derive( Debug , Deserialize , Serialize ) ]
5760pub struct Settings {
5861 pub admin : Admin ,
5962}
6063
61- #[ derive( Debug , Deserialize , Serialize ) ]
64+ #[ cfg_attr( test, derive( Clone , PartialEq ) ) ]
65+ #[ derive( Debug , Deserialize , Serialize , EnumDiscriminants ) ]
66+ #[ strum_discriminants(
67+ derive( VariantNames , EnumString , strum:: Display ) ,
68+ strum( ascii_case_insensitive)
69+ ) ]
6270pub enum Config {
6371 #[ serde( rename = "v1" ) ]
6472 V1 {
@@ -146,6 +154,58 @@ impl Config {
146154 | Config :: V3 { settings, .. } => settings. admin . public_key ,
147155 }
148156 }
157+
158+ /// Try to convert Config instance to the desired ConfigDiscriminants.
159+ /// As some conversions are impossible they will return an error accordingly.
160+ pub fn try_convert ( self , desired : ConfigDiscriminants ) -> Result < Self , Error > {
161+ match ( self , desired) {
162+ ( cfg @ Config :: V1 { .. } , ConfigDiscriminants :: V1 ) => Ok ( cfg) ,
163+ ( Config :: V1 { .. } , ConfigDiscriminants :: V2 ) => bail ! ( "cannot convert V1 to V2" ) ,
164+ ( Config :: V1 { .. } , ConfigDiscriminants :: V3 ) => bail ! ( "cannot convert V1 to V3" ) ,
165+ (
166+ Config :: V2 {
167+ device_bundle,
168+ derivation_path,
169+ registration_code,
170+ settings,
171+ } ,
172+ ConfigDiscriminants :: V1 ,
173+ ) => Ok ( Config :: V2 {
174+ device_bundle,
175+ derivation_path,
176+ registration_code,
177+ settings,
178+ } ) ,
179+ ( cfg @ Config :: V2 { .. } , ConfigDiscriminants :: V2 ) => Ok ( cfg) ,
180+ ( Config :: V2 { .. } , ConfigDiscriminants :: V3 ) => bail ! ( "cannot convert V2 to V3" ) ,
181+ (
182+ Config :: V3 {
183+ // device_bundle,
184+ // settings,
185+ ..
186+ } ,
187+ ConfigDiscriminants :: V1 ,
188+ ) => {
189+ unimplemented ! ( "convert V3 to V1 (lossy)" ) ;
190+ }
191+ (
192+ Config :: V3 {
193+ device_bundle,
194+ device_derivation_path,
195+ registration_code,
196+ settings,
197+ ..
198+ } ,
199+ ConfigDiscriminants :: V2 ,
200+ ) => Ok ( Config :: V2 {
201+ device_bundle,
202+ derivation_path : device_derivation_path,
203+ registration_code,
204+ settings,
205+ } ) ,
206+ ( cfg @ Config :: V3 { .. } , ConfigDiscriminants :: V3 ) => Ok ( cfg) ,
207+ }
208+ }
149209}
150210
151211// fn generate_keypair(
@@ -182,3 +242,56 @@ pub fn admin_keypair_from(
182242
183243 Ok ( SigningKey :: from_bytes ( & hash) )
184244}
245+
246+ #[ cfg( test) ]
247+ mod tests {
248+ use crate :: { test_utils:: generate_test_hpos_config, Config } ;
249+
250+ #[ tokio:: test]
251+ async fn convert_v3_to_v2 ( ) {
252+ let ( config, _) = generate_test_hpos_config ( ) . await . unwrap ( ) ;
253+
254+ // ensure we start with a v3 config
255+ let v3 = config
256+ . clone ( )
257+ . try_convert ( crate :: config:: ConfigDiscriminants :: V3 )
258+ . unwrap ( ) ;
259+ assert_eq ! ( config, v3) ;
260+
261+ let v2 = config
262+ . clone ( )
263+ . try_convert ( crate :: config:: ConfigDiscriminants :: V2 )
264+ . unwrap ( ) ;
265+
266+ if let Config :: V2 {
267+ device_bundle,
268+ derivation_path,
269+ registration_code,
270+ settings,
271+ } = v2
272+ {
273+ let v2_device_bundle = device_bundle;
274+ let v2_derivation_path = derivation_path;
275+ let v2_registration_code = registration_code;
276+ let v2_settings = settings;
277+
278+ if let Config :: V3 {
279+ device_bundle,
280+ device_derivation_path,
281+ registration_code,
282+ settings,
283+ ..
284+ } = config
285+ {
286+ assert_eq ! ( v2_device_bundle, device_bundle) ;
287+ assert_eq ! ( v2_derivation_path, device_derivation_path) ;
288+ assert_eq ! ( v2_registration_code, registration_code) ;
289+ assert_eq ! ( v2_settings, settings) ;
290+ } else {
291+ panic ! ( "config isn't v3" ) ;
292+ } ;
293+ } else {
294+ panic ! ( "must match v2" ) ;
295+ }
296+ }
297+ }
0 commit comments