1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
use std::sync::Arc;
use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize};
use crate::{
api::{
auth::{self, WithFxaLogin},
Empty, EMPTY,
},
auth::Authenticated,
db::{Db, DbConn},
mailer::Mailer,
push::PushClient,
types::UserID,
utils::DeferAction,
};
// MISSING get /recovery_emails
// MISSING post /recovery_email
// MISSING post /recovery_email/destroy
// MISSING post /recovery_email/resend_code
// MISSING post /recovery_email/set_primary
// MISSING post /emails/reminders/cad
// MISSING post /recovery_email/secondary/resend_code
// MISSING post /recovery_email/secondary/verify_code
#[derive(Debug, Serialize)]
#[allow(non_snake_case)]
pub(crate) struct StatusResp {
email: String,
verified: bool,
sessionVerified: bool,
emailVerified: bool,
}
// MISSING arg: reason
#[get("/recovery_email/status")]
pub(crate) async fn status(
db: &DbConn,
req: Authenticated<(), WithFxaLogin>,
) -> auth::Result<StatusResp> {
let user = db.get_user_by_id(&req.context.uid).await?;
Ok(Json(StatusResp {
email: user.email,
verified: user.verified,
sessionVerified: req.context.verified,
emailVerified: user.verified,
}))
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub(crate) struct VerifyReq {
uid: UserID,
code: String,
// MISSING service
// MISSING reminder
// MISSING type
// MISSING style
// MISSING marketingOptIn
// MISSING newsletters
}
#[post("/recovery_email/verify_code", data = "<req>")]
pub(crate) async fn verify_code(
db: &DbConn,
db_pool: &Db,
defer: &DeferAction,
pc: &State<Arc<PushClient>>,
req: Json<VerifyReq>,
) -> auth::Result<Empty> {
let code = match db.try_use_verify_code(&req.uid, &req.code).await? {
Some(code) => code,
None => return Err(auth::Error::InvalidVerificationCode),
};
db.set_user_verified(&req.uid).await?;
if let Some(sid) = code.session_id {
db.set_session_verified(&sid).await?;
}
match db.get_devices(&req.uid).await {
Ok(devs) => defer.spawn_after_success("api::auth/recovery_email/verify_code(post)", {
let (pc, db) = (Arc::clone(pc), db_pool.clone());
async move {
let db = db.begin().await?;
pc.account_verified(&db, &devs).await;
db.commit().await?;
Ok(())
}
}),
Err(e) => warn!("account_verified push failed: {e}"),
}
Ok(EMPTY)
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub(crate) struct ResendReq {
// MISSING email
// MISSING service
// MISSING redirectTo
// MISSING resume
// MISSING style
// MISSING type
}
// MISSING arg: service
// MISSING arg: type
#[post("/recovery_email/resend_code", data = "<req>")]
pub(crate) async fn resend_code(
db: &DbConn,
mailer: &State<Arc<Mailer>>,
req: Authenticated<ResendReq, WithFxaLogin>,
) -> auth::Result<Empty> {
let (email, code) = match db.get_verify_code(&req.context.uid).await {
Ok(v) => v,
Err(_) => return Err(auth::Error::InvalidVerificationCode),
};
// NOTE we send the email in this context rather than a spawn to signal
// send errors to the client.
mailer.send_account_verify(&req.context.uid, &email, &code.code).await.map_err(|e| {
error!("failed to send email: {e}");
auth::Error::EmailFailed
})?;
Ok(EMPTY)
}
|