2024-06-07 01:24:42 +00:00
|
|
|
pub mod db;
|
|
|
|
|
|
2024-06-10 17:43:24 +00:00
|
|
|
use anyhow::Result;
|
2024-06-06 18:21:12 +00:00
|
|
|
use axum::{
|
2024-06-19 22:01:01 +00:00
|
|
|
extract::Path,
|
2024-06-10 17:43:24 +00:00
|
|
|
body::Body, response::{IntoResponse, Response}, routing::{get, post}, Json, Router
|
2024-06-06 18:21:12 +00:00
|
|
|
};
|
2024-06-19 22:01:01 +00:00
|
|
|
use futures::stream::{self, StreamExt, TryStreamExt};
|
2024-06-10 21:05:03 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2024-06-08 15:36:06 +00:00
|
|
|
use crate::ApiResult;
|
2024-06-10 21:05:03 +00:00
|
|
|
use db::{get_database, get_users, LogEntry, Mole, User};
|
2024-06-19 22:01:01 +00:00
|
|
|
use http::StatusCode;
|
2024-06-10 21:05:03 +00:00
|
|
|
use mongodb::bson::{doc, oid::ObjectId, to_document, Document};
|
2024-06-10 17:43:24 +00:00
|
|
|
use serde_json::json;
|
2024-06-06 19:43:32 +00:00
|
|
|
|
2024-06-06 18:21:12 +00:00
|
|
|
pub fn router() -> Router {
|
|
|
|
|
Router::new()
|
2024-06-19 22:01:01 +00:00
|
|
|
.route("/sign-in/:username",
|
|
|
|
|
get(get_sign_in))
|
2024-06-06 18:21:12 +00:00
|
|
|
.route("/sign-in",
|
2024-06-19 22:01:01 +00:00
|
|
|
post(post_sign_in)
|
2024-06-06 18:21:12 +00:00
|
|
|
)
|
2024-06-07 21:29:49 +00:00
|
|
|
.route("/sign-up",
|
|
|
|
|
post(post_sign_up))
|
2024-06-19 22:01:01 +00:00
|
|
|
.route("/sign-out/:api",
|
|
|
|
|
get(get_sign_out))
|
|
|
|
|
.route("/backup/:api",
|
2024-06-06 18:21:12 +00:00
|
|
|
post(post_backup)
|
|
|
|
|
)
|
2024-06-19 22:01:01 +00:00
|
|
|
.route("/restore/:api",
|
2024-06-06 18:21:12 +00:00
|
|
|
get(get_restore)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-10 17:43:24 +00:00
|
|
|
pub async fn auth(api: &str) -> Result<Option<User>> {
|
|
|
|
|
let db = get_users().await?;
|
|
|
|
|
|
|
|
|
|
let query = doc! {
|
|
|
|
|
"$expr": { "$eq": ["$_auth._api", ObjectId::parse_str(api)?] }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(db.find_one(query, None).await?)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-10 21:05:03 +00:00
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
|
struct BackupData {
|
|
|
|
|
moles: Vec<Mole>,
|
|
|
|
|
logs: Vec<LogEntry>,
|
|
|
|
|
}
|
2024-06-10 17:43:24 +00:00
|
|
|
|
2024-06-19 22:01:01 +00:00
|
|
|
async fn get_sign_in(Path(username): Path<String>) -> ApiResult {
|
2024-06-07 15:37:00 +00:00
|
|
|
let db = get_users().await?;
|
2024-06-07 21:29:49 +00:00
|
|
|
let query = doc! {
|
2024-06-19 22:01:01 +00:00
|
|
|
"$expr": { "$eq": ["$username", username] }
|
2024-06-07 21:29:49 +00:00
|
|
|
};
|
2024-06-07 15:37:00 +00:00
|
|
|
|
|
|
|
|
match db.find_one(query, None).await? {
|
2024-06-07 21:29:49 +00:00
|
|
|
Some(user) => {
|
2024-06-07 17:59:35 +00:00
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::CREATED)
|
2024-06-10 17:43:24 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_salt": user.auth.unwrap().salt.unwrap()
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 15:37:00 +00:00
|
|
|
},
|
|
|
|
|
None => {
|
2024-06-07 17:59:35 +00:00
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::NOT_FOUND)
|
2024-06-19 22:01:01 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_error": "User does not exist"
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 15:37:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-07 14:30:16 +00:00
|
|
|
|
2024-06-10 17:43:24 +00:00
|
|
|
async fn post_sign_in(Json(body): Json<User>) -> ApiResult {
|
2024-06-07 15:37:00 +00:00
|
|
|
let db = get_users().await?;
|
2024-06-07 21:29:49 +00:00
|
|
|
let api = ObjectId::new();
|
|
|
|
|
let query = doc! {
|
|
|
|
|
"$expr": {
|
|
|
|
|
"$and": [
|
2024-06-19 22:01:01 +00:00
|
|
|
{ "$eq": ["$username", body.username] },
|
|
|
|
|
{ "$eq": ["$_auth._hash", body.auth.unwrap_or_default().hash] }
|
2024-06-07 21:29:49 +00:00
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
let update = doc! {
|
|
|
|
|
"$set": {
|
|
|
|
|
"_auth._api": api
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-06-07 15:37:00 +00:00
|
|
|
|
2024-06-10 21:05:03 +00:00
|
|
|
match db.count_documents(query.clone(), None).await? {
|
|
|
|
|
count if count != 0 => {
|
2024-06-07 21:29:49 +00:00
|
|
|
db.update_one(query, update, None).await?;
|
2024-06-07 17:59:35 +00:00
|
|
|
|
|
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::OK)
|
2024-06-10 17:43:24 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_api_key": api.to_string()
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 14:30:16 +00:00
|
|
|
},
|
2024-06-10 21:05:03 +00:00
|
|
|
_ => {
|
2024-06-07 17:59:35 +00:00
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::UNAUTHORIZED)
|
2024-06-19 22:01:01 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_error": "Username or password is incorrect"
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 17:59:35 +00:00
|
|
|
},
|
|
|
|
|
}
|
2024-06-07 14:30:16 +00:00
|
|
|
}
|
2024-06-06 18:21:12 +00:00
|
|
|
|
2024-06-10 17:43:24 +00:00
|
|
|
async fn post_sign_up(Json(body): Json<User>) -> ApiResult {
|
2024-06-07 15:37:00 +00:00
|
|
|
let db = get_users().await?;
|
2024-06-07 21:29:49 +00:00
|
|
|
let query = doc! {
|
2024-06-19 22:01:01 +00:00
|
|
|
"$expr": { "$eq": ["$username", &body.username] }
|
2024-06-07 21:29:49 +00:00
|
|
|
};
|
2024-06-07 14:30:16 +00:00
|
|
|
|
2024-06-10 21:05:03 +00:00
|
|
|
match db.count_documents(query, None).await? {
|
|
|
|
|
count if count != 0 => {
|
2024-06-07 17:59:35 +00:00
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::NOT_ACCEPTABLE)
|
2024-06-19 22:01:01 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_error": "Username is already taken"
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 14:30:16 +00:00
|
|
|
},
|
2024-06-10 21:05:03 +00:00
|
|
|
_ => {
|
2024-06-07 17:59:35 +00:00
|
|
|
db.insert_one(body, None).await?;
|
2024-06-07 21:29:49 +00:00
|
|
|
|
2024-06-07 17:59:35 +00:00
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::CREATED)
|
2024-06-19 22:01:01 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_success": "Account created successfully"
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 14:30:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-06 18:21:12 +00:00
|
|
|
|
2024-06-07 01:24:42 +00:00
|
|
|
|
2024-06-19 22:01:01 +00:00
|
|
|
async fn get_sign_out(Path(api): Path<String>) -> ApiResult {
|
2024-06-07 21:29:49 +00:00
|
|
|
let db = get_users().await?;
|
|
|
|
|
|
|
|
|
|
let query = doc! {
|
2024-06-19 22:01:01 +00:00
|
|
|
"$expr": { "$eq": ["$_auth._api", ObjectId::parse_str(&api)?] }
|
2024-06-07 21:29:49 +00:00
|
|
|
};
|
|
|
|
|
let update = doc! {
|
|
|
|
|
"$unset": {
|
|
|
|
|
"_auth._api": ObjectId::new()
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-06-07 17:59:35 +00:00
|
|
|
|
2024-06-19 22:01:01 +00:00
|
|
|
match auth(&api).await? {
|
2024-06-07 21:29:49 +00:00
|
|
|
Some(_user) => {
|
|
|
|
|
db.update_one(query, update, None).await?;
|
2024-06-07 17:59:35 +00:00
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::OK)
|
2024-06-19 22:01:01 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_success": "Sign out successful"
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 17:59:35 +00:00
|
|
|
},
|
2024-06-07 21:29:49 +00:00
|
|
|
None => {
|
2024-06-07 17:59:35 +00:00
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::NOT_ACCEPTABLE)
|
2024-06-19 22:01:01 +00:00
|
|
|
.body(Json(json!({
|
|
|
|
|
"_error": "User does not exist"
|
|
|
|
|
})).into_response().into_body())?)
|
2024-06-07 14:30:16 +00:00
|
|
|
},
|
|
|
|
|
}
|
2024-06-07 01:24:42 +00:00
|
|
|
}
|
2024-06-19 22:01:01 +00:00
|
|
|
async fn get_restore(Path(api): Path<String>) -> ApiResult {
|
2024-06-11 17:26:50 +00:00
|
|
|
let db = &get_database().await?;
|
|
|
|
|
|
2024-06-19 22:01:01 +00:00
|
|
|
match auth(&api).await? {
|
2024-06-11 17:26:50 +00:00
|
|
|
Some(user) => {
|
|
|
|
|
let moles: Vec<Mole> = db.collection::<Mole>("moles")
|
|
|
|
|
.find(doc! { "_user_id": user.id }, None).await?.try_collect().await?;
|
|
|
|
|
|
|
|
|
|
let logs: Vec<LogEntry> = stream::iter(&moles)
|
|
|
|
|
.then(|mole| async move {
|
|
|
|
|
db.collection::<LogEntry>("logs")
|
|
|
|
|
.find(doc! { "_mole_id": mole.id}, None)
|
|
|
|
|
.await.unwrap()
|
|
|
|
|
.try_collect()
|
|
|
|
|
.await.unwrap_or_else(|_| vec![])
|
|
|
|
|
})
|
|
|
|
|
.flat_map(stream::iter).collect().await;
|
|
|
|
|
|
|
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::OK)
|
|
|
|
|
.body(Json(json!({
|
|
|
|
|
"_moles": moles,
|
|
|
|
|
"_logs": logs
|
|
|
|
|
})).into_response().into_body()).unwrap())
|
|
|
|
|
},
|
|
|
|
|
None => Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::UNAUTHORIZED)
|
|
|
|
|
.body(Body::from("API Key is incorrect"))?),
|
|
|
|
|
}
|
2024-06-10 21:05:03 +00:00
|
|
|
}
|
|
|
|
|
|
2024-06-19 22:01:01 +00:00
|
|
|
async fn post_backup(Path(api): Path<String>, Json(user_data): Json<BackupData>) -> ApiResult {
|
2024-06-10 21:05:03 +00:00
|
|
|
|
2024-06-19 22:01:01 +00:00
|
|
|
match auth(&api).await? {
|
2024-06-10 21:05:03 +00:00
|
|
|
Some(_user) => {
|
|
|
|
|
let _ = backup_docs_if_new(user_data.moles, "moles").await;
|
|
|
|
|
let _ = backup_docs_if_new(user_data.logs, "logs").await;
|
|
|
|
|
|
|
|
|
|
Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::CREATED)
|
|
|
|
|
.body(Body::from("Account backup successful"))?)
|
|
|
|
|
},
|
|
|
|
|
None => Ok(Response::builder()
|
|
|
|
|
.status(StatusCode::UNAUTHORIZED)
|
|
|
|
|
.body(Body::from("API Key is incorrect"))?),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn backup_docs_if_new<T: serde::Serialize>(docs: Vec<T>, collection: &'static str) -> Result<()> {
|
|
|
|
|
let _ = docs.iter()
|
|
|
|
|
.map(|doc| to_document(doc).unwrap())
|
2024-06-11 17:26:50 +00:00
|
|
|
.map(|doc| async move {
|
2024-06-10 21:05:03 +00:00
|
|
|
let _ = insert_if_new(doc, collection).await;
|
|
|
|
|
});
|
2024-06-07 14:30:16 +00:00
|
|
|
|
2024-06-10 21:05:03 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn insert_if_new(doc: Document, collection: &str) -> Result<()> {
|
|
|
|
|
let db = get_database().await?.collection(collection);
|
|
|
|
|
|
|
|
|
|
match db.count_documents(doc.clone(), None).await? {
|
|
|
|
|
0 => Some(db.insert_one(doc, None)),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|