diff --git a/Makefile b/Makefile index 57c0df9..fa3f58c 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,9 @@ docker-stop: docker ps -aq --filter "name=chhoto-url" | xargs -r docker rm docker-test: docker-local docker-stop - docker run -p 4567:4567 --name chhoto-url -e password="${PASSWORD}" -d chhoto-url + docker run -p 4567:4567 --name chhoto-url -e password="${PASSWORD}" -e public_mode="${PUBLIC_MODE}" \ + -e site_url="${SITE_URL}" -e db_url="${DB_URL}" -e redirect_method="${REDIRECT_METHOD}" \ + -e slug_style="${SLUG_STYLE}" -e slug_length="${SLUG_LENGTH}" -d chhoto-url docker logs chhoto-url -f docker-dev: build-dev diff --git a/README.md b/README.md index a75aec6..b5fbf4c 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ for small. URL means, well... URL. So the name simply means Small URL. - Counts number of hits for each short link in a privacy respecting way i.e. only the hit is recorded, and nothing else. - Has a mobile friendly UI. +- Has a public mode, where anyone can add links without authentication. Deleting + or listing available links will need admin access using the password. - Allows setting the URL of your website, in case you want to conveniently generate short links locally. - Links are stored in an SQLite database. @@ -128,6 +130,9 @@ default, the auto-generated links are adjective-name pairs. You can use UIDs by the `slug_style` variable to `UID`. You can also set the length of those slug by setting the `slug_length` variable. It defaults to 8, and a minimum of 4 is supported. +To enable public mode, set `public_mode` to `Enable`. With this, anyone will be able to add +links. Listing existing links or deleting links will need admin access using the password. + ## Instructions for CLI usage The application can be used from the terminal using something like `curl`. In all the examples below, replace `http://localhost:4567` with where your instance of `chhoto-url` is accessible. diff --git a/actix/src/main.rs b/actix/src/main.rs index 8291c89..4b8b56f 100644 --- a/actix/src/main.rs +++ b/actix/src/main.rs @@ -30,7 +30,7 @@ const VERSION: &str = env!("CARGO_PKG_VERSION"); // Add new links #[post("/api/new")] async fn add_link(req: String, data: web::Data, session: Session) -> HttpResponse { - if auth::validate(session) { + if env::var("public_mode") == Ok(String::from("Enable")) || auth::validate(session) { let out = utils::add_link(req, &data.db); if out.0 { HttpResponse::Created().body(out.1) @@ -48,19 +48,20 @@ async fn getall(data: web::Data, session: Session) -> HttpResponse { if auth::validate(session) { HttpResponse::Ok().body(utils::getall(&data.db)) } else { - HttpResponse::Unauthorized().body("Not logged in!") + let body = if env::var("public_mode") == Ok(String::from("Enable")) { + "Using public mode." + } else { + "Not logged in!" + }; + HttpResponse::Unauthorized().body(body) } } // Get the site URL #[get("/api/siteurl")] -async fn siteurl(session: Session) -> HttpResponse { - if auth::validate(session) { - let site_url = env::var("site_url").unwrap_or(String::from("unset")); - HttpResponse::Ok().body(site_url) - } else { - HttpResponse::Unauthorized().body("Not logged in!") - } +async fn siteurl() -> HttpResponse { + let site_url = env::var("site_url").unwrap_or(String::from("unset")); + HttpResponse::Ok().body(site_url) } // Get the version number @@ -116,6 +117,16 @@ async fn login(req: String, session: Session) -> HttpResponse { HttpResponse::Ok().body("Correct password!") } +// Handle logout +#[delete("/api/logout")] +async fn logout(session: Session) -> HttpResponse { + if session.remove("chhoto-url-auth").is_some() { + HttpResponse::Ok().body("Logged out!") + } else { + HttpResponse::Unauthorized().body("You don't seem to be logged in.") + } +} + // Delete a given shortlink #[delete("/api/del/{shortlink}")] async fn delete_link( @@ -168,6 +179,7 @@ async fn main() -> Result<()> { .service(add_link) .service(delete_link) .service(login) + .service(logout) .service(Files::new("/", "./resources/").index_file("index.html")) .default_service(web::get().to(error404)) }) diff --git a/compose.yaml b/compose.yaml index e9ea700..12bdf21 100644 --- a/compose.yaml +++ b/compose.yaml @@ -31,6 +31,10 @@ services: # The length is 8 by default, and a minimum of 4 is allowed # - slug_style=Pair # - slug_length=8 + + # In case you want to provide public access to adding links (and not + # delete, or listing), change the following option to Enable + # - public_mode=Disable volumes: - db:/urls.sqlite networks: diff --git a/resources/index.html b/resources/index.html index e4b0bed..43e28c1 100644 --- a/resources/index.html +++ b/resources/index.html @@ -47,7 +47,7 @@ -

Loading links table...

+

Loading links table...


@@ -65,7 +65,9 @@
Active links
-
+
+ login +   diff --git a/resources/static/script.js b/resources/static/script.js index 7d4a79c..a7d996b 100644 --- a/resources/static/script.js +++ b/resources/static/script.js @@ -26,14 +26,32 @@ const getVersion = async () => { return ver; } +const showVersion = async () => { + let version = await getVersion(); + link = document.getElementById("version-number"); + link.innerText = "v" + version; + link.href = "https://github.com/SinTan1729/chhoto-url/releases/tag/" + version; + link.hidden = false; +} + +const getLogin = async () => { + document.getElementById("container").style.filter = "blur(2px)"; + document.getElementById("login-dialog").showModal(); + document.getElementById("password").focus(); +} + const refreshData = async () => { let res = await fetch(prepSubdir("/api/all")); if (!res.ok) { let errorMsg = await res.text(); console.log(errorMsg); - document.getElementById("container").style.filter = "blur(2px)"; - document.getElementById("login-dialog").showModal(); - document.getElementById("password").focus(); + if (errorMsg == "Using public mode.") { + loading_text = document.getElementById("loading-text"); + loading_text.style.display = "none"; + showVersion(); + } else { + getLogin(); + } } else { let data = await res.json(); displayData(data); @@ -41,16 +59,14 @@ const refreshData = async () => { } const displayData = async (data) => { - let version = await getVersion(); - link = document.getElementById("version-number") - link.innerText = "v" + version; - link.href = "https://github.com/SinTan1729/chhoto-url/releases/tag/" + version; - link.hidden = false; - + showVersion(); let site = await getSiteUrl(); + admin_button = document.getElementById("admin-button"); + admin_button.innerText = "logout"; + admin_button.href = "javascript:logOut()"; table_box = document.querySelector(".pure-table"); - loading_text = document.getElementsByName("loading-text")[0]; + loading_text = document.getElementById("loading-text"); if (data.length == 0) { table_box.style.visibility = "hidden"; @@ -221,6 +237,12 @@ const submitLogin = () => { }) } +const logOut = async () => { + let reply = await fetch(prepSubdir("/api/logout"), {method: "DELETE"}).then(res => res.text()); + console.log(reply); + location.reload(); +} + (async () => { await refreshData(); diff --git a/resources/static/styles.css b/resources/static/styles.css index 55fae0a..2ba0579 100644 --- a/resources/static/styles.css +++ b/resources/static/styles.css @@ -65,7 +65,7 @@ form input[name="shortUrl"]::placeholder { text-transform: none; } -div[name="github-link"] { +div[name="links-div"] { position: absolute; right: 0.5%; top: 0.5%;