|
|
@ -1,14 +1,25 @@
|
|
|
|
mod tsar;
|
|
|
|
mod tsar;
|
|
|
|
|
|
|
|
mod security;
|
|
|
|
|
|
|
|
|
|
|
|
use std::{env, net::{IpAddr, SocketAddr}};
|
|
|
|
use std::{env, net::{IpAddr, SocketAddr}};
|
|
|
|
|
|
|
|
|
|
|
|
use axum::{
|
|
|
|
use axum::{
|
|
|
|
routing::get,
|
|
|
|
routing::{get, post},
|
|
|
|
Router,
|
|
|
|
Router,
|
|
|
|
extract::{Path, State}, http::StatusCode,
|
|
|
|
extract::{Path, State}, http::StatusCode, Json,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
use rand::{thread_rng, seq::IteratorRandom};
|
|
|
|
use rand::{thread_rng, seq::IteratorRandom};
|
|
|
|
|
|
|
|
use security::salt_and_hash;
|
|
|
|
|
|
|
|
use serde::Deserialize;
|
|
|
|
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions};
|
|
|
|
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions};
|
|
|
|
|
|
|
|
use base64::prelude::*;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
|
|
|
struct SetPronounsRequest {
|
|
|
|
|
|
|
|
password: String,
|
|
|
|
|
|
|
|
new_pronouns: String,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
#[tokio::main]
|
|
|
@ -31,6 +42,7 @@ async fn main() {
|
|
|
|
let app = Router::new()
|
|
|
|
let app = Router::new()
|
|
|
|
.route("/api/thethirdcan/hello", get(|| async { "hello world!" }))
|
|
|
|
.route("/api/thethirdcan/hello", get(|| async { "hello world!" }))
|
|
|
|
.route("/api/thethirdcan/pronouns/:user", get(user_pronouns))
|
|
|
|
.route("/api/thethirdcan/pronouns/:user", get(user_pronouns))
|
|
|
|
|
|
|
|
.route("/api/thethirdcan/pronouns/:user", post(set_pronouns))
|
|
|
|
.with_state(pool);
|
|
|
|
.with_state(pool);
|
|
|
|
|
|
|
|
|
|
|
|
axum::Server::bind(&SocketAddr::new(IpAddr::from([0;4]), port))
|
|
|
|
axum::Server::bind(&SocketAddr::new(IpAddr::from([0;4]), port))
|
|
|
@ -46,7 +58,7 @@ async fn user_pronouns(
|
|
|
|
) -> Result<String, StatusCode> {
|
|
|
|
) -> Result<String, StatusCode> {
|
|
|
|
sqlx::query!("SELECT pronouns
|
|
|
|
sqlx::query!("SELECT pronouns
|
|
|
|
FROM users
|
|
|
|
FROM users
|
|
|
|
WHERE username == ?",
|
|
|
|
WHERE username = ?",
|
|
|
|
user)
|
|
|
|
user)
|
|
|
|
.fetch_one(pool)
|
|
|
|
.fetch_one(pool)
|
|
|
|
.await
|
|
|
|
.await
|
|
|
@ -61,3 +73,29 @@ async fn user_pronouns(
|
|
|
|
.map(ToOwned::to_owned)
|
|
|
|
.map(ToOwned::to_owned)
|
|
|
|
.ok_or(StatusCode::INTERNAL_SERVER_ERROR)
|
|
|
|
.ok_or(StatusCode::INTERNAL_SERVER_ERROR)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async fn set_pronouns(
|
|
|
|
|
|
|
|
State(pool): State<&SqlitePool>,
|
|
|
|
|
|
|
|
Path(user): Path<String>,
|
|
|
|
|
|
|
|
Json(payload): Json<SetPronounsRequest>,
|
|
|
|
|
|
|
|
) -> Result<(), StatusCode> {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let password_data = BASE64_URL_SAFE.decode(payload.password).map_err(|_| StatusCode::BAD_REQUEST)?;
|
|
|
|
|
|
|
|
let salted_hashed_password = salt_and_hash(&password_data);
|
|
|
|
|
|
|
|
let auth_slice = salted_hashed_password.as_ref();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let rows_affected = sqlx::query!("UPDATE users
|
|
|
|
|
|
|
|
SET pronouns = ?
|
|
|
|
|
|
|
|
WHERE username = ? AND auth = ?
|
|
|
|
|
|
|
|
", payload.new_pronouns, user, auth_slice)
|
|
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
|
|
.await
|
|
|
|
|
|
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
|
|
|
|
|
|
|
.rows_affected();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if rows_affected == 0 {
|
|
|
|
|
|
|
|
return Err(StatusCode::NOT_FOUND);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|