1- use crate :: anchor_management:: add_device;
21use crate :: authz_utils:: IdentityUpdateError ;
3- use crate :: state:: RegistrationState :: { DeviceRegistrationModeActive , DeviceTentativelyAdded } ;
2+ use crate :: state:: RegistrationState :: {
3+ DeviceRegistrationModeActive , DeviceTentativelyAdded , SessionTentativelyAdded ,
4+ SessionTentativelyConfirmed ,
5+ } ;
46use crate :: state:: TentativeDeviceRegistration ;
5- use crate :: storage:: anchor:: Anchor ;
67use crate :: { secs_to_nanos, state} ;
78use candid:: { CandidType , Principal } ;
89use ic_cdk:: api:: time;
910use ic_cdk:: { call, trap} ;
10- use internet_identity_interface:: archive:: types:: Operation ;
1111use internet_identity_interface:: internet_identity:: types:: * ;
1212use std:: collections:: { hash_map, HashMap } ;
1313use TentativeDeviceRegistrationError :: { AnotherDeviceTentativelyAdded , DeviceRegistrationModeOff } ;
@@ -77,7 +77,7 @@ pub fn exit_device_registration_mode(anchor_number: AnchorNumber) {
7777}
7878
7979pub struct TentativeRegistrationInfo {
80- pub verification_code : DeviceVerificationCode ,
80+ pub verification_code : DeviceConfirmationCode ,
8181 pub device_registration_timeout : Timestamp ,
8282}
8383
@@ -96,35 +96,42 @@ impl From<IdentityUpdateError> for TentativeDeviceRegistrationError {
9696
9797pub async fn add_tentative_device (
9898 anchor_number : AnchorNumber ,
99- device_data : DeviceData ,
99+ tentative_device : DeviceData ,
100100) -> Result < TentativeRegistrationInfo , TentativeDeviceRegistrationError > {
101- let verification_code = new_verification_code ( ) . await ;
101+ let confirmation_code = new_confirmation_code ( ) . await ;
102102 let now = time ( ) ;
103103
104104 state:: tentative_device_registrations_mut ( |registrations| {
105105 state:: lookup_tentative_device_registration_mut ( |lookup| {
106106 prune_expired_tentative_device_registrations ( registrations, lookup) ;
107107
108- match registrations. get_mut ( & anchor_number) {
109- None => Err ( DeviceRegistrationModeOff ) ,
110- Some ( TentativeDeviceRegistration { expiration, .. } ) if * expiration <= now => {
108+ // Get registration else throw error
109+ let registration = registrations
110+ . get_mut ( & anchor_number)
111+ . ok_or ( DeviceRegistrationModeOff ) ?;
112+
113+ match registration {
114+ // Make sure registration isn't expired
115+ TentativeDeviceRegistration { expiration, .. } if * expiration <= now => {
111116 Err ( DeviceRegistrationModeOff )
112117 }
113- Some ( TentativeDeviceRegistration {
114- state : DeviceTentativelyAdded { .. } ,
118+ // Add tentative session if registration mode is active
119+ TentativeDeviceRegistration {
120+ state : DeviceRegistrationModeActive ,
115121 ..
116- } ) => Err ( AnotherDeviceTentativelyAdded ) ,
117- Some ( registration) => {
122+ } => {
118123 registration. state = DeviceTentativelyAdded {
119- tentative_device : device_data ,
124+ tentative_device,
120125 failed_attempts : 0 ,
121- verification_code : verification_code . clone ( ) ,
126+ confirmation_code : confirmation_code . clone ( ) ,
122127 } ;
123128 Ok ( TentativeRegistrationInfo {
124129 device_registration_timeout : registration. expiration ,
125- verification_code,
130+ verification_code : confirmation_code ,
126131 } )
127132 }
133+ // Else return error
134+ _ => Err ( AnotherDeviceTentativelyAdded ) ,
128135 }
129136 } )
130137 } )
@@ -135,82 +142,80 @@ pub enum VerifyTentativeDeviceError {
135142 WrongCode { retries_left : u8 } ,
136143 DeviceRegistrationModeOff ,
137144 NoDeviceToVerify ,
138- IdentityUpdateError ( IdentityUpdateError ) ,
139- }
140-
141- impl From < IdentityUpdateError > for VerifyTentativeDeviceError {
142- fn from ( err : IdentityUpdateError ) -> Self {
143- VerifyTentativeDeviceError :: IdentityUpdateError ( err)
144- }
145- }
146-
147- /// Verifies the tentative device using the submitted `user_verification_code` and returns
148- /// a result of [VerifyTentativeDeviceResponse]. [VerifyTentativeDeviceResponse] is used both as
149- /// a success and an error type because it corresponds to the candid variant unifying success and
150- /// error cases. See `authenticated_anchor_operation` for more details on how the [Result] is handled.
151- pub fn verify_tentative_device (
152- anchor : & mut Anchor ,
153- anchor_number : AnchorNumber ,
154- user_verification_code : DeviceVerificationCode ,
155- ) -> Result < ( ( ) , Operation ) , VerifyTentativeDeviceError > {
156- match get_verified_device ( anchor_number, user_verification_code) {
157- Ok ( device) => {
158- let operation = add_device ( anchor, device) ;
159- Ok ( ( ( ) , operation) )
160- }
161- Err ( err) => Err ( err) ,
162- }
163145}
164146
165- /// Checks the device verification code for a tentative device.
166- /// If valid, returns the device to be added and exits device registration mode
167- /// If invalid, returns the appropriate error to send to the client and increases failed attempts. Exits device registration mode if there are no retries left.
168- fn get_verified_device (
147+ /// Confirm the tentative device or session using the submitted `user_confirmation_code`.
148+ ///
149+ /// # Returns
150+ /// [`Some(DeviceData)`] if a device (or [`None`] if a session) has been confirmed
151+ ///
152+ /// # Errors
153+ /// Returns an error if either there's no tentative device (or session) or the code is incorrect.
154+ pub fn confirm_tentative_device_or_session (
169155 anchor_number : AnchorNumber ,
170- user_verification_code : DeviceVerificationCode ,
171- ) -> Result < DeviceData , VerifyTentativeDeviceError > {
156+ user_confirmation_code : DeviceConfirmationCode ,
157+ ) -> Result < Option < DeviceData > , VerifyTentativeDeviceError > {
172158 state:: tentative_device_registrations_mut ( |registrations| {
173159 state:: lookup_tentative_device_registration_mut ( |lookup| {
174160 prune_expired_tentative_device_registrations ( registrations, lookup) ;
175161
176- // Check if the registration exists
177- if !registrations. contains_key ( & anchor_number) {
178- return Err ( VerifyTentativeDeviceError :: DeviceRegistrationModeOff ) ;
179- }
162+ // Get registration else throw error
163+ let registration = registrations
164+ . get_mut ( & anchor_number)
165+ . ok_or ( VerifyTentativeDeviceError :: DeviceRegistrationModeOff ) ?;
166+
167+ let ( should_remove, response) = match & mut registration. state {
168+ DeviceRegistrationModeActive | SessionTentativelyConfirmed { .. } => {
169+ ( false , Err ( VerifyTentativeDeviceError :: NoDeviceToVerify ) )
170+ }
171+ DeviceTentativelyAdded {
172+ failed_attempts,
173+ confirmation_code,
174+ tentative_device,
175+ } => {
176+ if user_confirmation_code == * confirmation_code {
177+ // Verification successful - return device to be added and remove the registration
178+ ( true , Ok ( Some ( tentative_device. clone ( ) ) ) )
179+ } else {
180+ // Increment failed attempts counter
181+ * failed_attempts += 1 ;
180182
181- // Check the state and prepare the response without keeping a mutable reference
182- let ( should_remove, response) =
183- match & mut registrations. get_mut ( & anchor_number) . unwrap ( ) . state {
184- DeviceRegistrationModeActive => {
185- ( false , Err ( VerifyTentativeDeviceError :: NoDeviceToVerify ) )
183+ // Remove registration if max attempts reached
184+ (
185+ * failed_attempts >= MAX_DEVICE_REGISTRATION_ATTEMPTS ,
186+ Err ( VerifyTentativeDeviceError :: WrongCode {
187+ retries_left : ( MAX_DEVICE_REGISTRATION_ATTEMPTS - * failed_attempts) ,
188+ } ) ,
189+ )
186190 }
187- DeviceTentativelyAdded {
188- failed_attempts,
189- verification_code,
190- tentative_device,
191- } => {
192- if user_verification_code == * verification_code {
193- // Verification successful - we'll remove the registration
194- ( true , Ok ( tentative_device. clone ( ) ) )
195- } else {
196- // Increment failed attempts counter
197- * failed_attempts += 1 ;
191+ }
192+ SessionTentativelyAdded {
193+ failed_attempts,
194+ confirmation_code,
195+ tentative_session,
196+ } => {
197+ if user_confirmation_code == * confirmation_code {
198+ let principal = * tentative_session;
198199
199- // Check if max attempts reached
200- let should_remove =
201- * failed_attempts >= MAX_DEVICE_REGISTRATION_ATTEMPTS ;
200+ // Verification successful - we'll confirm the session and keep the registration
201+ registration. state = SessionTentativelyConfirmed {
202+ tentative_session : principal,
203+ } ;
204+ ( false , Ok ( None ) )
205+ } else {
206+ // Increment failed attempts counter
207+ * failed_attempts += 1 ;
202208
203- (
204- should_remove,
205- Err ( VerifyTentativeDeviceError :: WrongCode {
206- retries_left : ( MAX_DEVICE_REGISTRATION_ATTEMPTS
207- - * failed_attempts) ,
208- } ) ,
209- )
210- }
209+ // Remove registration if max attempts reached
210+ (
211+ * failed_attempts >= MAX_DEVICE_REGISTRATION_ATTEMPTS ,
212+ Err ( VerifyTentativeDeviceError :: WrongCode {
213+ retries_left : ( MAX_DEVICE_REGISTRATION_ATTEMPTS - * failed_attempts) ,
214+ } ) ,
215+ )
211216 }
212- } ;
213-
217+ }
218+ } ;
214219 // Now handle removal if needed, after we're done with the mutable borrow
215220 if should_remove {
216221 if let Some ( TentativeDeviceRegistration {
@@ -221,14 +226,13 @@ fn get_verified_device(
221226 lookup. remove ( & reg_id) ;
222227 }
223228 }
224-
225229 response
226230 } )
227231 } )
228232}
229233
230- /// Return a decimal representation of a random `u32` to be used as verification code
231- async fn new_verification_code ( ) -> DeviceVerificationCode {
234+ /// Return a decimal representation of a random `u32` to be used as confirmation code
235+ async fn new_confirmation_code ( ) -> DeviceConfirmationCode {
232236 let res: Vec < u8 > = match call ( Principal :: management_canister ( ) , "raw_rand" , ( ) ) . await {
233237 Ok ( ( res, ) ) => res,
234238 Err ( ( _, err) ) => trap ( & format ! ( "failed to get randomness: {err}" ) ) ,
0 commit comments