diff --git a/Cargo.toml b/Cargo.toml index be98c7a..33d01e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,8 +30,6 @@ uuid = { version = "1.16", features = ["serde", "v7"] } random-string = "1.1" actix-ws = "0.3.0" futures-util = "0.3.31" -bunny-api-tokio = "0.2.1" -bindet = "0.3.2" [dependencies.tokio] version = "1.44" diff --git a/src/api/v1/servers/uuid/icon.rs b/src/api/v1/servers/uuid/icon.rs deleted file mode 100644 index e8a828d..0000000 --- a/src/api/v1/servers/uuid/icon.rs +++ /dev/null @@ -1,56 +0,0 @@ -use actix_web::{put, web, Error, HttpRequest, HttpResponse}; -use uuid::Uuid; -use futures_util::StreamExt as _; - -use crate::{api::v1::auth::check_access_token, structs::{Guild, Member}, utils::get_auth_header, Data}; - -#[put("{uuid}/icon")] -pub async fn upload( - req: HttpRequest, - path: web::Path<(Uuid,)>, - mut payload: web::Payload, - data: web::Data, -) -> Result { - let headers = req.headers(); - - let auth_header = get_auth_header(headers); - - if let Err(error) = auth_header { - return Ok(error); - } - - let guild_uuid = path.into_inner().0; - - let authorized = check_access_token(auth_header.unwrap(), &data.pool).await; - - if let Err(error) = authorized { - return Ok(error); - } - - let uuid = authorized.unwrap(); - - let member = Member::fetch_one(&data.pool, uuid, guild_uuid).await; - - if let Err(error) = member { - return Ok(error); - } - - let guild_result = Guild::fetch_one(&data.pool, guild_uuid).await; - - if let Err(error) = guild_result { - return Ok(error); - } - - let mut guild = guild_result.unwrap(); - - let mut bytes = web::BytesMut::new(); - while let Some(item) = payload.next().await { - bytes.extend_from_slice(&item?); - } - - if let Err(error) = guild.set_icon(&data.bunny_cdn, &data.pool, data.config.bunny.cdn_url.clone(), bytes).await { - return Ok(error) - } - - Ok(HttpResponse::Ok().finish()) -} diff --git a/src/api/v1/servers/uuid/mod.rs b/src/api/v1/servers/uuid/mod.rs index 87d9e51..8f387aa 100644 --- a/src/api/v1/servers/uuid/mod.rs +++ b/src/api/v1/servers/uuid/mod.rs @@ -4,7 +4,6 @@ use uuid::Uuid; mod channels; mod invites; mod roles; -mod icon; use crate::{ Data, @@ -31,8 +30,6 @@ pub fn web() -> Scope { // Invites .service(invites::get) .service(invites::create) - // Icon - .service(icon::upload) } #[get("/{uuid}")] diff --git a/src/config.rs b/src/config.rs index 95818b3..65a5965 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,17 +1,14 @@ use crate::Error; -use bunny_api_tokio::edge_storage::Endpoint; use log::debug; use serde::Deserialize; use sqlx::postgres::PgConnectOptions; use tokio::fs::read_to_string; -use url::Url; #[derive(Debug, Deserialize)] pub struct ConfigBuilder { database: Database, cache_database: CacheDatabase, web: Option, - bunny: BunnyBuilder, } #[derive(Debug, Deserialize, Clone)] @@ -39,14 +36,6 @@ struct WebBuilder { _ssl: Option, } -#[derive(Debug, Deserialize)] -struct BunnyBuilder { - api_key: String, - endpoint: String, - storage_zone: String, - cdn_url: Url, -} - impl ConfigBuilder { pub async fn load(path: String) -> Result { debug!("loading config from: {}", path); @@ -70,31 +59,10 @@ impl ConfigBuilder { } }; - let endpoint = match &*self.bunny.endpoint { - "Frankfurt" => Endpoint::Frankfurt, - "London" => Endpoint::London, - "New York" => Endpoint::NewYork, - "Los Angeles" => Endpoint::LosAngeles, - "Singapore" => Endpoint::Singapore, - "Stockholm" => Endpoint::Stockholm, - "Sao Paulo" => Endpoint::SaoPaulo, - "Johannesburg" => Endpoint::Johannesburg, - "Sydney" => Endpoint::Sydney, - url => Endpoint::Custom(url.to_string()), - }; - - let bunny = Bunny { - api_key: self.bunny.api_key, - endpoint, - storage_zone: self.bunny.storage_zone, - cdn_url: self.bunny.cdn_url, - }; - Config { database: self.database, cache_database: self.cache_database, web, - bunny, } } } @@ -104,7 +72,6 @@ pub struct Config { pub database: Database, pub cache_database: CacheDatabase, pub web: Web, - pub bunny: Bunny, } #[derive(Debug, Clone)] @@ -113,14 +80,6 @@ pub struct Web { pub port: u16, } -#[derive(Debug, Clone)] -pub struct Bunny { - pub api_key: String, - pub endpoint: Endpoint, - pub storage_zone: String, - pub cdn_url: Url, -} - impl Database { pub fn connect_options(&self) -> PgConnectOptions { PgConnectOptions::new() diff --git a/src/main.rs b/src/main.rs index bf918dc..fbad594 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,10 +25,9 @@ struct Args { pub struct Data { pub pool: Pool, pub cache_pool: redis::Client, - pub config: Config, + pub _config: Config, pub argon2: Argon2<'static>, pub start_time: SystemTime, - pub bunny_cdn: bunny_api_tokio::Client, } #[tokio::main] @@ -49,10 +48,6 @@ async fn main() -> Result<(), Error> { let cache_pool = redis::Client::open(config.cache_database.url())?; - let mut bunny_cdn = bunny_api_tokio::Client::new(config.bunny.api_key.clone()).await?; - - bunny_cdn.storage.init(config.bunny.endpoint.clone(), config.bunny.storage_zone.clone())?; - /* TODO: Figure out if a table should be used here and if not then what. Also figure out if these should be different types from what they currently are and if we should add more "constraints" @@ -99,8 +94,7 @@ async fn main() -> Result<(), Error> { uuid uuid PRIMARY KEY NOT NULL, owner_uuid uuid NOT NULL REFERENCES users(uuid), name VARCHAR(100) NOT NULL, - description VARCHAR(300), - icon VARCHAR(100) DEFAULT NULL + description VARCHAR(300) ); CREATE TABLE IF NOT EXISTS guild_members ( uuid uuid PRIMARY KEY NOT NULL, @@ -170,11 +164,10 @@ async fn main() -> Result<(), Error> { let data = Data { pool, cache_pool, - config, + _config: config, // TODO: Possibly implement "pepper" into this (thinking it could generate one if it doesnt exist and store it on disk) argon2: Argon2::default(), start_time: SystemTime::now(), - bunny_cdn, }; HttpServer::new(move || { diff --git a/src/structs.rs b/src/structs.rs index 92252cc..0ef738f 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,12 +1,9 @@ use std::str::FromStr; -use actix_web::{web::BytesMut, HttpResponse}; -use bindet::FileType; +use actix_web::HttpResponse; use log::error; use serde::{Deserialize, Serialize}; use sqlx::{Pool, Postgres, prelude::FromRow}; -use tokio::task; -use url::Url; use uuid::Uuid; use crate::Data; @@ -291,7 +288,7 @@ pub struct Guild { pub uuid: Uuid, name: String, description: Option, - icon: Option, + icon: String, owner_uuid: Uuid, pub roles: Vec, member_count: i64, @@ -300,7 +297,7 @@ pub struct Guild { impl Guild { pub async fn fetch_one(pool: &Pool, guild_uuid: Uuid) -> Result { let row = sqlx::query_as(&format!( - "SELECT CAST(owner_uuid AS VARCHAR), name, description, icon FROM guilds WHERE uuid = '{}'", + "SELECT CAST(owner_uuid AS VARCHAR), name, description FROM guilds WHERE uuid = '{}'", guild_uuid )) .fetch_one(pool) @@ -312,7 +309,7 @@ impl Guild { return Err(HttpResponse::InternalServerError().finish()); } - let (owner_uuid_raw, name, description, icon): (String, String, Option, Option) = row.unwrap(); + let (owner_uuid_raw, name, description): (String, String, Option) = row.unwrap(); let owner_uuid = Uuid::from_str(&owner_uuid_raw).unwrap(); @@ -324,7 +321,8 @@ impl Guild { uuid: guild_uuid, name, description, - icon, + // FIXME: This isnt supposed to be bogus + icon: String::from("bogus"), owner_uuid, roles, member_count, @@ -380,7 +378,7 @@ impl Guild { uuid: guild_uuid, name, description, - icon: None, + icon: "bogus".to_string(), owner_uuid, roles: vec![], member_count: 1, @@ -445,78 +443,6 @@ impl Guild { guild_uuid: self.uuid, }) } - - // FIXME: Horrible security - pub async fn set_icon(&mut self, bunny_cdn: &bunny_api_tokio::Client, pool: &Pool, cdn_url: Url, icon: BytesMut) -> Result<(), HttpResponse> { - let ico = icon.clone(); - - let result = task::spawn_blocking(move || { - let buf = std::io::Cursor::new(ico.to_vec()); - - let detect = bindet::detect(buf).map_err(|e| e.kind()); - - if let Ok(Some(file_type)) = detect { - if file_type.likely_to_be == vec![FileType::Jpg] { - return String::from("jpg") - } else if file_type.likely_to_be == vec![FileType::Png] { - return String::from("png") - } - } - String::from("unknown") - }).await; - - if let Err(error) = result { - error!("{}", error); - - return Err(HttpResponse::InternalServerError().finish()) - } - - let image_type = result.unwrap(); - - if image_type == "unknown" { - return Err(HttpResponse::BadRequest().finish()) - } - - if let Some(icon) = &self.icon { - let relative_url = icon.trim_start_matches("https://cdn.gorb.app/"); - - let delete_result = bunny_cdn.storage.delete(relative_url).await; - - if let Err(error) = delete_result { - error!("{}", error); - - return Err(HttpResponse::InternalServerError().finish()) - } - } - - let path = format!("icons/{}/icon.{}", self.uuid, image_type); - - let upload_result = bunny_cdn.storage.upload(path.clone(), icon.into()).await; - - if let Err(error) = upload_result { - error!("{}", error); - - return Err(HttpResponse::InternalServerError().finish()) - } - - - let icon_url = cdn_url.join(&path).unwrap(); - - let row = sqlx::query(&format!("UPDATE guilds SET icon = $1 WHERE uuid = '{}'", self.uuid)) - .bind(icon_url.as_str()) - .execute(pool) - .await; - - if let Err(error) = row { - error!("{}", error); - - return Err(HttpResponse::InternalServerError().finish()) - } - - self.icon = Some(icon_url.to_string()); - - Ok(()) - } } #[derive(FromRow)]