Using rust #2

Merged
phoenix merged 29 commits from v0.2.0 into main 2026-05-31 18:18:42 -04:00
4 changed files with 145 additions and 2 deletions
Showing only changes of commit 775410907b - Show all commits
Generated
+2 -1
View File
@@ -2241,10 +2241,11 @@ dependencies = [
[[package]]
name = "textsender_models"
version = "0.3.0"
source = "git+ssh://git@git.kundeng.us/phoenix/textsender-models.git?tag=v0.3.0-v0.3.0-migrate-1340440fec-111#1340440fecd79463bad053539c47e65d8da73194"
source = "git+ssh://git@git.kundeng.us/phoenix/textsender-models.git?tag=v0.3.0-17-f920e91ec0-111#f920e91ec07487dbe1a72207a8bd2be84c0e95b9"
dependencies = [
"const_format",
"dotenvy",
"josekit",
"rand 0.10.1",
"serde",
"serde_json",
+1 -1
View File
@@ -21,7 +21,7 @@ time = { version = "0.3.47", features = ["macros", "serde"] }
josekit = { version = "0.10.3" }
utoipa = { version = "5.5.0", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] }
textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender-models.git", tag = "v0.3.0-v0.3.0-migrate-1340440fec-111" }
textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender-models.git", tag = "v0.3.0-17-f920e91ec0-111" }
# icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.7.0" }
# dotenvy = { version = "0.15.7" }
# const_format = { version = "0.2.36" }
+1
View File
@@ -2,6 +2,7 @@ pub mod config;
pub mod db;
pub mod hashing;
pub mod repo;
pub mod token_stuff;
#[tokio::main]
+141
View File
@@ -0,0 +1,141 @@
use josekit::{
self,
jws::alg::hmac::HmacJwsAlgorithm::Hs256,
jwt::{self},
};
use time;
pub const KEY_ENV: &str = "SECRET_KEY";
pub const MESSAGE: &str = "Something random";
pub const ISSUER: &str = "textsender_auth";
pub const AUDIENCE: &str = "textsender";
pub fn get_issued() -> time::Result<time::OffsetDateTime> {
Ok(time::OffsetDateTime::now_utc())
}
pub fn get_expiration(issued: &time::OffsetDateTime) -> Result<time::OffsetDateTime, time::Error> {
let duration_expire = time::Duration::hours(4);
Ok(*issued + duration_expire)
}
pub fn create_token(
provided_key: &String,
id: &uuid::Uuid,
) -> Result<(String, i64), josekit::JoseError> {
let resource = textsender_models::token::TokenResource {
message: String::from(MESSAGE),
issuer: String::from(ISSUER),
audiences: vec![String::from(AUDIENCE)],
id: *id,
};
textsender_models::token::create_token(provided_key, &resource, time::Duration::hours(4))
}
pub fn create_service_token(
provided: &String,
id: &uuid::Uuid,
) -> Result<(String, i64), josekit::JoseError> {
let resource = textsender_models::token::TokenResource {
message: String::from(SERVICE_SUBJECT),
issuer: String::from(ISSUER),
audiences: vec![String::from(AUDIENCE)],
id: *id,
};
textsender_models::token::create_token(provided, &resource, time::Duration::hours(1))
}
pub fn create_service_refresh_token(
key: &String,
id: &uuid::Uuid,
) -> Result<(String, i64), josekit::JoseError> {
let resource = textsender_models::token::TokenResource {
message: String::from(SERVICE_SUBJECT),
issuer: String::from(ISSUER),
audiences: vec![String::from(AUDIENCE)],
id: *id,
};
textsender_models::token::create_token(key, &resource, time::Duration::hours(4))
}
pub fn verify_token(key: &String, token: &String) -> bool {
match get_payload(key, token) {
Ok((payload, _header)) => match payload.subject() {
Some(_sub) => true,
None => false,
},
Err(_err) => false,
}
}
pub fn extract_id_from_token(key: &String, token: &String) -> Result<uuid::Uuid, std::io::Error> {
match get_payload(key, token) {
Ok((payload, _header)) => match payload.claim("id") {
Some(id) => match uuid::Uuid::parse_str(id.as_str().unwrap()) {
Ok(extracted) => Ok(extracted),
Err(err) => Err(std::io::Error::other(err.to_string())),
},
None => Err(std::io::Error::other("No claim found")),
},
Err(err) => Err(std::io::Error::other(err.to_string())),
}
}
pub const APP_TOKEN_TYPE: &str = "Icarus_App";
pub const APP_SUBJECT: &str = "Something random";
pub const SERVICE_TOKEN_TYPE: &str = "Icarus_Service";
pub const SERVICE_SUBJECT: &str = "Service random";
pub fn get_token_type(key: &String, token: &String) -> Result<String, std::io::Error> {
match get_payload(key, token) {
Ok((payload, _header)) => match payload.subject() {
Some(subject) => {
if subject == APP_SUBJECT {
Ok(String::from(APP_TOKEN_TYPE))
} else if subject == SERVICE_SUBJECT {
Ok(String::from(SERVICE_TOKEN_TYPE))
} else {
Err(std::io::Error::other(String::from("Invalid subject")))
}
}
None => Err(std::io::Error::other(String::from("Invalid payload"))),
},
Err(err) => Err(std::io::Error::other(err.to_string())),
}
}
pub fn is_token_type_valid(token_type: &String) -> bool {
token_type == SERVICE_TOKEN_TYPE
}
fn get_payload(
key: &String,
token: &String,
) -> Result<(josekit::jwt::JwtPayload, josekit::jws::JwsHeader), josekit::JoseError> {
let ver = Hs256.verifier_from_bytes(key.as_bytes()).unwrap();
jwt::decode_with_verifier(token, &ver)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tokenize() {
let rt = tokio::runtime::Runtime::new().unwrap();
let special_key = rt
.block_on(textsender_models::envy::environment::get_secret_key())
.value;
let id = uuid::Uuid::new_v4();
match create_token(&special_key, &id) {
Ok((token, _duration)) => {
let result = verify_token(&special_key, &token);
assert!(result, "Token not verified");
}
Err(err) => {
assert!(false, "Error: {:?}", err.to_string());
}
};
}
}