1
0
Fork 0
mirror of https://github.com/SinTan1729/chhoto-url synced 2025-04-30 21:06:51 -05:00

Compare commits

..

No commits in common. "main" and "5.7.0" have entirely different histories.
main ... 5.7.0

6 changed files with 40 additions and 44 deletions

View file

@ -38,9 +38,9 @@ for small. URL means, well... URL. So the name simply means Small URL.
# Features # Features
- Shortens URLs of any length to a randomly generated link. - Shortens URLs of any length to a randomly generated link.
- (Optional) Allows you to specify the shortened URL instead of the generated - (Optional) Allows you to specify the shortened URL instead of the generated
one. (It's missing in a surprising number of alternatives.) one. (It's surprisingly missing in a surprising number of alternatives.)
- Opening the shortened URL in your browser will instantly redirect you - Opening the shortened URL in your browser will instantly redirect you
to the correct long URL. (So no stupid redirection pages.) to the correct long URL. (So no stupid redirecting pages.)
- Super lightweight and snappy. (The docker image is only ~6MB and RAM uasge - Super lightweight and snappy. (The docker image is only ~6MB and RAM uasge
stays under 5MB under normal use.) stays under 5MB under normal use.)
- Counts number of hits for each short link in a privacy respecting way - Counts number of hits for each short link in a privacy respecting way
@ -52,8 +52,8 @@ for small. URL means, well... URL. So the name simply means Small URL.
- Allows setting the URL of your website, in case you want to conveniently - Allows setting the URL of your website, in case you want to conveniently
generate short links locally. generate short links locally.
- Links are stored in an SQLite database. - Links are stored in an SQLite database.
- Available as a Docker container with a provided compose file. - Available as a Docker container.
- Backend written in Rust using [Actix](https://actix.rs/), and frontend - Backend written in Rust using [Actix](https://actix.rs/), frontend
written in plain HTML and vanilla JS, using [Pure CSS](https://purecss.io/) written in plain HTML and vanilla JS, using [Pure CSS](https://purecss.io/)
for styling. for styling.
- Uses very basic authentication using a provided password. It's not encrypted in transport. - Uses very basic authentication using a provided password. It's not encrypted in transport.
@ -61,16 +61,17 @@ for small. URL means, well... URL. So the name simply means Small URL.
encrypt the connection by SSL. encrypt the connection by SSL.
# Bloat that will not be implemented # Bloat that will not be implemented
- **Tracking or spying of any kind.** The only logs that still exist are - Tracking or spying of any kind. The only logs that still exist are
errors printed to stderr and the basic logging (only warnings) provided by the errors printed to stderr and the basic logging (only warnings) provided by the
[`env_logger`](https://crates.io/crates/env_logger) crate. [`env_logger`](https://crates.io/crates/env_logger) crate.
- **User management.** If you need a shortener for your whole organization, either - User management. If you need a shortener for your whole organization, either
run separate containers for everyone or use something else. run separate containers for everyone or use something else.
- **Cookies, newsletters**, "we value your privacy" popups or any of the multiple - Cookies, newsletters, "we value your privacy" popups or any of the multiple
other ways modern web shows how anti-user it is. We all hate those, and they're other ways modern web shows how anti-user it is. We all hate those, and they're
not needed here. not needed here.
- **Paywalls** or messages begging for donations. If you want to buy me a coffee, - Paywalls or messages begging for donations. If you want to support me (for
you can message me through GitHub discussions or mail me. whatever reason), you can message me through GitHub issues.
# Screenshots # Screenshots
<p align="middle"> <p align="middle">
<img src="screenshot-desktop.webp" height="250" alt="desktop screenshot" /> <img src="screenshot-desktop.webp" height="250" alt="desktop screenshot" />

26
actix/Cargo.lock generated
View file

@ -31,7 +31,7 @@ dependencies = [
"actix-web", "actix-web",
"bitflags", "bitflags",
"bytes", "bytes",
"derive_more 0.99.20", "derive_more 0.99.19",
"futures-core", "futures-core",
"http-range", "http-range",
"log", "log",
@ -458,7 +458,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chhoto-url" name = "chhoto-url"
version = "5.7.1" version = "5.7.0"
dependencies = [ dependencies = [
"actix-files", "actix-files",
"actix-session", "actix-session",
@ -562,9 +562,9 @@ dependencies = [
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "0.99.20" version = "0.99.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"proc-macro2", "proc-macro2",
@ -760,9 +760,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.16" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -1059,9 +1059,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]] [[package]]
name = "jiff" name = "jiff"
version = "0.2.10" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6" checksum = "59ec30f7142be6fe14e1b021f50b85db8df2d4324ea6e91ec3e5dcde092021d0"
dependencies = [ dependencies = [
"jiff-static", "jiff-static",
"log", "log",
@ -1072,9 +1072,9 @@ dependencies = [
[[package]] [[package]]
name = "jiff-static" name = "jiff-static"
version = "0.2.10" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254" checksum = "526b834d727fd59d37b076b0c3236d9adde1b1729a4361e20b2026f738cc1dbe"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1407,7 +1407,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [ dependencies = [
"getrandom 0.2.16", "getrandom 0.2.15",
] ]
[[package]] [[package]]
@ -1741,9 +1741,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.15" version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",

View file

@ -3,7 +3,7 @@
[package] [package]
name = "chhoto-url" name = "chhoto-url"
version = "5.7.1" version = "5.7.0"
edition = "2021" edition = "2021"
authors = ["Sayantan Santra <sayantan[dot]santra689[at]gmail[dot]com"] authors = ["Sayantan Santra <sayantan[dot]santra689[at]gmail[dot]com"]
license = "mit" license = "mit"

View file

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2023 Sayantan Santra <sayantan.santra689@gmail.com> // SPDX-FileCopyrightText: 2023 Sayantan Santra <sayantan.santra689@gmail.com>
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use rusqlite::{Connection, Error}; use rusqlite::Connection;
use serde::Serialize; use serde::Serialize;
// Struct for encoding a DB row // Struct for encoding a DB row
@ -67,11 +67,12 @@ pub fn add_hit(shortlink: &str, db: &Connection) {
} }
// Insert a new link // Insert a new link
pub fn add_link(shortlink: String, longlink: String, db: &Connection) -> Result<usize, Error> { pub fn add_link(shortlink: String, longlink: String, db: &Connection) -> bool {
db.execute( db.execute(
"INSERT INTO urls (long_url, short_url, hits) VALUES (?1, ?2, ?3)", "INSERT INTO urls (long_url, short_url, hits) VALUES (?1, ?2, ?3)",
(longlink, shortlink, 0), (longlink, shortlink, 0),
) )
.is_ok()
} }
// Delete and existing link // Delete and existing link

View file

@ -63,9 +63,15 @@ async fn main() -> Result<()> {
// Set the site_url without the quotes // Set the site_url without the quotes
env::set_var("site_url", url); env::set_var("site_url", url);
eprintln!("WARN: The site_url environment variable is encapsulated by quotes. Automatically adjusting to {}", url); eprintln!("WARN: The site_url environment variable is encapsulated by quotes. Automatically adjusting to {}", url);
// Tell the user what URI the server will respond with
eprintln!("INFO: Public URI is: {url}:{port}.")
} else { } else {
// No issues // No issues
eprintln!("INFO: Configured Site URL is: {site_url}."); eprintln!("INFO: Configured Site URL is: {site_url}.");
// Tell the user what URI the server will respond with
eprintln!("INFO: Public URI is: {site_url}:{port}.")
} }
} else { } else {
// Site URL is not configured // Site URL is not configured

View file

@ -6,7 +6,7 @@ use actix_web::HttpRequest;
use nanoid::nanoid; use nanoid::nanoid;
use rand::seq::IndexedRandom; use rand::seq::IndexedRandom;
use regex::Regex; use regex::Regex;
use rusqlite::{ffi::SQLITE_CONSTRAINT_UNIQUE, Connection}; use rusqlite::Connection;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::env; use std::env;
@ -123,27 +123,15 @@ pub fn add_link(req: String, db: &Connection) -> (bool, String) {
len = 4; len = 4;
} }
let shortlink_provided = if chunks.shortlink.is_empty() { if chunks.shortlink.is_empty() {
chunks.shortlink = gen_link(style, len); chunks.shortlink = gen_link(style, len);
false }
} else {
true
};
if validate_link(chunks.shortlink.as_str()) { if validate_link(chunks.shortlink.as_str()) {
match database::add_link(chunks.shortlink.clone(), chunks.longlink, db) { if database::add_link(chunks.shortlink.clone(), chunks.longlink, db) {
Ok(_) => (true, chunks.shortlink), (true, chunks.shortlink)
Err(error) => { } else {
if error.sqlite_error().map(|err| err.extended_code) (false, String::from("Short URL is already in use!"))
== Some(SQLITE_CONSTRAINT_UNIQUE)
&& shortlink_provided
{
(false, String::from("Short URL is already in use!"))
} else {
// This should be super rare
(false, String::from("Something went wrong!"))
}
}
} }
} else { } else {
(false, String::from("Short URL is not valid!")) (false, String::from("Short URL is not valid!"))