diff --git a/src/internal/user_api/mod.rs b/src/internal/user_api/mod.rs index 58663879..6cb64369 100644 --- a/src/internal/user_api/mod.rs +++ b/src/internal/user_api/mod.rs @@ -134,6 +134,7 @@ pub struct UserVerifyResult { account_id: UserId, segment_id: usize, user_public_key: PublicKey, + needs_rotation: bool, } impl UserVerifyResult { pub fn user_public_key(&self) -> &PublicKey { @@ -147,6 +148,10 @@ impl UserVerifyResult { pub fn segment_id(&self) -> usize { self.segment_id } + + pub fn needs_rotation(&self) -> bool { + self.needs_rotation + } } #[derive(Debug)] diff --git a/src/internal/user_api/requests.rs b/src/internal/user_api/requests.rs index 04d9678f..3380ce3c 100644 --- a/src/internal/user_api/requests.rs +++ b/src/internal/user_api/requests.rs @@ -35,18 +35,20 @@ impl TryFrom for EncryptedMasterKey { } pub mod user_verify { - use crate::internal::{user_api::UserVerifyResult, TryInto}; + use crate::internal::user_api::UserVerifyResult; + use std::convert::TryInto; use super::*; #[derive(Deserialize, PartialEq, Debug)] #[serde(rename_all = "camelCase")] pub struct UserVerifyResponse { - pub id: String, + pub(crate) id: String, status: usize, - pub segment_id: usize, - pub user_private_key: PrivateKey, - pub user_master_public_key: PublicKey, + pub(crate) segment_id: usize, + pub(crate) user_private_key: PrivateKey, + pub(crate) user_master_public_key: PublicKey, + pub(crate) needs_rotation: bool, } pub fn user_verify( @@ -68,9 +70,54 @@ pub mod user_verify { account_id: body.id.try_into()?, segment_id: body.segment_id, user_public_key: body.user_master_public_key.try_into()?, + needs_rotation: body.needs_rotation, }) } } + + #[cfg(test)] + mod test { + use super::*; + use crate::internal; + use galvanic_assert::matchers::*; + use recrypt::prelude::*; + + #[test] + fn user_verify_resp_to_result() -> Result<(), IronOxideErr> { + let r = recrypt::api::Recrypt::new(); + let (_, r_pub) = r.generate_key_pair()?; + + // private key doesn't go through any validation as we don't return it in the Result + let priv_key: PrivateKey = PrivateKey(vec![1u8; 60]); + let pub_key: PublicKey = r_pub.into(); + + let t_account_id: UserId = UserId::unsafe_from_string("valid_user_id".to_string()); + let t_segment_id: usize = 200; + let t_user_public_key: internal::PublicKey = r_pub.into(); + let t_needs_rotation = true; + + let resp = UserVerifyResponse { + id: t_account_id.id().to_string(), + status: 100, + segment_id: t_segment_id, + user_private_key: priv_key, + user_master_public_key: pub_key, + needs_rotation: t_needs_rotation, + }; + let result: UserVerifyResult = resp.try_into().unwrap(); + + assert_that!( + &result, + has_structure!(UserVerifyResult { + account_id: eq(t_account_id.clone()), + segment_id: eq(t_segment_id), + user_public_key: eq(t_user_public_key.clone()), + needs_rotation: eq(t_needs_rotation) + }) + ); + Ok(()) + } + } } pub mod user_create { diff --git a/tests/user_ops.rs b/tests/user_ops.rs index b0b189a5..727a1ba6 100644 --- a/tests/user_ops.rs +++ b/tests/user_ops.rs @@ -37,6 +37,22 @@ fn user_verify_existing_user() { assert_eq!(2012, verify_resp.segment_id()); } +#[test] +fn user_verify_after_create_with_needs_rotation() -> Result<(), IronOxideErr> { + let account_id: UserId = Uuid::new_v4().to_string().try_into().unwrap(); + IronOxide::user_create( + &gen_jwt(1012, "test-segment", 551, Some(account_id.id())).0, + "foo", + &UserCreateOpts::new(true), + )?; + + let result = + IronOxide::user_verify(&gen_jwt(1012, "test-segment", 551, Some(account_id.id())).0)?; + assert_eq!(true, result.is_some()); + let verify_resp = result.unwrap(); + + Ok(assert!(verify_resp.needs_rotation())) +} #[test] fn user_create_good_with_devices() { let account_id: UserId = Uuid::new_v4().to_string().try_into().unwrap();