Compare commits
No commits in common. "fbbe6719b6823435889fe6638c9449fc3ba36f11" and "81b249d34196b3645d2e99100bc8fac553dcdcc0" have entirely different histories.
fbbe6719b6
...
81b249d341
13 changed files with 124 additions and 30 deletions
88
Cargo.lock
generated
88
Cargo.lock
generated
|
@ -346,6 +346,12 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
|
@ -714,6 +720,21 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
|
@ -723,6 +744,18 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frank_jwt"
|
||||
version = "3.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9febc9f09c7569636ba0e3d98a12addd6b11b3b3bc1d7baad06d52c60c1bbadd"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"openssl",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fully_pub"
|
||||
version = "0.1.4"
|
||||
|
@ -1232,6 +1265,21 @@ dependencies = [
|
|||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jwt"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6204285f77fe7d9784db3fdc449ecce1a0114927a51d5a41c4c7a292011c015f"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"crypto-common",
|
||||
"digest",
|
||||
"hmac",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
|
@ -1346,8 +1394,10 @@ dependencies = [
|
|||
"chrono",
|
||||
"dotenvy",
|
||||
"env_logger",
|
||||
"frank_jwt",
|
||||
"fully_pub",
|
||||
"jsonwebtoken",
|
||||
"jwt",
|
||||
"log",
|
||||
"minijinja",
|
||||
"minijinja-embed",
|
||||
|
@ -1515,6 +1565,44 @@ version = "1.20.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
|
|
20
Cargo.toml
20
Cargo.toml
|
@ -14,14 +14,8 @@ edition = "2021"
|
|||
anyhow = "1.0"
|
||||
fully_pub = "0.1"
|
||||
argon2 = "0.5"
|
||||
strum = "0.26.3"
|
||||
strum_macros = "0.26"
|
||||
uuid = { version = "1.8", features = ["serde", "v4"] }
|
||||
dotenvy = "0.15.7"
|
||||
base64 = "0.22.1"
|
||||
rand = "0.8.5"
|
||||
rand_core = { version = "0.6.4", features = ["std"] }
|
||||
url = "2.5.3"
|
||||
argh = "0.1" # for CLI
|
||||
|
||||
# Async
|
||||
|
@ -34,7 +28,6 @@ env_logger = "0.11"
|
|||
# Serialization
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_urlencoded = "0.7.1"
|
||||
toml = "0.8"
|
||||
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
@ -45,9 +38,7 @@ redis = { version = "0.27.3", default-features = false, features = ["acl"] }
|
|||
|
||||
# Web
|
||||
axum = { version = "0.7.7", features = ["json", "multipart"] }
|
||||
axum-extra = { version = "0.9.4", features = ["cookie"] }
|
||||
axum-template = { version = "2.4.0", features = ["minijinja"] }
|
||||
axum_typed_multipart = "0.13.1"
|
||||
minijinja = { version = "2.1", features = ["builtins"] }
|
||||
# to make work the static assets server
|
||||
tower-http = { version = "0.6.1", features = ["fs"] }
|
||||
|
@ -56,7 +47,18 @@ tower-http = { version = "0.6.1", features = ["fs"] }
|
|||
totp-rs = "5.6"
|
||||
minijinja-embed = "2.3.1"
|
||||
axum-macros = "0.4.2"
|
||||
jwt = "0.16.0"
|
||||
dotenvy = "0.15.7"
|
||||
frank_jwt = "3.1.3"
|
||||
jsonwebtoken = "9.3.0"
|
||||
axum-extra = { version = "0.9.4", features = ["cookie"] }
|
||||
axum_typed_multipart = "0.13.1"
|
||||
base64 = "0.22.1"
|
||||
rand = "0.8.5"
|
||||
rand_core = { version = "0.6.4", features = ["std"] }
|
||||
url = "2.5.3"
|
||||
strum = "0.26.3"
|
||||
serde_urlencoded = "0.7.1"
|
||||
|
||||
[build-dependencies]
|
||||
minijinja-embed = "2.3.1"
|
||||
|
|
1
TODO.md
1
TODO.md
|
@ -32,4 +32,3 @@
|
|||
- [ ] Add admin panel via API
|
||||
- [ ] Add admin CLI
|
||||
|
||||
- [ ] add TOTP
|
||||
|
|
|
@ -208,9 +208,12 @@ pub async fn perform_authorize(
|
|||
.bind(authorization.created_at.to_rfc3339_opts(SecondsFormat::Millis, true))
|
||||
.execute(&app_state.db)
|
||||
.await;
|
||||
if let Err(err) = res {
|
||||
error!("Failed to save authorization in DB. {}", err);
|
||||
return (StatusCode::INTERNAL_SERVER_ERROR, Html("Internal server error: Failed to process authorization form.")).into_response();
|
||||
match res {
|
||||
Err(err) => {
|
||||
error!("Failed to save authorization in DB. {}", err);
|
||||
return (StatusCode::INTERNAL_SERVER_ERROR, Html("Internal server error: Failed to process authorization form.")).into_response();
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
info!("Created authorization {}", &authorization.id);
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ pub async fn perform_login(
|
|||
headers.insert("Set-Cookie", HeaderValue::from_str(&jwt_cookie).unwrap());
|
||||
// TODO: check redirection for arbitrary URL, enforce relative path
|
||||
headers.insert("Location", HeaderValue::from_str(
|
||||
&query_params.redirect_to.unwrap_or("/me".to_string())
|
||||
&query_params.redirect_to.unwrap_or(format!("/me"))
|
||||
).unwrap());
|
||||
|
||||
(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anyhow::{Context, Result};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use sqlx::{sqlite::{SqliteConnectOptions, SqlitePoolOptions}, Pool, Sqlite, ConnectOptions};
|
||||
use std::str::FromStr;
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@ use log::info;
|
|||
use sqlx::{Pool, Sqlite};
|
||||
use models::config::{AppSecrets, Config};
|
||||
|
||||
pub const DEFAULT_DB_PATH: &str = "/var/lib/autotasker/autotasker.db";
|
||||
pub const DEFAULT_ASSETS_PATH: &str = "/usr/local/lib/autotasker/assets";
|
||||
pub const DEFAULT_CONFIG_PATH: &str = "/etc/autotasker/config.yaml";
|
||||
pub const DEFAULT_DB_PATH: &'static str = &"/var/lib/autotasker/autotasker.db";
|
||||
pub const DEFAULT_ASSETS_PATH: &'static str = &"/usr/local/lib/autotasker/assets";
|
||||
pub const DEFAULT_CONFIG_PATH: &'static str = &"/etc/autotasker/config.yaml";
|
||||
|
||||
fn get_config(path: String) -> Result<Config> {
|
||||
let inp_def_yaml = fs::read_to_string(path)
|
||||
|
@ -45,7 +45,7 @@ async fn get_app_context(start_app_config: StartAppConfig) -> Result<(Config, Ap
|
|||
|
||||
let database_path = &start_app_config.database_path.unwrap_or(DEFAULT_DB_PATH.to_string());
|
||||
info!("Using database file at {}", database_path);
|
||||
let pool = prepare_database(database_path).await.context("Could not prepare db.")?;
|
||||
let pool = prepare_database(&database_path).await.context("Could not prepare db.")?;
|
||||
|
||||
let config_path = start_app_config.config_path.unwrap_or(DEFAULT_CONFIG_PATH.to_string());
|
||||
info!("Using config file at {}", &config_path);
|
||||
|
|
|
@ -99,7 +99,7 @@ pub async fn enforce_jwt_auth_middleware(
|
|||
);
|
||||
}
|
||||
};
|
||||
let token_claims: AppUserTokenClaims = match verify_token(&app_state.secrets, jwt) {
|
||||
let token_claims: AppUserTokenClaims = match verify_token(&app_state.secrets, &jwt) {
|
||||
Ok(val) => val,
|
||||
Err(_e) => {
|
||||
return Err(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use axum::{extract::{OriginalUri, Request, State}, http::StatusCode, middleware::Next, response::{Html, IntoResponse, Redirect, Response}, Extension};
|
||||
use axum::{extract::{OriginalUri, Query, Request, State}, http::{HeaderMap, HeaderValue, StatusCode}, middleware::Next, response::{Html, IntoResponse, Redirect, Response}, Extension};
|
||||
use axum_extra::extract::CookieJar;
|
||||
|
||||
use crate::{
|
||||
|
@ -23,7 +24,7 @@ pub async fn auth_middleware(
|
|||
return Ok(next.run(req).await)
|
||||
}
|
||||
};
|
||||
let token_claims: UserTokenClaims = match verify_token(&app_state.secrets, jwt) {
|
||||
let token_claims: UserTokenClaims = match verify_token(&app_state.secrets, &jwt) {
|
||||
Ok(val) => val,
|
||||
Err(_e) => {
|
||||
return Err(
|
||||
|
|
|
@ -39,7 +39,7 @@ impl TemplateRenderer {
|
|||
return res
|
||||
}
|
||||
*res.status_mut() = status;
|
||||
res
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::models::{authorization::AuthorizationScope, config::Application};
|
|||
pub fn verify_redirect_uri(app: &Application, input_redirect_uri: &str) -> bool {
|
||||
app.allowed_redirect_uris
|
||||
.iter()
|
||||
.any(|uri| *uri == input_redirect_uri)
|
||||
.find(|uri| **uri == input_redirect_uri).is_some()
|
||||
}
|
||||
|
||||
pub fn parse_scope(scope_str: &str) -> Result<Vec<AuthorizationScope>> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use fully_pub::fully_pub;
|
||||
use anyhow::Result;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};
|
||||
|
||||
use crate::models::config::AppSecrets;
|
||||
|
@ -9,16 +10,16 @@ pub fn create_token<T: Serialize>(secrets: &AppSecrets, claims: T) -> String {
|
|||
let token = encode(
|
||||
&Header::default(),
|
||||
&claims,
|
||||
&EncodingKey::from_secret(secrets.jwt_secret.as_bytes())
|
||||
&EncodingKey::from_secret(&secrets.jwt_secret.as_bytes())
|
||||
).expect("Create token");
|
||||
|
||||
token
|
||||
return token;
|
||||
}
|
||||
|
||||
pub fn verify_token<T: DeserializeOwned>(secrets: &AppSecrets, jwt: &str) -> Result<T> {
|
||||
let token_data = decode::<T>(
|
||||
jwt,
|
||||
&DecodingKey::from_secret(secrets.jwt_secret.as_bytes()),
|
||||
&jwt,
|
||||
&DecodingKey::from_secret(&secrets.jwt_secret.as_bytes()),
|
||||
&Validation::new(Algorithm::HS256)
|
||||
)?;
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ pub fn parse_basic_auth(header_value: &str) -> Result<(String, String)> {
|
|||
let components: Vec<&str> = basic_auth_str.split(':').collect();
|
||||
|
||||
Ok((
|
||||
components.first().ok_or(anyhow!("Expected username in encoded Authorization header value."))?.to_string(),
|
||||
components.get(0).ok_or(anyhow!("Expected username in encoded Authorization header value."))?.to_string(),
|
||||
components.get(1).ok_or(anyhow!("Expected password in encoded Authorization header value."))?.to_string()
|
||||
))
|
||||
|
||||
|
|
Loading…
Reference in a new issue