mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Enable premium, add custom avatar saving support to complete #10
This commit is contained in:
82
cdn/src/robocraft/internal_auth.rs
Normal file
82
cdn/src/robocraft/internal_auth.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
pub struct IntercomAuth {
|
||||
key: Vec<u8>,
|
||||
}
|
||||
|
||||
impl IntercomAuth {
|
||||
pub fn new(data: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
||||
let key = std::fs::read(data.as_ref().join(oj_rc_core::persist::user::TOKEN_SECRET_FILENAME))?;
|
||||
Ok(Self {
|
||||
key,
|
||||
})
|
||||
}
|
||||
|
||||
fn validate_token(&self, received_token: &str, salt: &str) -> Result<(), IntercomOpError> {
|
||||
let expected_token = oj_rc_core::persist::user::generate_intercom_token(salt.as_bytes(), &self.key);
|
||||
if received_token.to_lowercase() == expected_token.to_lowercase() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(IntercomOpError::Unauthorized)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self, req: &actix_web::HttpRequest, salt: &str) -> Result<(), IntercomOpError> {
|
||||
if let Some(auth_header) = req.headers().get("Authorization") {
|
||||
if let Ok(header_val) = auth_header.to_str() {
|
||||
if let Some((bearer, token)) = header_val.split_once(" ") {
|
||||
if bearer.to_lowercase() == "internal" || bearer.to_lowercase() == "bearer" {
|
||||
self.validate_token(token, salt)?;
|
||||
} else {
|
||||
return Err(super::IntercomOpError::BadHeader);
|
||||
}
|
||||
} else {
|
||||
return Err(super::IntercomOpError::BadHeader);
|
||||
}
|
||||
} else {
|
||||
return Err(super::IntercomOpError::BadHeader);
|
||||
}
|
||||
} else {
|
||||
return Err(super::IntercomOpError::Unauthorized);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IntercomOpError {
|
||||
BadHeader,
|
||||
Unauthorized,
|
||||
Io(std::io::Error),
|
||||
#[allow(dead_code)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for IntercomOpError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Intercom error variant {:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl actix_web::error::ResponseError for IntercomOpError {
|
||||
fn status_code(&self) -> actix_web::http::StatusCode {
|
||||
match self {
|
||||
Self::BadHeader => actix_web::http::StatusCode::BAD_REQUEST,
|
||||
Self::Unauthorized => actix_web::http::StatusCode::FORBIDDEN,
|
||||
Self::Io(_) => actix_web::http::StatusCode::INSUFFICIENT_STORAGE,
|
||||
Self::Unknown => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> {
|
||||
match self {
|
||||
Self::Io(io_e) => {
|
||||
actix_web::HttpResponse::new(self.status_code())
|
||||
.set_body(format!("Intercom IO error: {}", io_e))
|
||||
.map_into_boxed_body()
|
||||
},
|
||||
_ => {
|
||||
actix_web::HttpResponse::new(self.status_code()).set_body(self.to_string()).map_into_boxed_body()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,7 @@ pub mod brawl_data;
|
||||
pub mod campaign_data;
|
||||
pub mod factory;
|
||||
pub mod favicon;
|
||||
mod internal_auth;
|
||||
pub use internal_auth::{IntercomAuth, IntercomOpError};
|
||||
|
||||
pub(self) const DEFAULT_IMAGE: &str = "default.jpg";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use actix_web::{get, web::{Data, Path}, Responder};
|
||||
use actix_web::{get, post, web::{Data, Path, Bytes}, Responder};
|
||||
|
||||
#[get("/customavatar/Live/{name}")]
|
||||
pub async fn get(cli: Data<crate::cli::CliArgs>, name: Path<String>) -> impl Responder {
|
||||
@@ -11,3 +11,12 @@ pub async fn get(cli: Data<crate::cli::CliArgs>, name: Path<String>) -> impl Res
|
||||
actix_files::NamedFile::open_async(std::path::PathBuf::from(&cli.assets_robocraft).join(super::DEFAULT_IMAGE)).await
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/customavatar/Live/{name}")]
|
||||
pub async fn post(cli: Data<crate::cli::CliArgs>, auth: Data<crate::robocraft::IntercomAuth>, name: Path<String>, body: Bytes, req: actix_web::HttpRequest) -> Result<actix_web::HttpResponse, super::IntercomOpError> {
|
||||
auth.validate(&req, &name)?;
|
||||
let path = std::path::PathBuf::from(&cli.data_robocraft).join("customavatars").join(format!("{}.jpg", *name));
|
||||
log::debug!("Saving customavatar for {} to {}: {}B", name, path.display(), body.len());
|
||||
std::fs::write(path, &body).map_err(super::IntercomOpError::Io)?;
|
||||
Ok(actix_web::HttpResponse::NoContent().finish())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user