1 Commits

Author SHA1 Message Date
892787f3be add: LICENSE
Signed-off-by: prashantrahul141 <prashantrahul141@protonmail.com>
2025-11-11 22:55:01 +05:30
8 changed files with 131 additions and 487 deletions

230
Cargo.lock generated
View File

@@ -2,32 +2,17 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "axum"
version = "0.8.7"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871"
dependencies = [
"axum-core",
"bytes",
@@ -82,27 +67,11 @@ version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytes"
version = "1.11.0"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "cc"
version = "1.2.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36"
dependencies = [
"find-msvc-tools",
"shlex",
]
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
@@ -110,25 +79,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chrono"
version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "encoding_rs"
version = "0.8.35"
@@ -138,12 +88,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
[[package]]
name = "fnv"
version = "1.0.7"
@@ -271,9 +215,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.8.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
dependencies = [
"atomic-waker",
"bytes",
@@ -292,9 +236,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.18"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
dependencies = [
"bytes",
"futures-core",
@@ -306,46 +250,12 @@ dependencies = [
"tower-service",
]
[[package]]
name = "iana-time-zone"
version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.177"
@@ -423,15 +333,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@@ -550,12 +451,6 @@ dependencies = [
"bitflags",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "ryu"
version = "1.0.20"
@@ -633,12 +528,6 @@ dependencies = [
"serde",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
@@ -678,9 +567,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "syn"
version = "2.0.110"
version = "2.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f"
dependencies = [
"proc-macro2",
"quote",
@@ -815,110 +704,12 @@ dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
@@ -1013,7 +804,6 @@ name = "yamaf"
version = "0.1.0"
dependencies = [
"axum",
"chrono",
"futures-util",
"mime_guess",
"rand",

View File

@@ -7,12 +7,8 @@ edition = "2024"
[dependencies]
axum = { version = "0.8.6", features = ["multipart"] }
chrono = "*"
futures-util = "0.3.31"
mime_guess= "*"
rand = "*"
tokio = { version = "1.48.0", features = ["full"] }
tokio-util = { version = "0.7.17", features = ["io"] }
[features]
cleanup = []

23
LICENSE
View File

@@ -1,14 +1,15 @@
Marvel Rivals License Revision 2
(c) Amneesh Singh, 2025
Marvel Rivals License Revision 1
(c) Author, year
Permission to use, copy, distribute, sell, or modify the compiled binaries,
source code, and documentation (the "Software") is granted only to individuals
who currently hold a higher competitive matchmaking rank in Marvel Rivals
(NetEase / Marvel Games) than the copyright holder.
Permission is hereby granted, free of charge, for anyone to use, distribute, or
sell the compiled binaries, source code, and documentation (the "Software")
without attribution.
All others are expressly prohibited from using, copying, distributing, selling,
or modifying the Software in any form.
The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. The authors
are NOT LIABLE FOR ANY LOSS, DAMAGE, OR MISUSE arising from its use.
Permission to modify the Software is only granted to those that have a higher
competitive matchmaking rank than the copyright holder in Marvel Rivals
(NetEase, 2024).
The Software is provided in the hope that some will find it useful, but the
Software comes under NO WARRANTY, EXPRESS OR IMPLIED, and the authors of the
Software are NOT LIABLE IN THE EVENT OF LOSSES, DAMAGES OR MISUSE relating to
the Software.

View File

@@ -19,18 +19,6 @@
| EXTERNAL_HAS_TLS | URLs in html have https if set, otherwise http | - |
| MAX_FILES | This does not actually limit the number of files, and used to calculate bodysize | 10 |
| MAX_FILESIZE_MB | Determines the max filesize possible, used to return failure and calculate bodysize | 100M |
| MIN_FILEDAYS | Minimum number of days for file retention | 30 days |
| MAX_FILEDAYS | Maximum number of days for file retention | 365 days |
** Retention
File retention is as per the following formula
#+begin_src text
retention = min_days + (max_days - min_days) * (1 - file_size / max_size) ^ e
#+end_src
Cleanup happens everyday when midnight (IST) has passed
[fn:1] https://git.weirdnatto.in/natto1784/simple-filehost/

View File

@@ -47,14 +47,17 @@
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
yamaf = pkgs.callPackage ./nix/yamaf.nix {
inherit craneLib lib src;
};
yamaf = craneLib.buildPackage (
commonArgs
// {
inherit cargoArtifacts;
doCheck = false;
}
);
in
{
packages = {
inherit yamaf;
yamaf-all = yamaf.override { withCleanup = true; };
default = yamaf;
image = pkgs.dockerTools.buildImage {
name = "yamaf";

View File

@@ -1,15 +0,0 @@
{
craneLib,
lib,
src,
withCleanup ? false,
}:
let
cargoArtifacts = craneLib.buildDepsOnly { inherit src; };
in
craneLib.buildPackage {
inherit cargoArtifacts src;
doCheck = false;
cargoExtraArgs = lib.optionalString withCleanup "--features cleanup";
}

View File

@@ -5,7 +5,6 @@
</head>
<body>
<h1>{{TITLE}}</h1>
<p>
Use curl to upload:
<br>
@@ -22,24 +21,11 @@
curl -F "key=[key]" -F file=@"[file]" -F file=@"[file2]" {{USER_URL}}
</code>
</p>
<form method="post" enctype="multipart/form-data">
{{KEY_FIELD}}
<input type="file" name="file" multiple>
<br>
<button type="submit">Upload</button>
</form>
<!-- CLEANUP_START -->
<h4>Cleanup</h4>
File retention is as per the following formula
<pre><code>
max_size = {{MAX_SIZE}} // in megabytes
max_days = {{MAX_DAYS}}
min_days = {{MIN_DAYS}}
retention = min_days + (max_days - min_days) * (1 - file_size / max_size) ^ e
</code></pre>
Cleanup happens everyday when midnight (IST) has passed
<!-- CLEANUP_END -->
<div id="progress-container"></div>
</html>

View File

@@ -6,10 +6,11 @@ use axum::{
response::{Html, IntoResponse, Response},
routing::get,
};
use rand::{Rng, distr::Alphanumeric};
use std::{env, net::SocketAddr, sync::LazyLock};
use std::{env::VarError, path::PathBuf};
use tokio::fs;
use tokio::fs::File;
use tokio_util::io::ReaderStream;
struct Config {
@@ -22,14 +23,12 @@ struct Config {
external_protocol: &'static str,
max_filesize: usize,
max_bodysize: usize,
min_filedays: usize,
max_filedays: usize,
}
static CONFIG: LazyLock<Config> = LazyLock::new(|| {
let root_dir = env::var("ROOT_DIR").unwrap_or_else(|_| "/var/files".to_string());
let key = env::var("KEY");
let title = env::var("TITLE").unwrap_or_else(|_| "Yet Another Mid Ahh Filehost".to_string());
let title = env::var("TITLE").unwrap_or_else(|_| "Simpler Filehost".to_string());
let internal_host = env::var("INTERNAL_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
let internal_port = env::var("INTERNAL_PORT")
@@ -55,18 +54,6 @@ static CONFIG: LazyLock<Config> = LazyLock::new(|| {
<< 20;
let max_bodysize = max_files * max_filesize * 2;
let min_filedays = env::var("MIN_FILEDAYS")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(30);
let max_filedays = env::var("MAX_FILEDAYS")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(365);
assert!(max_filedays >= min_filedays);
Config {
root_dir,
key,
@@ -77,8 +64,6 @@ static CONFIG: LazyLock<Config> = LazyLock::new(|| {
external_protocol,
max_filesize,
max_bodysize,
min_filedays,
max_filedays,
}
});
@@ -101,35 +86,6 @@ async fn main() {
addr, CONFIG.root_dir
);
/* cleanup cronjob */
#[cfg(feature = "cleanup")]
tokio::spawn(async move {
use chrono::{Local, NaiveDate};
let mut last_cleanup_day: NaiveDate = Local::now().date_naive();
loop {
use tokio::time::{Duration, sleep};
/* every 30 minutes */
sleep(Duration::from_secs(30 * 60)).await;
let now = Local::now();
let today = now.date_naive();
/* if the date changed, midnight has passed */
if today > last_cleanup_day {
println!("attempting cleanup at {}", now.to_string());
if let Err(e) = cleanup_directory().await {
eprintln!("cleanup failed: {}", e);
} else {
println!("cleanup succeeded!");
last_cleanup_day = today;
}
}
}
});
axum::serve(listener, app).await.unwrap();
}
@@ -152,19 +108,6 @@ static INDEX_HTML: LazyLock<String> = LazyLock::new(|| {
},
);
if cfg!(feature = "cleanup") {
html = html
.replace("{{MAX_SIZE}}", &(CONFIG.max_filesize >> 20).to_string())
.replace("{{MAX_DAYS}}", &CONFIG.max_filedays.to_string())
.replace("{{MIN_DAYS}}", &CONFIG.min_filedays.to_string());
} else {
if let Some(start) = html.find("<!-- CLEANUP_START -->") {
if let Some(end) = html.find("<!-- CLEANUP_END -->") {
html.replace_range(start..end + "<!-- CLEANUP_END -->".len(), "");
}
}
}
html
});
@@ -210,7 +153,10 @@ fn clean_filename(filename: &str) -> String {
let mut prev_dash = false;
for c in filename.to_lowercase().chars() {
if c.is_ascii_alphanumeric() || c == '.' {
if c.is_ascii_alphanumeric() {
slug.push(c);
prev_dash = false;
} else if c == '.' {
slug.push(c);
prev_dash = false;
} else if !prev_dash {
@@ -222,21 +168,14 @@ fn clean_filename(filename: &str) -> String {
slug.trim_matches('-').to_string()
}
async fn upload(
headers: HeaderMap,
mut payload: Multipart,
) -> Result<impl IntoResponse, YamafError> {
async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError> {
let mut responses = Vec::new();
let mut found_key = false;
let wants_html = headers
.get("accept")
.and_then(|h| h.to_str().ok())
.map(|a| a.contains("text/html"))
.unwrap_or(false);
while let Some(mut field) = payload.next_field().await.unwrap() {
match field.name() {
Some("key") => {
if let Ok(ref key) = CONFIG.key {
if let Some(field) = payload.next_field().await.unwrap() {
if field.name() == Some("key") {
let bytes = field
.bytes()
.await
@@ -248,16 +187,16 @@ async fn upload(
if s != *key {
return Err(YamafError::BadRequest("Wrong key".into()));
}
} else {
return Err(YamafError::BadRequest("Missing key".into()));
}
} else {
return Err(YamafError::BadRequest("Missing key".into()));
found_key = true;
}
}
while let Some(mut field) = payload.next_field().await.unwrap() {
if field.name() == Some("file") {
Some("file") => {
if CONFIG.key.is_ok() && found_key == false {
return Err(YamafError::BadRequest("Missing key".into()));
}
let filename = field
.file_name()
.map_or(format!("{}-upload", random(10)), |filename| {
@@ -266,7 +205,7 @@ async fn upload(
let save_path = std::path::Path::new(&CONFIG.root_dir).join(&filename);
let mut file = fs::File::create(&save_path)
let mut file = File::create(&save_path)
.await
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
@@ -284,7 +223,7 @@ async fn upload(
.ok_or_else(|| YamafError::BadRequest("File too large".into()))?;
if written > CONFIG.max_filesize {
_ = fs::remove_file(&save_path).await;
_ = tokio::fs::remove_file(&save_path).await;
return Err(YamafError::FileTooBig(filename));
}
@@ -294,22 +233,16 @@ async fn upload(
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
}
let url = format!(
"{proto}://{host}/{file}",
responses.push(format!(
r#"<a href="{proto}://{host}/{file}">{proto}://{host}/{file}</a> (size ~ {size:.2}k)"#,
proto = CONFIG.external_protocol,
host = CONFIG.external_host,
file = filename,
);
if wants_html {
responses.push(format!(
r#"<a href="{url}">{url}</a> (size ~ {size:.2}k)"#,
url = url,
size = written as f64 / 1024.0,
size = written as f64 / 1024 as f64
));
} else {
responses.push(url);
}
None | Some(_) => {}
}
}
@@ -317,24 +250,20 @@ async fn upload(
return Err(YamafError::BadRequest("No files uploaded".into()));
}
if wants_html {
Ok(Html(format!(
"Here are your file(s):<br>{}",
responses.join("<br>")
))
.into_response())
} else {
Ok(responses.join("\n").into_response())
}
}
async fn serve_file(Path(filename): Path<String>) -> Result<impl IntoResponse, YamafError> {
let path = PathBuf::from(&CONFIG.root_dir).join(&filename);
let metadata = fs::metadata(&path)
let metadata = tokio::fs::metadata(&path)
.await
.map_err(|_| YamafError::FileNotFound)?;
let file = fs::File::open(&path)
let file = File::open(&path)
.await
.map_err(|_| YamafError::FileNotFound)?;
let mime = mime_guess::from_path(&path).first_or_octet_stream();
@@ -360,37 +289,3 @@ async fn serve_file(Path(filename): Path<String>) -> Result<impl IntoResponse, Y
Ok((StatusCode::OK, headers, body).into_response())
}
#[cfg(feature = "cleanup")]
async fn cleanup_directory() -> Result<(), std::io::Error> {
let dir = std::path::Path::new(&CONFIG.root_dir);
let mut entries = fs::read_dir(dir).await?;
while let Some(entry) = entries.next_entry().await? {
use std::os::unix::fs::MetadataExt;
use std::time::SystemTime;
let path = entry.path();
let meta = entry.metadata().await?;
let modified = meta.modified().unwrap_or(SystemTime::UNIX_EPOCH);
let age = SystemTime::now()
.duration_since(modified)
.unwrap_or_default();
/* min_days + (max_days - min_days) * (1 - size/max_size)^e */
let retention = (CONFIG.min_filedays as f64
+ (CONFIG.max_filedays - CONFIG.min_filedays) as f64
* (1.0 - (meta.size() as f64 / CONFIG.max_filesize as f64))
.powf(std::f64::consts::E))
* 24.0
* 60.0
* 60.0;
if meta.is_file() && age.as_secs_f64() > retention {
fs::remove_file(&path).await?;
println!("Deleted {:?}", path);
}
}
Ok(())
}