258 lines
8.4 KiB
Rust
258 lines
8.4 KiB
Rust
#![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
#[macro_use]
|
|
extern crate rocket;
|
|
|
|
#[macro_use]
|
|
extern crate lazy_static;
|
|
use std::path::{PathBuf, Path};
|
|
use std::env;
|
|
use std::fs;
|
|
use std::ffi::OsStr;
|
|
use std::collections::HashMap;
|
|
use rocket::response::{NamedFile, Redirect};
|
|
use rocket::http::{Cookie, Cookies, ContentType, Status};
|
|
use rocket::request::{self, Request, Form, FromRequest};
|
|
use rocket_contrib::templates::Template;
|
|
use rocket_upload::MultipartDatas;
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
lazy_static! {
|
|
static ref DIR: PathBuf = Path::new(env::var("FASTCLOUD_DIR").unwrap_or_else(|_| String::from("")).as_str()).to_path_buf();
|
|
static ref ADMIN_KEY: String = env::var("FASTCLOUD_ADMIN_KEY").unwrap_or_else(|_| String::from(""));
|
|
static ref USER_KEY: String = env::var("FASTCLOUD_USER_KEY").unwrap_or_else(|_| String::from(""));
|
|
static ref PUBLIC_READ: bool = env::var("FASTCLOUD_PUBLIC").unwrap_or_else(|_| String::from("")) != *"";
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct DirPath {
|
|
is_file: bool,
|
|
path: String,
|
|
name: String,
|
|
}
|
|
|
|
#[derive(FromForm)]
|
|
struct DirName {
|
|
name: String
|
|
}
|
|
|
|
#[derive(Debug, FromForm, Deserialize)]
|
|
struct GenericUser {
|
|
key: String,
|
|
}
|
|
|
|
struct AdminUser;
|
|
|
|
impl<'a, 'r> FromRequest<'a, 'r> for GenericUser {
|
|
type Error = ();
|
|
|
|
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
|
match request.cookies().get("key") {
|
|
Some(key) => {
|
|
if key.value() == ADMIN_KEY.as_str() || key.value() == USER_KEY.as_str() {
|
|
request::Outcome::Success(GenericUser { key: String::from(key.value()) })
|
|
} else if *PUBLIC_READ {
|
|
request::Outcome::Success(GenericUser { key: String::from("") })
|
|
} else {
|
|
request::Outcome::Failure((Status::BadRequest, ()))
|
|
}
|
|
},
|
|
None => {
|
|
if *PUBLIC_READ {
|
|
request::Outcome::Success(GenericUser { key: String::from("") })
|
|
} else {
|
|
request::Outcome::Failure((Status::BadRequest, ()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, 'r> FromRequest<'a, 'r> for AdminUser {
|
|
type Error = ();
|
|
|
|
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
|
match request.cookies().get("key") {
|
|
Some(key) => {
|
|
if key.value() == ADMIN_KEY.as_str() {
|
|
request::Outcome::Success(AdminUser)
|
|
} else {
|
|
request::Outcome::Forward(())
|
|
}
|
|
},
|
|
None => request::Outcome::Forward(())
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/")]
|
|
fn root() -> Template {
|
|
let map: HashMap<String, String> = HashMap::new();
|
|
Template::render("home", map)
|
|
}
|
|
|
|
#[post("/login", data = "<form>")]
|
|
fn login(form: Form<GenericUser>, mut cookies: Cookies) -> Redirect {
|
|
let key = form.into_inner().key;
|
|
let mut cook = Cookie::new("key", key);
|
|
cook.set_http_only(true);
|
|
cook.set_secure(true);
|
|
cookies.add(cook);
|
|
Redirect::to("/serve")
|
|
}
|
|
|
|
#[get("/logout")]
|
|
fn logout(mut cookies: Cookies) -> Redirect {
|
|
match cookies.get("key") {
|
|
Some(_) => {
|
|
cookies.remove(Cookie::named("key"));
|
|
Redirect::to("/")
|
|
}
|
|
None => {
|
|
Redirect::to("/")
|
|
}
|
|
}
|
|
}
|
|
|
|
#[get("/serve")]
|
|
fn get_root(_guard: AdminUser) -> Template {
|
|
let path = DIR.as_path().to_str().unwrap_or("");
|
|
Template::render("dir", directory_structure(path.to_string()))
|
|
}
|
|
|
|
#[get("/serve", rank = 2)]
|
|
fn get_root_generic(_guard: GenericUser) -> Template {
|
|
let path = DIR.as_path().to_str().unwrap_or("");
|
|
Template::render("generic", directory_structure(path.to_string()))
|
|
}
|
|
|
|
#[get("/serve/<path..>")]
|
|
fn get_dir_entry(path: PathBuf, _guard: AdminUser) -> Template {
|
|
let dir = DIR.as_path().join(path);
|
|
let path = dir.to_str().unwrap_or("");
|
|
Template::render("dir", directory_structure(path.to_string()))
|
|
}
|
|
|
|
#[get("/serve/<path..>", rank = 2)]
|
|
fn get_dir_entry_generic(path: PathBuf, _guard: GenericUser) -> Template {
|
|
let dir = DIR.as_path().join(path);
|
|
let path = dir.to_str().unwrap_or("");
|
|
Template::render("generic", directory_structure(path.to_string()))
|
|
}
|
|
|
|
#[post("/dir/<path..>", data = "<form>")]
|
|
fn create_dir(path: PathBuf, form: Form<DirName>, _guard: AdminUser) -> Redirect {
|
|
let dir = DIR.as_path().join(path.clone()).join(form.into_inner().name);
|
|
fs::create_dir_all(dir).unwrap();
|
|
Redirect::to(uri!(get_dir_entry: path))
|
|
}
|
|
|
|
#[post("/dir", data = "<form>")]
|
|
fn create_dir_root(form: Form<DirName>, _guard: AdminUser) -> Redirect {
|
|
let dir = DIR.as_path().join(form.into_inner().name);
|
|
fs::create_dir_all(dir).unwrap();
|
|
Redirect::to(uri!(get_root))
|
|
}
|
|
|
|
#[get("/del/<path..>")]
|
|
fn delete(path: PathBuf, _guard: AdminUser) -> Redirect {
|
|
let dir = DIR.as_path().join(path.clone());
|
|
if dir.is_file() {
|
|
fs::remove_file(dir).unwrap();
|
|
} else {
|
|
fs::remove_dir_all(dir).unwrap();
|
|
}
|
|
let npath = path.parent().unwrap().to_path_buf();
|
|
Redirect::to(uri!(get_dir_entry: npath))
|
|
}
|
|
|
|
fn directory_structure(path: String) -> HashMap<&'static str, HashMap<i32, DirPath>> {
|
|
let dir = Path::new(path.as_str());
|
|
let paths = fs::read_dir(dir).unwrap()
|
|
.map(|x| x.unwrap().path().into_os_string().into_string().unwrap())
|
|
.enumerate()
|
|
.map(|x| (x.0 as i32, DirPath {
|
|
is_file: Path::new(&x.1).is_file(),
|
|
path: Path::new(&x.1).strip_prefix(DIR.clone().into_os_string().into_string().unwrap()).unwrap().to_str().unwrap().to_string(),
|
|
name: Path::new(&x.1).file_name().unwrap().to_str().unwrap().to_string(),
|
|
}))
|
|
.collect::<HashMap<i32, DirPath>>();
|
|
let mut context: HashMap<&str, HashMap<i32, DirPath>> = HashMap::new();
|
|
let parent = DirPath {
|
|
is_file: false,
|
|
path: dir.strip_prefix(DIR.clone().into_os_string().into_string().unwrap()).unwrap().parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().to_string(),
|
|
name: dir.parent().unwrap().file_name().unwrap_or_else(|| OsStr::new("")).to_str().unwrap().to_string(),
|
|
};
|
|
|
|
let current = DirPath {
|
|
is_file: false,
|
|
path: dir.strip_prefix(DIR.clone().into_os_string().into_string().unwrap()).unwrap_or_else(|_| Path::new("")).to_str().unwrap().to_string(),
|
|
name: dir.file_name().unwrap_or_else(|| OsStr::new("")).to_str().unwrap().to_string(),
|
|
};
|
|
let mut pt = HashMap::new();
|
|
pt.insert(0, parent);
|
|
context.insert("parent", pt);
|
|
let mut pt = HashMap::new();
|
|
pt.insert(0, current);
|
|
context.insert("current", pt);
|
|
context.insert("ctx", paths);
|
|
context
|
|
}
|
|
|
|
|
|
#[get("/file/<path..>")]
|
|
fn file_get(path: PathBuf, _guard: GenericUser) -> Option<NamedFile> {
|
|
let dir = DIR.as_path().join(path);
|
|
rocket::response::NamedFile::open(dir.as_path()).ok()
|
|
}
|
|
|
|
#[post("/upload/<path..>", data = "<data>")]
|
|
fn upload_file(path: PathBuf, _content_type: &ContentType, data:MultipartDatas, _guard: AdminUser) -> Redirect {
|
|
let dir = DIR.as_path().join(path.clone());
|
|
for f in data.files {
|
|
if !Path::new(&format!("{}/{}", dir.to_str().unwrap(), f.filename)).exists() {
|
|
f.persist(&dir);
|
|
}
|
|
for i in 0.. {
|
|
if !Path::new(&format!("{}/{}.{}", dir.to_str().unwrap(), f.filename, i)).exists() {
|
|
f.persist(&dir);
|
|
break
|
|
}
|
|
}
|
|
}
|
|
Redirect::to(uri!(get_dir_entry: path))
|
|
}
|
|
|
|
#[post("/upload", data = "<data>")]
|
|
fn upload_root(_content_type: &ContentType, data:MultipartDatas, _guard: AdminUser) -> Redirect {
|
|
let dir = DIR.as_path();
|
|
for f in data.files {
|
|
if !Path::new(&format!("{}/{}", dir.to_str().unwrap(), f.filename)).exists() {
|
|
f.persist(dir);
|
|
}
|
|
for i in 0.. {
|
|
if !Path::new(&format!("{}/{}.{}", dir.to_str().unwrap(), f.filename, i)).exists() {
|
|
f.persist(dir);
|
|
break
|
|
}
|
|
}
|
|
}
|
|
Redirect::to(uri!(get_root))
|
|
}
|
|
|
|
|
|
|
|
// TODO: move files
|
|
// TODO: rename files
|
|
// TODO: rewrite frontend
|
|
|
|
fn main() {
|
|
rocket::ignite()
|
|
.attach(Template::fairing())
|
|
.mount("/", routes![
|
|
root, login, logout,
|
|
get_root, get_root_generic, get_dir_entry, get_dir_entry_generic,
|
|
create_dir, create_dir_root, file_get,
|
|
upload_root, upload_file, delete]).launch();
|
|
}
|