2 files changed
+99
-7
smbpndk-cli/src/account/lib.rs
+2
@@ -34,6 +34,7 @@ pub struct SmbAuthorization {
34
pub enum ErrorCode {
35
EmailNotFound = 1000,
36
EmailUnverified = 1001,
37
+ PasswordNotSet = 1003,
38
}
39
40
impl Display for ErrorCode {
@@ -41,6 +42,7 @@ impl Display for ErrorCode {
42
match self {
43
ErrorCode::EmailNotFound => write!(f, "Email not found."),
44
ErrorCode::EmailUnverified => write!(f, "Email not verified."),
45
+ ErrorCode::PasswordNotSet => write!(f, "Password not set."),
46
}
47
}
48
}
smbpndk-cli/src/account/login/process.rs
+97
-7
@@ -76,6 +76,11 @@ async fn process_authorization(auth: SmbAuthorization) -> Result<CommandResult>
76
return create_new_account(auth.user_email, auth.user_info).await
77
}
78
ErrorCode::EmailUnverified => return send_email_verification(auth.user).await,
79
+ ErrorCode::PasswordNotSet => {
80
+ // Only for email and password login
81
+ let error = anyhow!("Password not set.");
82
+ return Err(error);
83
+ }
84
}
85
}
86
@@ -258,7 +263,7 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
263
return Err(error);
264
}
265
}
261
- },
266
+ }
267
StatusCode::NOT_FOUND => {
268
// Account not found and we show signup option
269
Ok(CommandResult {
@@ -269,14 +274,13 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
274
symbol: "✅".to_owned(),
275
msg: "Please signup!".to_owned(),
276
})
272
- },
277
+ }
278
StatusCode::UNPROCESSABLE_ENTITY => {
274
- // Account found but email not verified
275
- println!("✅ Account found but email not verified.");
279
+ // Account found but email not verified / password not set
280
let result: SmbAuthorization = response.json().await?;
277
- // println!("Result: {:#?}", &result);
278
- return send_email_verification(result.user).await;
279
- },
281
+ println!("Result: {:#?}", &result);
282
+ return verify_or_set_password(result).await;
283
+ }
284
_ => {
285
let error = anyhow!("Login failed. Check your username and password.");
286
return Err(error);
@@ -284,6 +288,86 @@ async fn do_process_login(args: LoginArgs) -> Result<CommandResult> {
288
}
289
}
290
291
+async fn verify_or_set_password(result: SmbAuthorization) -> Result<CommandResult> {
292
+ match result.error_code {
293
+ Some(error_code) => {
294
+ debug!("{}", error_code);
295
+ match error_code {
296
+ ErrorCode::EmailUnverified => {
297
+ return send_email_verification(result.user).await
298
+ }
299
+ ErrorCode::PasswordNotSet => {
300
+ return send_reset_password(result.user).await
301
+ }
302
+ _ => {
303
+ let error = anyhow!("Shouldn't be here.");
304
+ return Err(error);
305
+ }
306
+ }
307
+ }
308
+ None => {
309
+ let error = anyhow!("Shouldn't be here.");
310
+ return Err(error);
311
+ }
312
+ }
313
+}
314
+
315
+async fn send_reset_password(user: Option<User>) -> Result<CommandResult> {
316
+ // Return early if user is null
317
+ if let Some(user) = user {
318
+ let confirm = Confirm::with_theme(&ColorfulTheme::default())
319
+ .with_prompt("Do you want to reset your password?")
320
+ .interact()
321
+ .unwrap();
322
+
323
+ // Send verification email if user confirms
324
+ if !confirm {
325
+ let spinner = Spinner::new(
326
+ spinners::Spinners::SimpleDotsScrolling,
327
+ style("Cancel operation.").green().bold().to_string(),
328
+ );
329
+ return Ok(CommandResult {
330
+ spinner,
331
+ symbol: "✅".to_owned(),
332
+ msg: "Doing nothing.".to_owned(),
333
+ });
334
+ }
335
+ resend_reset_password_instruction(user).await
336
+ } else {
337
+ let error = anyhow!("Failed to get user.");
338
+ Err(error)
339
+ }
340
+}
341
+
342
+async fn resend_reset_password_instruction(user: User) -> Result<CommandResult> {
343
+ let spinner = Spinner::new(
344
+ spinners::Spinners::SimpleDotsScrolling,
345
+ style("Sending reset password instruction...")
346
+ .green()
347
+ .bold()
348
+ .to_string(),
349
+ );
350
+ let response = Client::new()
351
+ .post(build_smb_resend_reset_password_instructions_url())
352
+ .body(format!("id={}", user.id))
353
+ .header("Accept", "application/json")
354
+ .header("Content-Type", "application/x-www-form-urlencoded")
355
+ .send()
356
+ .await?;
357
+
358
+ match response.status() {
359
+ reqwest::StatusCode::OK => Ok(CommandResult {
360
+ spinner,
361
+ symbol: "✅".to_owned(),
362
+ msg: "Reset password instruction sent!".to_owned(),
363
+ }),
364
+ _ => {
365
+ let error = anyhow!("Failed to send reset password instruction.");
366
+ Err(error)
367
+ }
368
+ }
369
+}
370
+
371
fn build_smb_login_url() -> String {
372
let mut url_builder = smb_base_url_builder();
373
url_builder.add_route("v1/users/sign_in");
@@ -296,6 +380,12 @@ fn build_smb_resend_email_verification_url() -> String {
380
url_builder.build()
381
}
382
383
+fn build_smb_resend_reset_password_instructions_url() -> String {
384
+ let mut url_builder = smb_base_url_builder();
385
+ url_builder.add_route("v1/resend_reset_password_instructions");
386
+ url_builder.build()
387
+}
388
+
389
pub async fn process_logout() -> Result<CommandResult> {
390
let spinner = Spinner::new(
391
spinners::Spinners::SimpleDotsScrolling,