Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom URL support #253

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ export MICROBIN_GC_DAYS=90
# Default value: false
export MICROBIN_ENABLE_BURN_AFTER=true

# Enables or disables the "Custom Url" function
# Default value: false
export MICROBIN_ENABLE_CUSTOM_URL=true

# Sets the default burn after setting on the main screen.
# Default value: 0. Available expiration options: 1, 10,
# 100, 1000, 10000, 0 (= no limit)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ On our website [microbin.eu](https://microbin.eu) you will find the following:
- QR code support
- URL shortening and redirection
- Animal names instead of random numbers for upload identifiers (64 animals)
- Custom URL
- SQLite and JSON database support
- Private and public, editable and uneditable, automatically and never expiring uploads
- Automatic dark mode and custom styling support with very little CSS and only vanilla JS (see [`water.css`](https://github.com/kognise/water.css))
Expand Down
1 change: 1 addition & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ services:
MICROBIN_THREADS: ${MICROBIN_THREADS}
MICROBIN_GC_DAYS: ${MICROBIN_GC_DAYS}
MICROBIN_ENABLE_BURN_AFTER: ${MICROBIN_ENABLE_BURN_AFTER}
MICROBIN_ENABLE_CUSTOM_URL: ${MICROBIN_ENABLE_CUSTOM_URL}
MICROBIN_DEFAULT_BURN_AFTER: ${MICROBIN_DEFAULT_BURN_AFTER}
MICROBIN_WIDE: ${MICROBIN_WIDE}
MICROBIN_QR: ${MICROBIN_QR}
Expand Down
6 changes: 5 additions & 1 deletion src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ pub struct Args {
#[clap(long, env = "MICROBIN_ENABLE_READONLY")]
pub enable_readonly: bool,

#[clap(long, env = "MICROBIN_ENABLE_CUSTOM_URL")]
pub enable_custom_url: bool,

#[clap(long, env = "MICROBIN_DEFAULT_EXPIRY", default_value = "24hour")]
pub default_expiry: String,

Expand All @@ -114,7 +117,7 @@ pub struct Args {

#[clap(long, env = "MICROBIN_CUSTOM_CSS")]
pub custom_css: Option<String>,

#[clap(long, env = "MICROBIN_HASH_IDS")]
pub hash_ids: bool,

Expand Down Expand Up @@ -211,6 +214,7 @@ impl Args {
max_file_size_encrypted_mb: self.max_file_size_encrypted_mb,
max_file_size_unencrypted_mb: self.max_file_size_unencrypted_mb,
disable_update_checking: self.disable_update_checking,
enable_custom_url: self.enable_custom_url,
}
}
}
Expand Down
83 changes: 21 additions & 62 deletions src/endpoints/auth_upload.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::args::{Args, ARGS};
use crate::endpoints::errors::ErrorTemplate;
use crate::util::animalnumbers::to_u64;
use crate::util::hashids::to_u64 as hashid_to_u64;
use crate::util::hashids::alias_comparator;
use crate::util::misc::remove_expired;
use crate::AppState;
use actix_web::{get, web, HttpResponse};
Expand All @@ -25,14 +24,10 @@ pub async fn auth_upload(data: web::Data<AppState>, id: web::Path<String>) -> Ht

remove_expired(&mut pastas);

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_i, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -65,14 +60,10 @@ pub async fn auth_upload_with_status(

let (id, status) = param.into_inner();

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_i, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -100,14 +91,10 @@ pub async fn auth_raw_pasta(data: web::Data<AppState>, id: web::Path<String>) ->

remove_expired(&mut pastas);

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_i, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -140,14 +127,10 @@ pub async fn auth_raw_pasta_with_status(

let (id, status) = param.into_inner();

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_i, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -175,14 +158,10 @@ pub async fn auth_edit_private(data: web::Data<AppState>, id: web::Path<String>)

remove_expired(&mut pastas);

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -215,14 +194,10 @@ pub async fn auth_edit_private_with_status(

let (id, status) = param.into_inner();

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_i, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -250,14 +225,10 @@ pub async fn auth_file(data: web::Data<AppState>, id: web::Path<String>) -> Http

remove_expired(&mut pastas);

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -290,14 +261,10 @@ pub async fn auth_file_with_status(

let (id, status) = param.into_inner();

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_i, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -325,14 +292,10 @@ pub async fn auth_remove_private(data: web::Data<AppState>, id: web::Path<String

remove_expired(&mut pastas);

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down Expand Up @@ -365,14 +328,10 @@ pub async fn auth_remove_private_with_status(

let (id, status) = param.into_inner();

let intern_id = if ARGS.hash_ids {
hashid_to_u64(&id).unwrap_or(0)
} else {
to_u64(&id).unwrap_or(0)
};
let comparator = alias_comparator(id.as_str());

for (_i, pasta) in pastas.iter().enumerate() {
if pasta.id == intern_id {
if comparator(pasta) {
return HttpResponse::Ok().content_type("text/html").body(
AuthPasta {
args: &ARGS,
Expand Down
34 changes: 33 additions & 1 deletion src/endpoints/create.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::pasta::PastaFile;
use crate::util::animalnumbers::to_animal_names;
use crate::util::animalnumbers::to_u64;
use crate::util::db::insert;
use crate::util::hashids::to_hashids;
use crate::util::hashids::to_u64 as hashid_to_u64;
use crate::util::misc::{encrypt, encrypt_file, is_valid_url};
use crate::{AppState, Pasta, ARGS};
use actix_multipart::Multipart;
use actix_web::error::ErrorBadRequest;
use actix_web::error::ErrorForbidden;
use actix_web::{get, web, Error, HttpResponse, Responder};
use askama::Template;
use bytesize::ByteSize;
Expand Down Expand Up @@ -88,6 +91,7 @@ pub async fn create(
id: rand::thread_rng().gen::<u16>() as u64,
content: String::from(""),
file: None,
custom_alias: None,
extension: String::from(""),
private: false,
readonly: false,
Expand Down Expand Up @@ -207,6 +211,31 @@ pub async fn create(
}
continue;
}
"custom_alias" => {
if !ARGS.enable_custom_url {
continue;
}
while let Some(chunk) = field.try_next().await? {
let custom_alias_unchecked =
std::str::from_utf8(&chunk).unwrap().trim().to_string();
// todo check it
if hashid_to_u64(&custom_alias_unchecked).is_ok()
|| to_u64(&&custom_alias_unchecked).is_ok()
{
// prevent conflicts with default url.
return Err(ErrorForbidden("Conflicts with default URL format"));
}
if pastas
.iter()
.any(|pasta| pasta.custom_alias.as_ref() == Some(&custom_alias_unchecked))
{
// prevent conflicts with default url.
return Err(ErrorForbidden("Custom url conflicts with existing pasta"));
}
new_pasta.custom_alias = Some(custom_alias_unchecked);
}
continue;
}
"file" => {
if ARGS.no_file_upload {
continue;
Expand Down Expand Up @@ -303,6 +332,7 @@ pub async fn create(
}

let encrypt_server = new_pasta.encrypt_server;
let alias = new_pasta.custom_alias.clone();

pastas.push(new_pasta);

Expand All @@ -312,7 +342,9 @@ pub async fn create(
}
}

let slug = if ARGS.hash_ids {
let slug = if let Some(alias) = alias {
alias
} else if ARGS.hash_ids {
to_hashids(id)
} else {
to_animal_names(id)
Expand Down