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
|
use std::sync::Arc;
use rocket::serde::json::Json;
use rocket::State;
use serde::{Deserialize, Serialize};
use crate::api::auth::WithFxaLogin;
use crate::api::{auth, Empty, EMPTY};
use crate::auth::Authenticated;
use crate::db::Db;
use crate::db::DbConn;
use crate::mailer::Mailer;
use crate::push::PushClient;
use crate::types::{SessionID, UserID};
use crate::utils::DeferAction;
// MISSING post /session/duplicate
// MISSING post /session/reauth
// MISSING post /session/verify/send_push
#[derive(Debug, Serialize)]
pub(crate) struct StatusResp {
state: &'static str, // what does this *do*?
uid: UserID,
}
#[get("/session/status")]
pub(crate) async fn status(req: Authenticated<(), WithFxaLogin>) -> auth::Result<StatusResp> {
Ok(Json(StatusResp { state: "", uid: req.context.uid }))
}
#[post("/session/resend_code", data = "<req>")]
pub(crate) async fn resend_code(
db: &DbConn,
mailer: &State<Arc<Mailer>>,
req: Authenticated<Empty, WithFxaLogin>,
) -> auth::Result<Empty> {
let code = match req.context.verify_code {
Some(code) => code,
_ => return Err(auth::Error::InvalidVerificationCode),
};
let user = db.get_user_by_id(&req.context.uid).await?;
mailer.send_session_verify(&user.email, &code).await.map_err(|e| {
error!("failed to send email: {e}");
auth::Error::EmailFailed
})?;
Ok(EMPTY)
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub(crate) struct VerifyReq {
code: String,
// MISSING service
// MISSING scopes
// MISSING marketingOptIn
// MISSING newsletters
}
#[post("/session/verify_code", data = "<req>")]
pub(crate) async fn verify_code(
db: &DbConn,
req: Authenticated<VerifyReq, WithFxaLogin>,
) -> auth::Result<Empty> {
if req.context.verify_code.as_ref() != Some(&req.body.code) {
return Err(auth::Error::InvalidVerificationCode);
}
db.set_session_verified(&req.session).await?;
Ok(EMPTY)
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub(crate) struct DestroyReq {
custom_session_id: Option<SessionID>,
}
#[post("/session/destroy", data = "<data>")]
pub(crate) async fn destroy(
db: &DbConn,
db_pool: &Db,
defer: &DeferAction,
client: &State<Arc<PushClient>>,
data: Authenticated<DestroyReq, WithFxaLogin>,
) -> auth::Result<Empty> {
if data.body.custom_session_id.is_some() && !data.context.verified {
return Err(auth::Error::UnverifiedSession);
}
let id = data.body.custom_session_id.as_ref().unwrap_or(&data.session);
db.delete_session(&data.context.uid, id).await.map_err(|_| auth::Error::UnknownDevice)?;
if let Some(id) = data.context.device_id {
match db.get_devices(&data.context.uid).await {
Err(e) => warn!("device_disconnected push failed: {e}"),
Ok(devs) => defer.spawn_after_success("api::auth/session/destroy(post)", {
let (client, db) = (Arc::clone(client), db_pool.clone());
async move {
let db = db.begin().await?;
client.device_disconnected(&db, &devs, &id).await;
db.commit().await?;
Ok(())
}
}),
};
}
Ok(EMPTY)
}
|