forked from jmug/stoatchat
Clean up errors, add /users route.
This commit is contained in:
16
src/auth.rs
16
src/auth.rs
@@ -2,11 +2,13 @@ use rocket::Outcome;
|
|||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
use rocket::request::{self, Request, FromRequest};
|
use rocket::request::{self, Request, FromRequest};
|
||||||
|
|
||||||
use bson::{ bson, doc, ordered::OrderedDocument, oid::ObjectId };
|
use bson::{ bson, doc, ordered::OrderedDocument };
|
||||||
|
use ulid::Ulid;
|
||||||
|
|
||||||
use crate::database;
|
use crate::database;
|
||||||
|
|
||||||
pub struct User(
|
pub struct User(
|
||||||
pub ObjectId,
|
pub Ulid,
|
||||||
pub String,
|
pub String,
|
||||||
pub OrderedDocument,
|
pub OrderedDocument,
|
||||||
);
|
);
|
||||||
@@ -24,20 +26,20 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
|
|||||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||||
let keys: Vec<_> = request.headers().get("x-auth-token").collect();
|
let keys: Vec<_> = request.headers().get("x-auth-token").collect();
|
||||||
match keys.len() {
|
match keys.len() {
|
||||||
0 => Outcome::Failure((Status::BadRequest, AuthError::Missing)),
|
0 => Outcome::Failure((Status::Forbidden, AuthError::Missing)),
|
||||||
1 => {
|
1 => {
|
||||||
let key = keys[0];
|
let key = keys[0];
|
||||||
let col = database::get_db().collection("users");
|
let col = database::get_db().collection("users");
|
||||||
let result = col.find_one(Some( doc! { "auth_token": key } ), None).unwrap();
|
let result = col.find_one(doc! { "access_token": key }, None).unwrap();
|
||||||
|
|
||||||
if let Some(user) = result {
|
if let Some(user) = result {
|
||||||
Outcome::Success(User(
|
Outcome::Success(User(
|
||||||
user.get_object_id("_id").unwrap().clone(),
|
Ulid::from_string(user.get_str("_id").unwrap()).unwrap(),
|
||||||
user.get_str("username").unwrap().to_owned(),
|
user.get_str("username").unwrap().to_string(),
|
||||||
user
|
user
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Outcome::Failure((Status::BadRequest, AuthError::Invalid))
|
Outcome::Failure((Status::Forbidden, AuthError::Invalid))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
|
_ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
|
||||||
|
|||||||
@@ -18,13 +18,6 @@ fn gen_token(l: usize) -> String {
|
|||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
pub fn root(user: User) -> String {
|
|
||||||
let User ( id, username, _doc ) = user;
|
|
||||||
|
|
||||||
format!("hello, {}! [id: {}]", username, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Create {
|
pub struct Create {
|
||||||
username: String,
|
username: String,
|
||||||
@@ -72,7 +65,7 @@ pub fn create(info: Json<Create>) -> JsonValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(hashed) = hash(info.password.clone(), 10) {
|
if let Ok(hashed) = hash(info.password.clone(), 10) {
|
||||||
let access_token = gen_token(64);
|
let access_token = gen_token(92);
|
||||||
let code = gen_token(48);
|
let code = gen_token(48);
|
||||||
|
|
||||||
match col.insert_one(doc! {
|
match col.insert_one(doc! {
|
||||||
@@ -120,8 +113,8 @@ pub fn verify_email(code: String) -> JsonValue {
|
|||||||
|
|
||||||
if let Some(u) =
|
if let Some(u) =
|
||||||
col.find_one(doc! { "email_verification.code": code.clone() }, None).expect("Failed user lookup") {
|
col.find_one(doc! { "email_verification.code": code.clone() }, None).expect("Failed user lookup") {
|
||||||
let ev = u.get_document("email_verification").expect("Missing email_verification on user object!");
|
let ev = u.get_document("email_verification").expect("DOC[email_verification]");
|
||||||
let expiry = ev.get_utc_datetime("expiry").expect("Missing expiry date on email_verification!");
|
let expiry = ev.get_utc_datetime("expiry").expect("DOC[expiry]");
|
||||||
|
|
||||||
if Utc::now() > *expiry {
|
if Utc::now() > *expiry {
|
||||||
json!({
|
json!({
|
||||||
@@ -129,7 +122,7 @@ pub fn verify_email(code: String) -> JsonValue {
|
|||||||
"error": "Token has expired!",
|
"error": "Token has expired!",
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let target = ev.get_str("target").expect("Missing target email on email_verification!");
|
let target = ev.get_str("target").expect("DOC[target]");
|
||||||
col.update_one(
|
col.update_one(
|
||||||
doc! { "_id": u.get_str("_id").expect("Failed to retrieve user id.") },
|
doc! { "_id": u.get_str("_id").expect("Failed to retrieve user id.") },
|
||||||
doc! {
|
doc! {
|
||||||
@@ -179,22 +172,35 @@ pub fn resend_email(info: Json<Resend>) -> JsonValue {
|
|||||||
|
|
||||||
if let Some(u) =
|
if let Some(u) =
|
||||||
col.find_one(doc! { "email_verification.target": info.email.clone() }, None).expect("Failed user lookup") {
|
col.find_one(doc! { "email_verification.target": info.email.clone() }, None).expect("Failed user lookup") {
|
||||||
let ev = u.get_document("email_verification").expect("Missing email_verification on user object!");
|
let ev = u.get_document("email_verification").expect("DOC[email_verification]");
|
||||||
let rate_limit = ev.get_utc_datetime("rate_limit").expect("Missing rate_limit on email_verification!");
|
let expiry = ev.get_utc_datetime("expiry").expect("DOC[expiry]");
|
||||||
|
let rate_limit = ev.get_utc_datetime("rate_limit").expect("DOC[rate_limit]");
|
||||||
|
|
||||||
if Utc::now() < *rate_limit {
|
if Utc::now() < *rate_limit {
|
||||||
json!({
|
json!({
|
||||||
"success": false,
|
"success": false,
|
||||||
"error": "Hit rate limit! Please try again in a minute or so."
|
"error": "Hit rate limit! Please try again in a minute or so.",
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
let mut new_expiry = UtcDatetime(Utc::now() + chrono::Duration::days(1));
|
||||||
|
if info.email.clone() != u.get_str("email").expect("DOC[email]") {
|
||||||
|
if Utc::now() > *expiry {
|
||||||
|
return json!({
|
||||||
|
"success": "false",
|
||||||
|
"error": "For security reasons, please login and change your email again.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
new_expiry = UtcDatetime(*expiry);
|
||||||
|
}
|
||||||
|
|
||||||
let code = gen_token(48);
|
let code = gen_token(48);
|
||||||
col.update_one(
|
col.update_one(
|
||||||
doc! { "_id": u.get_str("_id").expect("Failed to retrieve user id.") },
|
doc! { "_id": u.get_str("_id").expect("Failed to retrieve user id.") },
|
||||||
doc! {
|
doc! {
|
||||||
"$set": {
|
"$set": {
|
||||||
"email_verification.code": code.clone(),
|
"email_verification.code": code.clone(),
|
||||||
"email_verification.expiry": UtcDatetime(Utc::now() + chrono::Duration::days(1)),
|
"email_verification.expiry": new_expiry,
|
||||||
"email_verification.rate_limit": UtcDatetime(Utc::now() + chrono::Duration::minutes(1)),
|
"email_verification.rate_limit": UtcDatetime(Utc::now() + chrono::Duration::minutes(1)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -210,7 +216,7 @@ pub fn resend_email(info: Json<Resend>) -> JsonValue {
|
|||||||
}),
|
}),
|
||||||
false => json!({
|
false => json!({
|
||||||
"success": false,
|
"success": false,
|
||||||
"error": "Failed to send email! Likely an issue with the backend API."
|
"error": "Failed to send email! Likely an issue with the backend API.",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,16 +244,16 @@ pub fn login(info: Json<Login>) -> JsonValue {
|
|||||||
|
|
||||||
if let Some(u) =
|
if let Some(u) =
|
||||||
col.find_one(doc! { "email": info.email.clone() }, None).expect("Failed user lookup") {
|
col.find_one(doc! { "email": info.email.clone() }, None).expect("Failed user lookup") {
|
||||||
match verify(info.password.clone(), u.get_str("password").expect("Missing password in user object!"))
|
match verify(info.password.clone(), u.get_str("password").expect("DOC[password]"))
|
||||||
.expect("Failed to check hash of password.") {
|
.expect("Failed to check hash of password.") {
|
||||||
true => {
|
true => {
|
||||||
let token =
|
let token =
|
||||||
match u.get_str("access_token") {
|
match u.get_str("access_token") {
|
||||||
Ok(t) => t.to_string(),
|
Ok(t) => t.to_string(),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let token = gen_token(64);
|
let token = gen_token(92);
|
||||||
col.update_one(
|
col.update_one(
|
||||||
doc! { "_id": u.get_str("_id").expect("Missing id in user object!") },
|
doc! { "_id": u.get_str("_id").expect("DOC[id]") },
|
||||||
doc! { "$set": { "access_token": token.clone() } },
|
doc! { "$set": { "access_token": token.clone() } },
|
||||||
None
|
None
|
||||||
).expect("Failed to update user object");
|
).expect("Failed to update user object");
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
use rocket::Rocket;
|
use rocket::Rocket;
|
||||||
|
|
||||||
mod account;
|
mod account;
|
||||||
|
mod user;
|
||||||
|
|
||||||
pub fn mount(rocket: Rocket) -> Rocket {
|
pub fn mount(rocket: Rocket) -> Rocket {
|
||||||
rocket
|
rocket
|
||||||
.mount("/api/account", routes![ account::root, account::create, account::verify_email, account::resend_email, account::login ])
|
.mount("/api/account", routes![ account::create, account::verify_email, account::resend_email, account::login ])
|
||||||
|
.mount("/api/users", routes![ user::me ])
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/routes/user.rs
Normal file
18
src/routes/user.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use crate::auth::User;
|
||||||
|
|
||||||
|
use rocket_contrib::json::{ JsonValue };
|
||||||
|
use bson::{ doc };
|
||||||
|
|
||||||
|
#[get("/@me")]
|
||||||
|
pub fn me(user: User) -> JsonValue {
|
||||||
|
let User ( id, username, doc ) = user;
|
||||||
|
|
||||||
|
json!({
|
||||||
|
"id": id.to_string(),
|
||||||
|
"username": username,
|
||||||
|
"email": doc.get_str("email").expect("Missing email in user object!"),
|
||||||
|
"verified": doc.get_document("email_verification").expect("DOC[email_verification]")
|
||||||
|
.get_bool("verified").expect("DOC[verified]"),
|
||||||
|
"created_timestamp": id.datetime().timestamp(),
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user