first
This commit is contained in:
commit
c8cae433e2
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1961
Cargo.lock
generated
Normal file
1961
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "fserve"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = "0.4.10"
|
||||||
|
rocket_upload = "0.1.0"
|
||||||
|
rocket_contrib = { version = "0.4.10", default-features = false, features = [ "handlebars_templates" ]}
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
rand = "0.8.5"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
23
Dockerfile
Normal file
23
Dockerfile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
FROM rust:1.59 as builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY ./src/ /build/src
|
||||||
|
COPY ./Cargo.toml /build/Cargo.toml
|
||||||
|
|
||||||
|
RUN rustup update nightly && rustup default nightly && \
|
||||||
|
cargo clean && cargo build --release
|
||||||
|
|
||||||
|
FROM debian:buster-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /build/target/release/fastcloud /app/fastcloud
|
||||||
|
|
||||||
|
RUN mkdir /app/service
|
||||||
|
|
||||||
|
COPY ./templates/ /app/templates
|
||||||
|
|
||||||
|
ENV FSERVE_DIR /app/service
|
||||||
|
|
||||||
|
CMD [ "/app/fastcloud" ]
|
114
src/main.rs
Normal file
114
src/main.rs
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#![feature(proc_macro_hygiene, decl_macro)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rocket;
|
||||||
|
use rand::Rng;
|
||||||
|
use rocket::http::{ContentType, Cookie, Cookies, Status};
|
||||||
|
use rocket::request;
|
||||||
|
use rocket::request::{Form, FromRequest, Request};
|
||||||
|
use rocket::response::{NamedFile, Redirect};
|
||||||
|
use rocket_contrib::templates::Template;
|
||||||
|
use rocket_upload::MultipartDatas;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref FSERVE_PASSWD: String =
|
||||||
|
env::var("FSERVE_PASSWD").unwrap_or_else(|_| String::from(""));
|
||||||
|
static ref DIR: PathBuf = Path::new(
|
||||||
|
env::var("FSERVE_DIR")
|
||||||
|
.unwrap_or_else(|_| String::from(""))
|
||||||
|
.as_str()
|
||||||
|
)
|
||||||
|
.to_path_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AdminUser;
|
||||||
|
|
||||||
|
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() == FSERVE_PASSWD.as_str() {
|
||||||
|
request::Outcome::Success(AdminUser)
|
||||||
|
} else {
|
||||||
|
request::Outcome::Failure((Status::BadRequest, ()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None => request::Outcome::Failure((Status::BadRequest, ())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/f/<path..>")]
|
||||||
|
fn get_file(path: PathBuf) -> Option<NamedFile> {
|
||||||
|
let dir = DIR.as_path().join(path);
|
||||||
|
rocket::response::NamedFile::open(dir.as_path()).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload(data: MultipartDatas) -> Vec<String> {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for f in data.files {
|
||||||
|
let mut hex_str = format!("{:016x}", rng.gen::<u64>());
|
||||||
|
while Path::new(&format!("{}/{}", DIR.to_str().unwrap(), hex_str)).exists() {
|
||||||
|
hex_str = format!("{:016x}", rng.gen::<u64>());
|
||||||
|
}
|
||||||
|
let dirloc = &format!("{}/{}", DIR.to_str().unwrap(), hex_str);
|
||||||
|
fs::create_dir_all(Path::new(dirloc)).unwrap();
|
||||||
|
let dir = Path::new(dirloc);
|
||||||
|
v.push(format!("/{}/{}", hex_str, f.filename));
|
||||||
|
f.persist(dir);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/upload", data = "<data>")]
|
||||||
|
fn upload_file(_content_type: &ContentType, data: MultipartDatas, _guard: AdminUser) -> Redirect {
|
||||||
|
let resp = upload(data);
|
||||||
|
Redirect::to(uri!(get_file: Path::new(&resp[0])))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/up")]
|
||||||
|
fn up(_guard: AdminUser) -> Template {
|
||||||
|
let map: HashMap<String, String> = HashMap::new();
|
||||||
|
Template::render("up", map)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromForm, Deserialize)]
|
||||||
|
struct GenericUser {
|
||||||
|
key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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("/up")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
fn root() -> Template {
|
||||||
|
let map: HashMap<String, String> = HashMap::new();
|
||||||
|
Template::render("home", map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rocket::ignite()
|
||||||
|
.attach(Template::fairing())
|
||||||
|
.mount("/", routes![get_file, upload_file, root, login, up])
|
||||||
|
.launch();
|
||||||
|
}
|
23
templates/home.html.hbs
Normal file
23
templates/home.html.hbs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="vstack gap-3">
|
||||||
|
<div class="bg-light border rounded-3 p-2">
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<form class='form-inline' action="/login" method="post" id = "login-form" enctype="application/x-ww-form-urlencoded">
|
||||||
|
<div class="input-group mb-3 flex-nowrap col-sm-6">
|
||||||
|
<input type="password" class="form-control" id="key" name="key" placeholder = "Enter Key"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("login").addEventListener("keyup", function (event) { if (event.keyCode == 13) { document.getElementById("login-form").submit(); }});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
templates/up.html.hbs
Normal file
21
templates/up.html.hbs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="vstack gap-3">
|
||||||
|
<div class="bg-light border rounded-3 p-2">
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="file" id="file" name="upload" onchange="this.form.submit()" hidden/>
|
||||||
|
</form>
|
||||||
|
<button class="btn btn-outline-success text-start col-sm-1 ms-1 me-1" onclick="document.getElementById('file').click()">
|
||||||
|
<i class="bi bi-file-earmark-plus"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user