mirror of
https://github.com/ivabus/aliurl
synced 2024-11-21 22:25:06 +03:00
Initial commit
This commit is contained in:
commit
7a847fe028
7 changed files with 264 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/target
|
||||||
|
access_keys
|
||||||
|
alias.json
|
||||||
|
.idea
|
||||||
|
*.DS_Store
|
||||||
|
Cargo.lock
|
9
.rustfmt.toml
Normal file
9
.rustfmt.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
edition = "2021"
|
||||||
|
hard_tabs = true
|
||||||
|
merge_derives = true
|
||||||
|
reorder_imports = true
|
||||||
|
reorder_modules = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
use_small_heuristics = "Off"
|
||||||
|
wrap_comments = true
|
||||||
|
comment_width = 80
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "aliurl"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/ivabus/aliurl"
|
||||||
|
description = "Small aliaser for URLs"
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = "0.5.0-rc.3"
|
||||||
|
serde = { version = "1.0.163", features = ["derive"] }
|
||||||
|
serde_json = "1.0.96"
|
||||||
|
url-escape = "0.1.1"
|
||||||
|
uuid = { version = "1.3.3", features = ["v4"] }
|
20
LICENSE
Normal file
20
LICENSE
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Ivan Bushchik
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||||
|
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
64
README.md
Normal file
64
README.md
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# aliurl
|
||||||
|
|
||||||
|
> ALIaser for URLs
|
||||||
|
|
||||||
|
Small http service to create aliases for URLs.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/ivabus/aliurl
|
||||||
|
cd aliurl
|
||||||
|
cargo b -r
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Add your access_keys to `./access_keys` or don't add any, if you don't want to use authorization.
|
||||||
|
|
||||||
|
Edit `Rocket.toml` to set port and ip.
|
||||||
|
|
||||||
|
### Running
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo run -r
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Create new alias
|
||||||
|
|
||||||
|
#### Request
|
||||||
|
|
||||||
|
```http request
|
||||||
|
POST /post HTTP/1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Request body
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"url": "<URL_TO_BE_ALIASED>",
|
||||||
|
"alias": "<ALIAS_URI>", // If not provided, UUID will be generated
|
||||||
|
"access_key": "<ACCESS_KEY>" // May not be provided, if no ./access_keys file
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use alias
|
||||||
|
|
||||||
|
```http request
|
||||||
|
GET /<ALIAS> HTTP/1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
```http request
|
||||||
|
HTTP/1.1 303 See Other
|
||||||
|
location: <URL>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alias for `/`
|
||||||
|
|
||||||
|
Aliases for root is declared in `src/main.rs` file in `INDEX_REDIRECT` const.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The project is licensed under the terms of the [MIT license](./LICENSE).
|
11
Rocket.toml
Normal file
11
Rocket.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[release]
|
||||||
|
address = "127.0.0.1"
|
||||||
|
port = 8080
|
||||||
|
workers = 8
|
||||||
|
keep_alive = 5
|
||||||
|
ident = "Rocket"
|
||||||
|
ip_header = "X-Real-IP" # set to `false` to disable
|
||||||
|
log_level = "normal"
|
||||||
|
temp_dir = "/tmp"
|
||||||
|
cli_colors = true
|
||||||
|
ctrlc = false
|
139
src/main.rs
Normal file
139
src/main.rs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
use rocket::http::RawStr;
|
||||||
|
use rocket::http::Status;
|
||||||
|
use rocket::response::Redirect;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct CreateAliasRequest {
|
||||||
|
url: String,
|
||||||
|
access_key: Option<String>,
|
||||||
|
alias: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut ACCESS_KEY_REQUIRED: bool = true;
|
||||||
|
const INDEX_REDIRECT: &'static str = "https://ivabus.dev";
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Clone)]
|
||||||
|
struct Alias {
|
||||||
|
url: String,
|
||||||
|
alias: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_alias() -> Vec<Alias> {
|
||||||
|
if !std::path::Path::new("./alias.json").exists() {
|
||||||
|
let mut file = std::fs::File::create("./alias.json").unwrap();
|
||||||
|
file.write_all(b"[]").unwrap();
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
if std::fs::File::open("./alias.json").unwrap().metadata().unwrap().len() == 0 {
|
||||||
|
let mut file = std::fs::File::options().write(true).open("./alias.json").unwrap();
|
||||||
|
file.write_all(b"[]").unwrap();
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
let file = std::fs::File::open("./alias.json").unwrap();
|
||||||
|
let mut buf_reader = BufReader::new(file);
|
||||||
|
let mut contents = String::new();
|
||||||
|
buf_reader.read_to_string(&mut contents).unwrap();
|
||||||
|
let alias_list: Vec<Alias> = serde_json::from_str(&contents).unwrap();
|
||||||
|
alias_list
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/post", data = "<data>")]
|
||||||
|
fn create_alias(data: &RawStr) -> (Status, String) {
|
||||||
|
let data: CreateAliasRequest = match serde_json::from_str(&data.to_string()) {
|
||||||
|
Ok(req) => req,
|
||||||
|
Err(e) => return (Status::BadRequest, format!("Error: {e}")),
|
||||||
|
};
|
||||||
|
let mut file = std::fs::File::open("./access_keys").unwrap();
|
||||||
|
let mut buffer: String = String::new();
|
||||||
|
file.read_to_string(&mut buffer).unwrap();
|
||||||
|
let access_keys: Vec<&str> = buffer.split("\n").collect();
|
||||||
|
if let Some(key) = data.access_key {
|
||||||
|
if !access_keys.contains(&key.as_str()) {
|
||||||
|
return (Status::Forbidden, "Access key is invalid".to_string());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
if ACCESS_KEY_REQUIRED {
|
||||||
|
return (Status::Forbidden, "Access key needs to be provided".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut alias_list = read_alias();
|
||||||
|
let mut file = std::fs::File::options().write(true).open("./alias.json").unwrap();
|
||||||
|
let alias = match data.alias {
|
||||||
|
None => uuid::Uuid::new_v4().to_string(),
|
||||||
|
Some(alias) => alias,
|
||||||
|
};
|
||||||
|
if alias.contains("?") {
|
||||||
|
return (Status::BadRequest, format!("Error: alias should not contain '?'"));
|
||||||
|
}
|
||||||
|
alias_list.push(Alias {
|
||||||
|
url: data.url.clone(),
|
||||||
|
alias: alias.clone(),
|
||||||
|
});
|
||||||
|
alias_list.dedup_by(|a, b| a.alias == b.alias);
|
||||||
|
|
||||||
|
file.write_all(serde_json::to_string(&alias_list).unwrap().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
file.sync_all().unwrap();
|
||||||
|
return (Status::Ok, format!("Created {} at {}", data.url, alias));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/404")]
|
||||||
|
fn not_found() -> Status {
|
||||||
|
Status::NotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/<page>")]
|
||||||
|
async fn get_page(page: String) -> Redirect {
|
||||||
|
let mut decoded_page = String::new();
|
||||||
|
url_escape::decode_to_string(page, &mut decoded_page);
|
||||||
|
let alias_list = read_alias();
|
||||||
|
for i in alias_list {
|
||||||
|
if i.alias == decoded_page {
|
||||||
|
return Redirect::to(i.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Redirect::to("/404")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn get_index() -> Redirect {
|
||||||
|
Redirect::to(INDEX_REDIRECT)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rocket::main]
|
||||||
|
async fn main() -> Result<(), rocket::Error> {
|
||||||
|
if !std::path::Path::new("./access_keys").exists() {
|
||||||
|
eprintln!("No ./access_keys found. Falling back to no authorization");
|
||||||
|
eprintln!("Continue? (press enter or ctrl-c to exit)");
|
||||||
|
let mut s = String::new();
|
||||||
|
std::io::stdin().read_line(&mut s).unwrap();
|
||||||
|
unsafe {
|
||||||
|
ACCESS_KEY_REQUIRED = false;
|
||||||
|
}
|
||||||
|
} else if std::fs::File::open("./access_keys").unwrap().metadata().unwrap().len() == 0 {
|
||||||
|
eprintln!("No keys in ./access_keys found. Falling back to no authorization");
|
||||||
|
eprintln!("Continue? (press enter or ctrl-c to exit)");
|
||||||
|
let mut s = String::new();
|
||||||
|
std::io::stdin().read_line(&mut s).unwrap();
|
||||||
|
unsafe {
|
||||||
|
ACCESS_KEY_REQUIRED = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _rocket = rocket::build()
|
||||||
|
.mount("/", routes![not_found, create_alias, get_page, get_index])
|
||||||
|
.launch()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue