Right now we're not doing any streaming and this isn't ideal. I'll need to figure it out at some point.
111 lines
3.0 KiB
Rust
111 lines
3.0 KiB
Rust
#[macro_use]
|
|
extern crate diesel;
|
|
|
|
use actix_files::NamedFile;
|
|
use actix_web::web::{HttpResponse, HttpRequest, Json};
|
|
use actix_web::{get, post, App, HttpServer, Responder};
|
|
use chrono::{Duration, Utc};
|
|
use data::{LoginRequest, ThumbnailRequest};
|
|
use jsonwebtoken::{encode, EncodingKey, Header};
|
|
use std::path::PathBuf;
|
|
|
|
use crate::data::{Claims, CreateAccountRequest, Token};
|
|
use crate::database::{create_user, get_user, user_exists};
|
|
use crate::files::list_files;
|
|
|
|
mod data;
|
|
mod database;
|
|
mod files;
|
|
|
|
#[post("/register")]
|
|
async fn register(user: Json<CreateAccountRequest>) -> impl Responder {
|
|
if !user.username.is_empty() && user.password.len() > 5 && user.password == user.confirmation {
|
|
if user_exists(&user.username) {
|
|
HttpResponse::BadRequest()
|
|
} else if let Some(_user) = create_user(&user.username, &user.password) {
|
|
HttpResponse::Ok()
|
|
} else {
|
|
HttpResponse::InternalServerError()
|
|
}
|
|
} else {
|
|
HttpResponse::BadRequest()
|
|
}
|
|
}
|
|
|
|
#[post("/login")]
|
|
async fn login(creds: Json<LoginRequest>) -> impl Responder {
|
|
if let Some(user) = get_user(&creds.username, &creds.password) {
|
|
let claims = Claims {
|
|
sub: user.id.to_string(),
|
|
exp: (Utc::now() + Duration::days(3)).timestamp(),
|
|
};
|
|
let token = encode(
|
|
&Header::default(),
|
|
&claims,
|
|
&EncodingKey::from_secret("secret_token".as_ref()),
|
|
)
|
|
.unwrap();
|
|
HttpResponse::Ok().json(Token { token: &token })
|
|
} else {
|
|
HttpResponse::NotFound().finish()
|
|
}
|
|
}
|
|
|
|
#[get("/photos")]
|
|
async fn list_photos(_claims: Claims, req: Json<ThumbnailRequest>) -> impl Responder {
|
|
println!("{}", req.path);
|
|
|
|
let path = &req.path;
|
|
if let Some(path) = is_valid_path(path) {
|
|
let files = list_files(path);
|
|
HttpResponse::Ok().json(files.unwrap_or_default())
|
|
} else {
|
|
HttpResponse::BadRequest().finish()
|
|
}
|
|
|
|
}
|
|
|
|
fn is_valid_path(path: &str) -> Option<PathBuf> {
|
|
match path {
|
|
path if path.contains("..") => None,
|
|
|
|
path => {
|
|
let path = PathBuf::from(path);
|
|
if path.is_relative() {
|
|
let mut full_path = PathBuf::from(dotenv::var("BASE_PATH").unwrap());
|
|
full_path.push(path);
|
|
Some(full_path)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/image")]
|
|
async fn image(_claims: Claims, request: HttpRequest, req: Json<ThumbnailRequest>) -> impl Responder {
|
|
if let Some(path) = is_valid_path(&req.path) {
|
|
if let Ok(file) = NamedFile::open(path) {
|
|
file.into_response(&request).unwrap()
|
|
} else {
|
|
HttpResponse::NotFound().finish()
|
|
}
|
|
} else {
|
|
HttpResponse::NotFound().finish()
|
|
}
|
|
}
|
|
|
|
#[actix_rt::main]
|
|
async fn main() -> std::io::Result<()> {
|
|
HttpServer::new(|| {
|
|
App::new()
|
|
.service(login)
|
|
.service(list_photos)
|
|
.service(register)
|
|
.service(image)
|
|
})
|
|
.bind("127.0.0.1:8088")?
|
|
.run()
|
|
.await
|
|
}
|