feat: add global email verification check
This commit is contained in:
parent
29dbb085a2
commit
abfbaf8918
18 changed files with 106 additions and 63 deletions
|
@ -36,6 +36,8 @@ pub async fn join(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
let invite = Invite::fetch_one(&mut conn, invite_id).await?;
|
||||
|
||||
let guild = Guild::fetch_one(&mut conn, invite.guild_uuid).await?;
|
||||
|
|
|
@ -3,7 +3,7 @@ use actix_web::{HttpRequest, HttpResponse, Scope, get, patch, web};
|
|||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
Data, api::v1::auth::check_access_token, error::Error, structs::Me, utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::Me, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
|
||||
mod servers;
|
||||
|
@ -27,7 +27,7 @@ pub async fn get(req: HttpRequest, data: web::Data<Data>) -> Result<HttpResponse
|
|||
Ok(HttpResponse::Ok().json(me))
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
struct NewInfo {
|
||||
username: Option<String>,
|
||||
display_name: Option<String>,
|
||||
|
@ -39,7 +39,7 @@ struct NewInfo {
|
|||
struct UploadForm {
|
||||
#[multipart(limit = "100MB")]
|
||||
avatar: Option<TempFile>,
|
||||
json: Option<MpJson<NewInfo>>,
|
||||
json: MpJson<Option<NewInfo>>,
|
||||
}
|
||||
|
||||
#[patch("")]
|
||||
|
@ -56,6 +56,10 @@ pub async fn update(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
if form.avatar.is_some() || form.json.0.clone().is_some_and(|ni| ni.username.is_some() || ni.display_name.is_some()) {
|
||||
global_checks(&data, uuid).await?;
|
||||
}
|
||||
|
||||
let mut me = Me::get(&mut conn, uuid).await?;
|
||||
|
||||
if let Some(avatar) = form.avatar {
|
||||
|
@ -72,7 +76,7 @@ pub async fn update(
|
|||
.await?;
|
||||
}
|
||||
|
||||
if let Some(new_info) = form.json {
|
||||
if let Some(new_info) = form.json.0 {
|
||||
if let Some(username) = &new_info.username {
|
||||
me.set_username(&mut conn, username.clone()).await?;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||
|
||||
use crate::{api::v1::auth::check_access_token, error::Error, structs::Me, utils::get_auth_header, Data};
|
||||
use crate::{api::v1::auth::check_access_token, error::Error, structs::Me, utils::{get_auth_header, global_checks}, Data};
|
||||
|
||||
|
||||
/// `GET /api/v1/me/servers` Returns all guild memberships in a list
|
||||
|
@ -37,6 +37,8 @@ pub async fn get(req: HttpRequest, data: web::Data<Data>) -> Result<HttpResponse
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
let me = Me::get(&mut conn, uuid).await?;
|
||||
|
||||
let memberships = me.fetch_memberships(&mut conn).await?;
|
||||
|
|
|
@ -6,11 +6,7 @@ use serde::Deserialize;
|
|||
mod uuid;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Guild, StartAmountQuery},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Guild, StartAmountQuery}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -134,7 +130,9 @@ pub async fn get(
|
|||
|
||||
let amount = request_query.amount.unwrap_or(10);
|
||||
|
||||
check_access_token(auth_header, &mut data.pool.get().await?).await?;
|
||||
let uuid = check_access_token(auth_header, &mut data.pool.get().await?).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
let guilds = Guild::fetch_amount(&data.pool, start, amount).await?;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Channel, Member}, utils::{get_auth_header, order_by_is_above}, Data
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Channel, Member}, utils::{get_auth_header, global_checks, order_by_is_above}, Data
|
||||
};
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
||||
|
@ -29,6 +29,8 @@ pub async fn get(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
if let Ok(cache_hit) = data.get_cache_key(format!("{}_channels", guild_uuid)).await {
|
||||
|
@ -68,6 +70,8 @@ pub async fn create(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
// FIXME: Logic to check permissions, should probably be done in utils.rs
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
//! `/api/v1/servers/{uuid}/channels/{uuid}/messages` Endpoints related to channel messages
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Channel, Member},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Channel, Member}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, web};
|
||||
|
@ -64,6 +60,8 @@ pub async fn get(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let channel: Channel;
|
||||
|
|
|
@ -2,11 +2,7 @@ pub mod messages;
|
|||
pub mod socket;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Channel, Member},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Channel, Member}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
use actix_web::{HttpRequest, HttpResponse, delete, get, web};
|
||||
use uuid::Uuid;
|
||||
|
@ -27,6 +23,8 @@ pub async fn get(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
if let Ok(cache_hit) = data.get_cache_key(format!("{}", channel_uuid)).await {
|
||||
|
@ -59,6 +57,8 @@ pub async fn delete(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let channel: Channel;
|
||||
|
|
|
@ -8,10 +8,7 @@ use futures_util::StreamExt as _;
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
structs::{Channel, Member},
|
||||
utils::get_ws_protocol_header,
|
||||
api::v1::auth::check_access_token, structs::{Channel, Member}, utils::{get_ws_protocol_header, global_checks}, Data
|
||||
};
|
||||
|
||||
#[get("{uuid}/channels/{channel_uuid}/socket")]
|
||||
|
@ -35,6 +32,8 @@ pub async fn ws(
|
|||
// Authorize client using auth header
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
// Get server member from psql
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
|
|
|
@ -5,11 +5,7 @@ use futures_util::StreamExt as _;
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Guild, Member},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Guild, Member}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
|
||||
/// `PUT /api/v1/servers/{uuid}/icon` Icon upload
|
||||
|
@ -34,6 +30,8 @@ pub async fn upload(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let mut guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
|
|
@ -3,11 +3,7 @@ use serde::Deserialize;
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Guild, Member},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Guild, Member}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -31,6 +27,8 @@ pub async fn get(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
@ -57,6 +55,8 @@ pub async fn create(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
let member = Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
|
|
@ -9,11 +9,7 @@ mod invites;
|
|||
mod roles;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Guild, Member},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Guild, Member}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
|
||||
pub fn web() -> Scope {
|
||||
|
@ -87,6 +83,8 @@ pub async fn get(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
|
|
@ -3,7 +3,7 @@ use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
|||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Member, Role}, utils::{get_auth_header, order_by_is_above}, Data
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Member, Role}, utils::{get_auth_header, global_checks, order_by_is_above}, Data
|
||||
};
|
||||
|
||||
pub mod uuid;
|
||||
|
@ -64,6 +64,8 @@ pub async fn create(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
// FIXME: Logic to check permissions, should probably be done in utils.rs
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Member, Role},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Member, Role}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, web};
|
||||
|
@ -24,6 +20,8 @@ pub async fn get(
|
|||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
Member::fetch_one(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
if let Ok(cache_hit) = data.get_cache_key(format!("{}", role_uuid)).await {
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
use actix_web::{HttpRequest, HttpResponse, Scope, get, web};
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{StartAmountQuery, User},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{StartAmountQuery, User}, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
|
||||
mod uuid;
|
||||
|
@ -68,7 +64,9 @@ pub async fn get(
|
|||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
check_access_token(auth_header, &mut conn).await?;
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
let users = User::fetch_amount(&mut conn, start, amount).await?;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use actix_web::{HttpRequest, HttpResponse, get, web};
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
Data, api::v1::auth::check_access_token, error::Error, structs::User, utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::User, utils::{get_auth_header, global_checks}, Data
|
||||
};
|
||||
|
||||
/// `GET /api/v1/users/{uuid}` Returns user with the given UUID
|
||||
|
@ -31,15 +31,17 @@ pub async fn get(
|
|||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
|
||||
let uuid = path.into_inner().0;
|
||||
let user_uuid = path.into_inner().0;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
check_access_token(auth_header, &mut conn).await?;
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
let user = User::fetch_one(&data, uuid).await?;
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
let user = User::fetch_one(&data, user_uuid).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(user))
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct ConfigBuilder {
|
|||
database: Database,
|
||||
cache_database: CacheDatabase,
|
||||
web: WebBuilder,
|
||||
instance: Option<Instance>,
|
||||
instance: Option<InstanceBuilder>,
|
||||
bunny: BunnyBuilder,
|
||||
mail: Mail,
|
||||
}
|
||||
|
@ -42,9 +42,10 @@ struct WebBuilder {
|
|||
_ssl: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Instance {
|
||||
pub registration: bool,
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct InstanceBuilder {
|
||||
registration: Option<bool>,
|
||||
require_email_verification: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -106,11 +107,22 @@ impl ConfigBuilder {
|
|||
cdn_url: self.bunny.cdn_url,
|
||||
};
|
||||
|
||||
let instance = match self.instance {
|
||||
Some(instance) => Instance {
|
||||
registration: instance.registration.unwrap_or(true),
|
||||
require_email_verification: instance.require_email_verification.unwrap_or(false),
|
||||
},
|
||||
None => Instance {
|
||||
registration: true,
|
||||
require_email_verification: false,
|
||||
},
|
||||
};
|
||||
|
||||
Config {
|
||||
database: self.database,
|
||||
cache_database: self.cache_database,
|
||||
web,
|
||||
instance: self.instance.unwrap_or(Instance { registration: true }),
|
||||
instance,
|
||||
bunny,
|
||||
mail: self.mail,
|
||||
}
|
||||
|
@ -134,6 +146,12 @@ pub struct Web {
|
|||
pub url: Url,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Instance {
|
||||
pub registration: bool,
|
||||
pub require_email_verification: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Bunny {
|
||||
pub api_key: String,
|
||||
|
|
|
@ -16,7 +16,7 @@ use argon2::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
error::Error, schema::*, utils::{generate_refresh_token, image_check, order_by_is_above, user_uuid_from_identifier, EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX}, Conn, Data
|
||||
error::Error, schema::*, utils::{generate_refresh_token, global_checks, image_check, order_by_is_above, user_uuid_from_identifier, EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX}, Conn, Data
|
||||
};
|
||||
|
||||
pub trait HasUuid {
|
||||
|
@ -1070,6 +1070,8 @@ impl PasswordResetToken {
|
|||
|
||||
let user_uuid = user_uuid_from_identifier(&mut conn, &identifier).await?;
|
||||
|
||||
global_checks(&data, user_uuid).await?;
|
||||
|
||||
use users::dsl as udsl;
|
||||
let (username, email_address): (String, String) = udsl::users
|
||||
.filter(udsl::uuid.eq(user_uuid))
|
||||
|
|
20
src/utils.rs
20
src/utils.rs
|
@ -161,6 +161,26 @@ pub async fn user_uuid_from_identifier(conn: &mut Conn, identifier: &String) ->
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn global_checks(data: &Data, user_uuid: Uuid) -> Result<(), Error> {
|
||||
if data.config.instance.require_email_verification {
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
use users::dsl;
|
||||
let email_verified: bool = dsl::users
|
||||
.filter(dsl::uuid.eq(user_uuid))
|
||||
.select(dsl::email_verified)
|
||||
.get_result(&mut conn)
|
||||
.await?;
|
||||
|
||||
if !email_verified {
|
||||
return Err(Error::Forbidden("server requires email verification".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn order_by_is_above<T>(mut items: Vec<T>) -> Result<Vec<T>, Error>
|
||||
where
|
||||
T: HasUuid + HasIsAbove,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue