mirror of
https://github.com/SinTan1729/chhoto-url
synced 2025-04-19 19:30:01 -05:00
Compare commits
No commits in common. "af1685bb70da435cd4c952159985d55d79908b99" and "f952cb88a08829be5c19ad3518f5df34833d2939" have entirely different histories.
af1685bb70
...
f952cb88a0
7 changed files with 46 additions and 98 deletions
62
README.md
62
README.md
|
@ -162,40 +162,6 @@ below, replace `http://localhost:4567` with where your instance of `chhoto-url`
|
|||
You can get the version of `chhoto-url` the server is running using `curl http://localhost:4567/api/version` and
|
||||
get the siteurl using `curl http://localhost:4567/api/siteurl`. These routes are accessible without any authentication.
|
||||
|
||||
### API key validation
|
||||
**This is required for programs that rely on a JSON response from Chhoto URL**
|
||||
|
||||
In order to use API key validation, set the `api_key` environment variable. If this is not set, the API will default to cookie
|
||||
validation (see section above). If the API key is insecure, a warning will be outputted along with a generated API key which may be used.
|
||||
|
||||
Example Linux command for generating a secure API key: `tr -dc A-Za-z0-9 </dev/urandom | head -c 128`
|
||||
|
||||
To add a link:
|
||||
``` bash
|
||||
curl -X POST -H "X-API-Key: <YOUR_API_KEY>" -d '{"shortlink":"<shortlink>", "longlink":"<longlink>"}' http://localhost:4567/api/new
|
||||
```
|
||||
Send an empty `<shortlink>` if you want it to be auto-generated. The server will reply with the generated shortlink.
|
||||
|
||||
To get information about a single shortlink:
|
||||
``` bash
|
||||
curl -H "X-API-Key: <YOUR_API_KEY>" -d '<shortlink>' http://localhost:4567/api/expand
|
||||
```
|
||||
(This route is not accessible using cookie validation.)
|
||||
|
||||
To get a list of all the currently available links:
|
||||
``` bash
|
||||
curl -H "X-API-Key: <YOUR_API_KEY>" http://localhost:4567/api/all
|
||||
```
|
||||
|
||||
To delete a link:
|
||||
``` bash
|
||||
curl -X DELETE -H "X-API-Key: <YOUR_API_KEY>" http://localhost:4567/api/del/<shortlink>
|
||||
```
|
||||
Where `<shortlink>` is name of the shortened link you would like to delete. For example, if the shortened link is
|
||||
`http://localhost:4567/example`, `<shortlink>` would be `example`.
|
||||
|
||||
The server will output when the instance is accessed over API, when an incorrect API key is received, etc.
|
||||
|
||||
### Cookie validation
|
||||
If you have set up a password, first do the following to get an authentication cookie and store it in a file.
|
||||
```bash
|
||||
|
@ -221,6 +187,34 @@ curl -X DELETE http://localhost:4567/api/del/<shortlink>
|
|||
```
|
||||
The server will send a confirmation.
|
||||
|
||||
### API key validation
|
||||
**This is required for programs that rely on a JSON response from Chhoto URL**
|
||||
|
||||
In order to use API key validation, set the `api_key` environment variable. If this is not set, the API will default to cookie
|
||||
validation (see section above). If the API key is insecure, a warning will be outputted along with a generated API key which may be used.
|
||||
|
||||
Example Linux command for generating a secure API key: `tr -dc A-Za-z0-9 </dev/urandom | head -c 128`
|
||||
|
||||
To add a link:
|
||||
``` bash
|
||||
curl -X POST -H "X-API-Key: <YOUR_API_KEY>" -d '{"shortlink":"<shortlink>", "longlink":"<longlink>"}' http://localhost:4567/api/new
|
||||
```
|
||||
Send an empty `<shortlink>` if you want it to be auto-generated. The server will reply with the generated shortlink.
|
||||
|
||||
To get a list of all the currently available links:
|
||||
``` bash
|
||||
curl -H "X-API-Key: <YOUR_API_KEY>" http://localhost:4567/api/all
|
||||
```
|
||||
|
||||
To delete a link:
|
||||
``` bash
|
||||
curl -X DELETE -H "X-API-Key: <YOUR_API_KEY>" http://localhost:4567/api/del/<shortlink>
|
||||
```
|
||||
Where `<shortlink>` is name of the shortened link you would like to delete. For example, if the shortened link is
|
||||
`http://localhost:4567/example`, `<shortlink>` would be `example`.
|
||||
|
||||
The server will output when the instance is accessed over API, when an incorrect API key is received, etc.
|
||||
|
||||
## Disable authentication
|
||||
If you do not define a password environment variable when starting the docker image, authentication
|
||||
will be disabled.
|
||||
|
|
14
actix/Cargo.lock
generated
14
actix/Cargo.lock
generated
|
@ -476,7 +476,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "chhoto-url"
|
||||
version = "5.6.0"
|
||||
version = "5.5.0"
|
||||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-session",
|
||||
|
@ -1244,9 +1244,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
|||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -1485,9 +1485,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.135"
|
||||
version = "1.0.134"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
|
||||
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
@ -1646,9 +1646,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.43.0"
|
||||
version = "1.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
|
||||
checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[package]
|
||||
name = "chhoto-url"
|
||||
version = "5.6.0"
|
||||
version = "5.5.0"
|
||||
edition = "2021"
|
||||
authors = ["Sayantan Santra <sayantan[dot]santra689[at]gmail[dot]com"]
|
||||
license = "mit"
|
||||
|
|
|
@ -13,21 +13,14 @@ pub struct DBRow {
|
|||
}
|
||||
|
||||
// Find a single URL
|
||||
pub fn find_url(shortlink: &str, db: &Connection, needhits: bool) -> (Option<String>, Option<i64>) {
|
||||
let query = if needhits {
|
||||
"SELECT long_url,hits FROM urls WHERE short_url = ?1"
|
||||
} else {
|
||||
"SELECT long_url FROM urls WHERE short_url = ?1"
|
||||
};
|
||||
pub fn find_url(shortlink: &str, db: &Connection) -> Option<String> {
|
||||
let mut statement = db
|
||||
.prepare_cached(query)
|
||||
.prepare_cached("SELECT long_url FROM urls WHERE short_url = ?1")
|
||||
.expect("Error preparing SQL statement for find_url.");
|
||||
|
||||
let longlink = statement
|
||||
statement
|
||||
.query_row([shortlink], |row| row.get("long_url"))
|
||||
.ok();
|
||||
let hits = statement.query_row([shortlink], |row| row.get("hits")).ok();
|
||||
(longlink, hits)
|
||||
.ok()
|
||||
}
|
||||
|
||||
// Get all URLs in DB
|
||||
|
|
|
@ -82,7 +82,6 @@ async fn main() -> Result<()> {
|
|||
.service(services::delete_link)
|
||||
.service(services::login)
|
||||
.service(services::logout)
|
||||
.service(services::expand)
|
||||
.service(Files::new("/", "./resources/").index_file("index.html"))
|
||||
.default_service(actix_web::web::get().to(services::error404))
|
||||
})
|
||||
|
|
|
@ -31,7 +31,7 @@ struct Response {
|
|||
reason: String,
|
||||
}
|
||||
|
||||
// Needed to return the short URL to make it easier for programs leveraging the API
|
||||
// Needs to return the short URL to make it easier for programs leveraging the API
|
||||
#[derive(Serialize)]
|
||||
struct CreatedURL {
|
||||
success: bool,
|
||||
|
@ -39,15 +39,6 @@ struct CreatedURL {
|
|||
shorturl: String,
|
||||
}
|
||||
|
||||
// Struct for returning information about a shortlink
|
||||
#[derive(Serialize)]
|
||||
struct LinkInfo {
|
||||
success: bool,
|
||||
error: bool,
|
||||
longurl: String,
|
||||
hits: i64,
|
||||
}
|
||||
|
||||
// Define the routes
|
||||
|
||||
// Add new links
|
||||
|
@ -132,35 +123,6 @@ pub async fn getall(
|
|||
}
|
||||
}
|
||||
|
||||
// Get information about a single shortlink
|
||||
#[post("/api/expand")]
|
||||
pub async fn expand(req: String, data: web::Data<AppState>, http: HttpRequest) -> HttpResponse {
|
||||
let result = utils::is_api_ok(http);
|
||||
if result.success {
|
||||
let linkinfo = utils::get_longurl(req, &data.db, true);
|
||||
if let Some(longlink) = linkinfo.0 {
|
||||
let body = LinkInfo {
|
||||
success: true,
|
||||
error: false,
|
||||
longurl: longlink,
|
||||
hits: linkinfo
|
||||
.1
|
||||
.expect("Error getting hit count for existing shortlink."),
|
||||
};
|
||||
HttpResponse::Ok().json(body)
|
||||
} else {
|
||||
let body = Response {
|
||||
success: false,
|
||||
error: true,
|
||||
reason: "The shortlink does not exist on the server.".to_string(),
|
||||
};
|
||||
HttpResponse::Unauthorized().json(body)
|
||||
}
|
||||
} else {
|
||||
HttpResponse::Unauthorized().json(result)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the site URL
|
||||
#[get("/api/siteurl")]
|
||||
pub async fn siteurl() -> HttpResponse {
|
||||
|
@ -192,7 +154,7 @@ pub async fn link_handler(
|
|||
data: web::Data<AppState>,
|
||||
) -> impl Responder {
|
||||
let shortlink_str = shortlink.to_string();
|
||||
if let Some(longlink) = utils::get_longurl(shortlink_str, &data.db, false).0 {
|
||||
if let Some(longlink) = utils::get_longurl(shortlink_str, &data.db) {
|
||||
let redirect_method = env::var("redirect_method").unwrap_or(String::from("PERMANENT"));
|
||||
database::add_hit(shortlink.as_str(), &data.db);
|
||||
if redirect_method == "TEMPORARY" {
|
||||
|
|
|
@ -80,11 +80,11 @@ pub fn is_api_ok(http: HttpRequest) -> Response {
|
|||
}
|
||||
|
||||
// Request the DB for searching an URL
|
||||
pub fn get_longurl(shortlink: String, db: &Connection, needhits: bool) -> (Option<String>, Option<i64>) {
|
||||
pub fn get_longurl(shortlink: String, db: &Connection) -> Option<String> {
|
||||
if validate_link(&shortlink) {
|
||||
database::find_url(shortlink.as_str(), db, needhits)
|
||||
database::find_url(shortlink.as_str(), db)
|
||||
} else {
|
||||
(None, None)
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ pub fn add_link(req: String, db: &Connection) -> (bool, String) {
|
|||
}
|
||||
|
||||
if validate_link(chunks.shortlink.as_str())
|
||||
&& get_longurl(chunks.shortlink.clone(), db, false).0.is_none()
|
||||
&& get_longurl(chunks.shortlink.clone(), db).is_none()
|
||||
{
|
||||
(
|
||||
database::add_link(chunks.shortlink.clone(), chunks.longlink, db),
|
||||
|
|
Loading…
Reference in a new issue