Skip to content
Snippets Groups Projects
Verified Commit 0021ada6 authored by insert's avatar insert
Browse files

Clean up errors, add /users route.

parent c831da6a
Branches
Tags
No related merge requests found
...@@ -2,11 +2,13 @@ use rocket::Outcome; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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");
......
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 ])
} }
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(),
})
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment