CORS fixup

This commit is contained in:
core 2023-02-20 13:42:15 -05:00
parent 49aacc71ef
commit 36409b3dca
Signed by: core
GPG Key ID: FDBF740DADDCEECF
8 changed files with 72 additions and 3 deletions

View File

@ -18,4 +18,4 @@ paste = "1.0.11"
totp-rs = { version = "4.2.0", features = ["qr", "otpauth", "gen_secret"]} totp-rs = { version = "4.2.0", features = ["qr", "otpauth", "gen_secret"]}
uuid = { version = "1.3.0", features = ["v4", "fast-rng", "macro-diagnostics"]} uuid = { version = "1.3.0", features = ["v4", "fast-rng", "macro-diagnostics"]}
url = { version = "2.3.1", features = ["serde"] } url = { version = "2.3.1", features = ["serde"] }
urlencoding = "2.1.2" urlencoding = "2.1.2"

View File

@ -5,7 +5,9 @@ use std::fs;
use std::path::Path; use std::path::Path;
use dotenvy::dotenv; use dotenvy::dotenv;
use log::{error, info}; use log::{error, info};
use rocket::{catchers, routes}; use rocket::{catchers, Request, Response, routes};
use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::Header;
use sqlx::migrate::Migrator; use sqlx::migrate::Migrator;
use sqlx::postgres::PgPoolOptions; use sqlx::postgres::PgPoolOptions;
use crate::config::TFConfig; use crate::config::TFConfig;
@ -20,6 +22,25 @@ pub mod auth;
static MIGRATOR: Migrator = sqlx::migrate!(); static MIGRATOR: Migrator = sqlx::migrate!();
pub struct CORS;
#[rocket::async_trait]
impl Fairing for CORS {
fn info(&self) -> Info {
Info {
name: "Add CORS headers to responses",
kind: Kind::Response
}
}
async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mut Response<'r>) {
response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS"));
response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
}
}
#[rocket::main] #[rocket::main]
async fn main() -> Result<(), Box<dyn Error>> { async fn main() -> Result<(), Box<dyn Error>> {
let _ = rocket::build(); let _ = rocket::build();
@ -81,11 +102,17 @@ async fn main() -> Result<(), Box<dyn Error>> {
let _ = rocket::custom(figment) let _ = rocket::custom(figment)
.mount("/", routes![ .mount("/", routes![
crate::routes::v1::auth::magic_link::magiclink_request, crate::routes::v1::auth::magic_link::magiclink_request,
crate::routes::v1::auth::magic_link::options,
crate::routes::v1::signup::signup_request, crate::routes::v1::signup::signup_request,
crate::routes::v1::signup::options,
crate::routes::v1::auth::verify_magic_link::verify_magic_link, crate::routes::v1::auth::verify_magic_link::verify_magic_link,
crate::routes::v1::auth::verify_magic_link::options,
crate::routes::v1::totp_authenticators::totp_authenticators_request, crate::routes::v1::totp_authenticators::totp_authenticators_request,
crate::routes::v1::totp_authenticators::options,
crate::routes::v1::verify_totp_authenticator::verify_totp_authenticator_request, crate::routes::v1::verify_totp_authenticator::verify_totp_authenticator_request,
crate::routes::v1::auth::totp::totp_request crate::routes::v1::verify_totp_authenticator::options,
crate::routes::v1::auth::totp::totp_request,
crate::routes::v1::auth::totp::options
]) ])
.register("/", catchers![ .register("/", catchers![
crate::routes::handler_400, crate::routes::handler_400,
@ -101,6 +128,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
crate::routes::handler_504, crate::routes::handler_504,
crate::routes::handler_505, crate::routes::handler_505,
]) ])
.attach(CORS)
.manage(pool) .manage(pool)
.manage(config) .manage(config)
.launch().await?; .launch().await?;

View File

@ -5,6 +5,7 @@ use rocket::http::{ContentType, Status};
use sqlx::PgPool; use sqlx::PgPool;
use crate::config::TFConfig; use crate::config::TFConfig;
use crate::tokens::send_magic_link; use crate::tokens::send_magic_link;
use rocket::options;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
@ -23,6 +24,12 @@ pub struct MagicLinkResponse {
pub metadata: MagicLinkResponseMetadata, pub metadata: MagicLinkResponseMetadata,
} }
#[options("/v1/auth/magic-link")]
pub async fn options() -> &'static str {
""
}
#[post("/v1/auth/magic-link", data = "<req>")] #[post("/v1/auth/magic-link", data = "<req>")]
pub async fn magiclink_request(req: Json<MagicLinkRequest>, pool: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<MagicLinkResponse>), (Status, String)> { pub async fn magiclink_request(req: Json<MagicLinkRequest>, pool: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<MagicLinkResponse>), (Status, String)> {
// figure out if the user already exists // figure out if the user already exists

View File

@ -4,6 +4,7 @@ use crate::auth::PartialUserInfo;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use rocket::{post, State}; use rocket::{post, State};
use sqlx::PgPool; use sqlx::PgPool;
use rocket::options;
use crate::tokens::{generate_auth_token, get_totpmachine, user_has_totp}; use crate::tokens::{generate_auth_token, get_totpmachine, user_has_totp};
pub const TOTP_GENERIC_UNAUTHORIZED_ERROR: &str = "{\"errors\":[{\"code\":\"ERR_INVALID_TOTP_CODE\",\"message\":\"invalid TOTP code (maybe it expired?)\",\"path\":\"code\"}]}"; pub const TOTP_GENERIC_UNAUTHORIZED_ERROR: &str = "{\"errors\":[{\"code\":\"ERR_INVALID_TOTP_CODE\",\"message\":\"invalid TOTP code (maybe it expired?)\",\"path\":\"code\"}]}";
@ -32,6 +33,12 @@ pub struct TotpResponse {
metadata: TotpResponseMetadata metadata: TotpResponseMetadata
} }
#[options("/v1/auth/totp")]
pub async fn options() -> &'static str {
""
}
#[post("/v1/auth/totp", data = "<req>")] #[post("/v1/auth/totp", data = "<req>")]
pub async fn totp_request(req: Json<TotpRequest>, user: PartialUserInfo, db: &State<PgPool>) -> Result<(ContentType, Json<TotpResponse>), (Status, String)> { pub async fn totp_request(req: Json<TotpRequest>, user: PartialUserInfo, db: &State<PgPool>) -> Result<(ContentType, Json<TotpResponse>), (Status, String)> {
if !match user_has_totp(user.user_id, db.inner()).await { if !match user_has_totp(user.user_id, db.inner()).await {

View File

@ -6,6 +6,7 @@ use rocket::{post, State};
use sqlx::PgPool; use sqlx::PgPool;
use crate::config::TFConfig; use crate::config::TFConfig;
use crate::tokens::generate_session_token; use crate::tokens::generate_session_token;
use rocket::options;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
@ -30,6 +31,12 @@ pub struct VerifyMagicLinkResponse {
pub metadata: VerifyMagicLinkResponseMetadata, pub metadata: VerifyMagicLinkResponseMetadata,
} }
#[options("/v1/auth/verify-magic-link")]
pub async fn options() -> &'static str {
""
}
#[post("/v1/auth/verify-magic-link", data = "<req>")] #[post("/v1/auth/verify-magic-link", data = "<req>")]
pub async fn verify_magic_link(req: Json<VerifyMagicLinkRequest>, db: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<VerifyMagicLinkResponse>), (Status, String)> { pub async fn verify_magic_link(req: Json<VerifyMagicLinkRequest>, db: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<VerifyMagicLinkResponse>), (Status, String)> {
// get the current time to check if the token is expired // get the current time to check if the token is expired

View File

@ -6,6 +6,7 @@ use rocket::http::{ContentType, Status};
use sqlx::PgPool; use sqlx::PgPool;
use crate::config::TFConfig; use crate::config::TFConfig;
use crate::tokens::send_magic_link; use crate::tokens::send_magic_link;
use rocket::options;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
@ -29,6 +30,11 @@ created_on TIMESTAMP NOT NULL,
banned INTEGER NOT NULL, banned INTEGER NOT NULL,
ban_reason VARCHAR(1024) NOT NULL ban_reason VARCHAR(1024) NOT NULL
*/ */
#[options("/v1/signup")]
pub async fn options() -> &'static str {
""
}
#[post("/v1/signup", data = "<req>")] #[post("/v1/signup", data = "<req>")]
pub async fn signup_request(req: Json<SignupRequest>, pool: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<SignupResponse>), (Status, String)> { pub async fn signup_request(req: Json<SignupRequest>, pool: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<SignupResponse>), (Status, String)> {
// figure out if the user already exists // figure out if the user already exists

View File

@ -6,6 +6,7 @@ use serde::{Serialize, Deserialize};
use crate::auth::PartialUserInfo; use crate::auth::PartialUserInfo;
use crate::config::TFConfig; use crate::config::TFConfig;
use crate::tokens::{create_totp_token, user_has_totp}; use crate::tokens::{create_totp_token, user_has_totp};
use rocket::options;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct TotpAuthenticatorsRequest {} pub struct TotpAuthenticatorsRequest {}
@ -27,6 +28,12 @@ pub struct TotpAuthenticatorsResponse {
pub metadata: TotpAuthenticatorsResponseMetadata, pub metadata: TotpAuthenticatorsResponseMetadata,
} }
#[options("/v1/totp-authenticators")]
pub async fn options() -> &'static str {
""
}
#[post("/v1/totp-authenticators", data = "<_req>")] #[post("/v1/totp-authenticators", data = "<_req>")]
pub async fn totp_authenticators_request(_req: Json<TotpAuthenticatorsRequest>, user: PartialUserInfo, db: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<TotpAuthenticatorsResponse>), (Status, String)> { pub async fn totp_authenticators_request(_req: Json<TotpAuthenticatorsRequest>, user: PartialUserInfo, db: &State<PgPool>, config: &State<TFConfig>) -> Result<(ContentType, Json<TotpAuthenticatorsResponse>), (Status, String)> {
if match user_has_totp(user.user_id, db.inner()).await { if match user_has_totp(user.user_id, db.inner()).await {

View File

@ -15,6 +15,7 @@ use rocket::State;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use sqlx::PgPool; use sqlx::PgPool;
use crate::tokens::{generate_auth_token, use_totp_token, verify_totp_token}; use crate::tokens::{generate_auth_token, use_totp_token, verify_totp_token};
use rocket::options;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct VerifyTotpAuthenticatorRequest { pub struct VerifyTotpAuthenticatorRequest {
@ -38,6 +39,12 @@ pub struct VerifyTotpAuthenticatorResponse {
pub metadata: VerifyTotpAuthenticatorResponseMetadata, pub metadata: VerifyTotpAuthenticatorResponseMetadata,
} }
#[options("/v1/auth/verify-totp-authenticator")]
pub async fn options() -> &'static str {
""
}
#[post("/v1/verify-totp-authenticator", data = "<req>")] #[post("/v1/verify-totp-authenticator", data = "<req>")]
pub async fn verify_totp_authenticator_request(req: Json<VerifyTotpAuthenticatorRequest>, db: &State<PgPool>, user: PartialUserInfo) -> Result<(ContentType, Json<VerifyTotpAuthenticatorResponse>), (Status, String)> { pub async fn verify_totp_authenticator_request(req: Json<VerifyTotpAuthenticatorRequest>, db: &State<PgPool>, user: PartialUserInfo) -> Result<(ContentType, Json<VerifyTotpAuthenticatorResponse>), (Status, String)> {
let totpmachine = match verify_totp_token(req.0.totp_token.clone(), user.email.clone(), db.inner()).await { let totpmachine = match verify_totp_token(req.0.totp_token.clone(), user.email.clone(), db.inner()).await {