mirror of
https://github.com/SinTan1729/chhoto-url
synced 2025-02-05 13:52:33 -06:00
chg: Small semantic changes
This commit is contained in:
parent
eed3c2292a
commit
f1c1642976
6 changed files with 90 additions and 54 deletions
|
@ -21,7 +21,7 @@ RUN cargo chef cook --release --target=$target --recipe-path recipe.json
|
||||||
COPY ./actix/Cargo.toml ./actix/Cargo.lock ./
|
COPY ./actix/Cargo.toml ./actix/Cargo.lock ./
|
||||||
COPY ./actix/src ./src
|
COPY ./actix/src ./src
|
||||||
# Build application
|
# Build application
|
||||||
RUN cargo build --release --target=$target --offline --bin chhoto-url
|
RUN cargo build --release --target=$target --locked --bin chhoto-url
|
||||||
RUN cp /chhoto-url/target/$target/release/chhoto-url /chhoto-url/release
|
RUN cp /chhoto-url/target/$target/release/chhoto-url /chhoto-url/release
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use actix_session::Session;
|
use actix_session::Session;
|
||||||
use std::{env, time::SystemTime};
|
|
||||||
use actix_web::HttpRequest;
|
use actix_web::HttpRequest;
|
||||||
|
use std::{env, time::SystemTime};
|
||||||
|
|
||||||
// API key generation and scoring
|
// API key generation and scoring
|
||||||
use passwords::{PasswordGenerator, scorer, analyzer};
|
use passwords::{analyzer, scorer, PasswordGenerator};
|
||||||
|
|
||||||
// Validate API key
|
// Validate API key
|
||||||
pub fn validate_key(key: String) -> bool {
|
pub fn validate_key(key: String) -> bool {
|
||||||
|
|
|
@ -47,7 +47,11 @@ async fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the user that the server has started, and where it is listening to, rather than simply outputting nothing
|
// Tell the user that the server has started, and where it is listening to, rather than simply outputting nothing
|
||||||
eprintln!("Server has started at 0.0.0.0 on port {}. Configured Site URL is: {}", port, env::var("site_url").unwrap_or(String::from("http://localhost")));
|
eprintln!(
|
||||||
|
"Server has started at 0.0.0.0 on port {}. Configured Site URL is: {}",
|
||||||
|
port,
|
||||||
|
env::var("site_url").unwrap_or(String::from("http://localhost"))
|
||||||
|
);
|
||||||
|
|
||||||
// Actually start the server
|
// Actually start the server
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
|
|
|
@ -3,7 +3,13 @@
|
||||||
|
|
||||||
use actix_files::NamedFile;
|
use actix_files::NamedFile;
|
||||||
use actix_session::Session;
|
use actix_session::Session;
|
||||||
use actix_web::{delete, get, http::StatusCode, post, web::{self, Redirect}, Either, HttpRequest, HttpResponse, Responder};
|
use actix_web::{
|
||||||
|
delete, get,
|
||||||
|
http::StatusCode,
|
||||||
|
post,
|
||||||
|
web::{self, Redirect},
|
||||||
|
Either, HttpRequest, HttpResponse, Responder,
|
||||||
|
};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
// Serialize JSON data
|
// Serialize JSON data
|
||||||
|
@ -37,7 +43,12 @@ struct CreatedURL {
|
||||||
|
|
||||||
// Add new links
|
// Add new links
|
||||||
#[post("/api/new")]
|
#[post("/api/new")]
|
||||||
pub async fn add_link(req: String, data: web::Data<AppState>, session: Session, http: HttpRequest) -> HttpResponse {
|
pub async fn add_link(
|
||||||
|
req: String,
|
||||||
|
data: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
http: HttpRequest,
|
||||||
|
) -> HttpResponse {
|
||||||
// Call is_api_ok() function, pass HttpRequest
|
// Call is_api_ok() function, pass HttpRequest
|
||||||
let result = utils::is_api_ok(http);
|
let result = utils::is_api_ok(http);
|
||||||
// If success, add new link
|
// If success, add new link
|
||||||
|
@ -48,26 +59,29 @@ pub async fn add_link(req: String, data: web::Data<AppState>, session: Session,
|
||||||
.unwrap_or(String::from("4567"))
|
.unwrap_or(String::from("4567"))
|
||||||
.parse::<u16>()
|
.parse::<u16>()
|
||||||
.expect("Supplied port is not an integer");
|
.expect("Supplied port is not an integer");
|
||||||
let url = format!("{}:{}", env::var("site_url").unwrap_or(String::from("http://localhost")), port);
|
let url = format!(
|
||||||
|
"{}:{}",
|
||||||
|
env::var("site_url").unwrap_or(String::from("http://localhost")),
|
||||||
|
port
|
||||||
|
);
|
||||||
let response = CreatedURL {
|
let response = CreatedURL {
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
shorturl: format!("{}/{}", url, out.1)
|
shorturl: format!("{}/{}", url, out.1),
|
||||||
};
|
};
|
||||||
HttpResponse::Created().json(response)
|
HttpResponse::Created().json(response)
|
||||||
} else {
|
} else {
|
||||||
let response = Response {
|
let response = Response {
|
||||||
success: false,
|
success: false,
|
||||||
error: true,
|
error: true,
|
||||||
reason: out.1
|
reason: out.1,
|
||||||
};
|
};
|
||||||
HttpResponse::Conflict().json(response)
|
HttpResponse::Conflict().json(response)
|
||||||
}
|
}
|
||||||
} else if result.error {
|
} else if result.error {
|
||||||
HttpResponse::Unauthorized().json(result)
|
HttpResponse::Unauthorized().json(result)
|
||||||
// If "pass" is true - keeps backwards compatibility
|
// If password authentication or public mode is used - keeps backwards compatibility
|
||||||
} else {
|
} else if env::var("public_mode") == Ok(String::from("Enable")) || auth::validate(session) {
|
||||||
if env::var("public_mode") == Ok(String::from("Enable")) || auth::validate(session) {
|
|
||||||
let out = utils::add_link(req, &data.db);
|
let out = utils::add_link(req, &data.db);
|
||||||
if out.0 {
|
if out.0 {
|
||||||
HttpResponse::Created().body(out.1)
|
HttpResponse::Created().body(out.1)
|
||||||
|
@ -78,11 +92,14 @@ pub async fn add_link(req: String, data: web::Data<AppState>, session: Session,
|
||||||
HttpResponse::Unauthorized().body("Not logged in!")
|
HttpResponse::Unauthorized().body("Not logged in!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Return all active links
|
// Return all active links
|
||||||
#[get("/api/all")]
|
#[get("/api/all")]
|
||||||
pub async fn getall(data: web::Data<AppState>, session: Session, http: HttpRequest) -> HttpResponse {
|
pub async fn getall(
|
||||||
|
data: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
http: HttpRequest,
|
||||||
|
) -> HttpResponse {
|
||||||
// Call is_api_ok() function, pass HttpRequest
|
// Call is_api_ok() function, pass HttpRequest
|
||||||
let result = utils::is_api_ok(http);
|
let result = utils::is_api_ok(http);
|
||||||
// If success, return all links
|
// If success, return all links
|
||||||
|
@ -90,9 +107,8 @@ pub async fn getall(data: web::Data<AppState>, session: Session, http: HttpReque
|
||||||
HttpResponse::Ok().body(utils::getall(&data.db))
|
HttpResponse::Ok().body(utils::getall(&data.db))
|
||||||
} else if result.error {
|
} else if result.error {
|
||||||
HttpResponse::Unauthorized().json(result)
|
HttpResponse::Unauthorized().json(result)
|
||||||
// If "pass" is true - keeps backwards compatibility
|
// If password authentication is used - keeps backwards compatibility
|
||||||
} else {
|
} else if auth::validate(session) {
|
||||||
if auth::validate(session){
|
|
||||||
HttpResponse::Ok().body(utils::getall(&data.db))
|
HttpResponse::Ok().body(utils::getall(&data.db))
|
||||||
} else {
|
} else {
|
||||||
let body = if env::var("public_mode") == Ok(String::from("Enable")) {
|
let body = if env::var("public_mode") == Ok(String::from("Enable")) {
|
||||||
|
@ -103,7 +119,6 @@ pub async fn getall(data: web::Data<AppState>, session: Session, http: HttpReque
|
||||||
HttpResponse::Unauthorized().body(body)
|
HttpResponse::Unauthorized().body(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Get the site URL
|
// Get the site URL
|
||||||
#[get("/api/siteurl")]
|
#[get("/api/siteurl")]
|
||||||
|
@ -166,7 +181,7 @@ pub async fn login(req: String, session: Session) -> HttpResponse {
|
||||||
let response = Response {
|
let response = Response {
|
||||||
success: false,
|
success: false,
|
||||||
error: true,
|
error: true,
|
||||||
reason: "Wrong password!".to_string()
|
reason: "Wrong password!".to_string(),
|
||||||
};
|
};
|
||||||
return HttpResponse::Unauthorized().json(response);
|
return HttpResponse::Unauthorized().json(response);
|
||||||
}
|
}
|
||||||
|
@ -179,7 +194,7 @@ pub async fn login(req: String, session: Session) -> HttpResponse {
|
||||||
let response = Response {
|
let response = Response {
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
reason: "Correct password!".to_string()
|
reason: "Correct password!".to_string(),
|
||||||
};
|
};
|
||||||
HttpResponse::Ok().json(response)
|
HttpResponse::Ok().json(response)
|
||||||
} else {
|
} else {
|
||||||
|
@ -225,22 +240,21 @@ pub async fn delete_link(
|
||||||
let response = Response {
|
let response = Response {
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
reason: format!("Deleted {}", shortlink)
|
reason: format!("Deleted {}", shortlink),
|
||||||
};
|
};
|
||||||
HttpResponse::Ok().json(response)
|
HttpResponse::Ok().json(response)
|
||||||
} else {
|
} else {
|
||||||
let response = Response {
|
let response = Response {
|
||||||
success: false,
|
success: false,
|
||||||
error: true,
|
error: true,
|
||||||
reason: "The short link was not found, and could not be deleted.".to_string()
|
reason: "The short link was not found, and could not be deleted.".to_string(),
|
||||||
};
|
};
|
||||||
HttpResponse::NotFound().json(response)
|
HttpResponse::NotFound().json(response)
|
||||||
}
|
}
|
||||||
} else if result.error {
|
} else if result.error {
|
||||||
HttpResponse::Unauthorized().json(result)
|
HttpResponse::Unauthorized().json(result)
|
||||||
// If "pass" is true - keeps backwards compatibility
|
// If "pass" is true - keeps backwards compatibility
|
||||||
} else {
|
} else if auth::validate(session) {
|
||||||
if auth::validate(session) {
|
|
||||||
if utils::delete_link(shortlink.to_string(), &data.db) {
|
if utils::delete_link(shortlink.to_string(), &data.db) {
|
||||||
HttpResponse::Ok().body(format!("Deleted {shortlink}"))
|
HttpResponse::Ok().body(format!("Deleted {shortlink}"))
|
||||||
} else {
|
} else {
|
||||||
|
@ -250,4 +264,3 @@ pub async fn delete_link(
|
||||||
HttpResponse::Unauthorized().body("Not logged in!")
|
HttpResponse::Unauthorized().body("Not logged in!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
// 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 crate::{auth, database};
|
||||||
|
use actix_web::HttpRequest;
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::env;
|
use std::env;
|
||||||
use actix_web::HttpRequest;
|
|
||||||
use crate::{auth, database};
|
|
||||||
|
|
||||||
// Struct for reading link pairs sent during API call
|
// Struct for reading link pairs sent during API call
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -26,7 +26,7 @@ pub struct Response {
|
||||||
pass: bool,
|
pass: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the api_key environment variable eists
|
// If the api_key environment variable exists
|
||||||
pub fn is_api_ok(http: HttpRequest) -> Response {
|
pub fn is_api_ok(http: HttpRequest) -> Response {
|
||||||
// If the api_key environment variable exists
|
// If the api_key environment variable exists
|
||||||
if env::var("api_key").is_ok() {
|
if env::var("api_key").is_ok() {
|
||||||
|
@ -34,26 +34,45 @@ pub fn is_api_ok(http: HttpRequest) -> Response {
|
||||||
if let Some(header) = auth::api_header(&http) {
|
if let Some(header) = auth::api_header(&http) {
|
||||||
// If the header is correct
|
// If the header is correct
|
||||||
if auth::validate_key(header.to_string()) {
|
if auth::validate_key(header.to_string()) {
|
||||||
Response { success: true, error: false, reason: "Correct API key".to_string(), pass: false }
|
Response {
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
reason: "Correct API key".to_string(),
|
||||||
|
pass: false,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Response { success: false, error: true, reason: "Incorrect API key".to_string(), pass: false }
|
Response {
|
||||||
|
success: false,
|
||||||
|
error: true,
|
||||||
|
reason: "Incorrect API key".to_string(),
|
||||||
|
pass: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// The header may not exist when the user logs in through the web interface, so allow a request with no header.
|
// The header may not exist when the user logs in through the web interface, so allow a request with no header.
|
||||||
// Further authentication checks will be conducted in services.rs
|
// Further authentication checks will be conducted in services.rs
|
||||||
} else {
|
} else {
|
||||||
// Due to the implementation of this result in services.rs, this JSON object will not be outputted.
|
// Due to the implementation of this result in services.rs, this JSON object will not be outputted.
|
||||||
Response { success: false, error: false, reason: "X-API-Key header was not found".to_string(), pass: true }
|
Response {
|
||||||
|
success: false,
|
||||||
|
error: false,
|
||||||
|
reason: "X-API-Key header was not found".to_string(),
|
||||||
|
pass: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the API key isn't set, but an API Key header is provided
|
// If the API key isn't set, but an API Key header is provided
|
||||||
if auth::api_header(&http).is_some() {
|
if auth::api_header(&http).is_some() {
|
||||||
Response {success: false, error: true, reason: "An API key was provided, but the 'api_key' environment variable is not configured in the Chhoto URL instance".to_string(), pass: false}
|
Response {success: false, error: true, reason: "An API key was provided, but the 'api_key' environment variable is not configured in the Chhoto URL instance".to_string(), pass: false}
|
||||||
} else {
|
} else {
|
||||||
Response {success: false, error: false, reason: "".to_string(), pass: true}
|
Response {
|
||||||
|
success: false,
|
||||||
|
error: false,
|
||||||
|
reason: "".to_string(),
|
||||||
|
pass: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Request the DB for searching an URL
|
// Request the DB for searching an URL
|
||||||
pub fn get_longurl(shortlink: String, db: &Connection) -> Option<String> {
|
pub fn get_longurl(shortlink: String, db: &Connection) -> Option<String> {
|
||||||
|
|
|
@ -26,7 +26,7 @@ services:
|
||||||
- password=TopSecretPass
|
- password=TopSecretPass
|
||||||
|
|
||||||
# This needs to be set in order to use programs that use the JSON interface of Chhoto URL.
|
# This needs to be set in order to use programs that use the JSON interface of Chhoto URL.
|
||||||
# You will get a warning if this is insecure, and a generated value will be outputted
|
# You will get a warning if this is insecure, and a generated value will be output
|
||||||
# You may use that value if you can't think of a secure key
|
# You may use that value if you can't think of a secure key
|
||||||
# - api_key=SECURE_API_KEY
|
# - api_key=SECURE_API_KEY
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue