Compare commits

..
Author SHA1 Message Date
phoenix 384dd41690 bump: textsender_models
textsender_models PR / Check (pull_request) Successful in 1m32s
textsender_models PR / Clippy (pull_request) Successful in 1m31s
textsender_models PR / Rustfmt (pull_request) Successful in 47s
Release Tagging / release (pull_request) Successful in 33s
2026-06-20 12:55:02 -04:00
phoenix f246676203 Changed type of response field to serde_json::Value 2026-06-20 12:54:55 -04:00
phoenix 47e6c85fc7 bump: textsender_models
textsender_models PR / Rustfmt (pull_request) Successful in 1m4s
textsender_models PR / Check (pull_request) Successful in 1m25s
Release Tagging / release (pull_request) Successful in 33s
textsender_models PR / Clippy (pull_request) Successful in 1m8s
2026-06-18 14:27:43 -04:00
phoenix 82370ad63a Added sqlx crate 2026-06-18 14:27:18 -04:00
phoenix e5ab4aa426 Adding sqlx::FromRow trait
textsender_models PR / Check (pull_request) Has been cancelled
textsender_models PR / Rustfmt (pull_request) Has been cancelled
textsender_models PR / Clippy (pull_request) Has been cancelled
Release Tagging / release (pull_request) Successful in 40s
2026-06-18 14:26:37 -04:00
phoenix ad632fca16 bump: textsender_models
textsender_models PR / Rustfmt (pull_request) Successful in 40s
textsender_models PR / Check (pull_request) Successful in 44s
Release Tagging / release (pull_request) Successful in 28s
textsender_models PR / Clippy (pull_request) Successful in 58s
2026-06-17 16:41:53 -04:00
phoenix 86febdab0d Fix field access issue 2026-06-17 16:41:46 -04:00
phoenix 7534e8652f Updating workflows
textsender_models PR / Rustfmt (pull_request) Successful in 36s
Release Tagging / release (pull_request) Successful in 33s
textsender_models PR / Clippy (pull_request) Successful in 1m12s
textsender_models PR / Check (pull_request) Successful in 1m39s
2026-06-17 16:17:38 -04:00
phoenix c4b2c19f77 Some refactoring
textsender_models PR / Rustfmt (pull_request) Successful in 35s
Release Tagging / release (pull_request) Successful in 38s
textsender_models PR / Check (pull_request) Successful in 1m34s
textsender_models PR / Clippy (pull_request) Successful in 1m33s
2026-06-17 16:15:35 -04:00
phoenix 890d03bdf3 Adding to macros and refactoring 2026-06-17 16:12:07 -04:00
16 changed files with 758 additions and 511 deletions
+7 -7
View File
@@ -1,4 +1,4 @@
name: schedtxt_models PR
name: textsender_models PR
on:
pull_request:
@@ -14,10 +14,10 @@ jobs:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: cargo check
@@ -25,10 +25,10 @@ jobs:
name: Rustfmt
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check
@@ -37,10 +37,10 @@ jobs:
name: Clippy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: cargo clippy -- -D warnings
+2 -2
View File
@@ -13,14 +13,14 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
fetch-depth: 0 # Important for git describe --tags
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
components: cargo
- name: Extract Version from Cargo.toml
+10 -10
View File
@@ -14,10 +14,10 @@ jobs:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: cargo check
@@ -25,10 +25,10 @@ jobs:
name: Test Suite
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: cargo test
@@ -36,10 +36,10 @@ jobs:
name: Rustfmt
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check
@@ -48,10 +48,10 @@ jobs:
name: Clippy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: cargo clippy -- -D warnings
@@ -60,9 +60,9 @@ jobs:
name: build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
toolchain: 1.96
- uses: Swatinem/rust-cache@v2
- run: cargo build
Generated
+669 -218
View File
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -1,17 +1,16 @@
[package]
name = "schedtxt_models"
version = "0.5.3"
name = "textsender_models"
version = "0.4.3"
edition = "2024"
rust-version = "1.97"
license = "MIT"
description = "Models used for the schedtxt project"
rust-version = "1.96"
description = "Models used for the textsender project"
[dependencies]
serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.150" }
time = { version = "0.3.53", features = ["formatting", "macros", "parsing", "serde"] }
sqlx = { version = "0.9.0", features = ["runtime-tokio", "tls-native-tls", "postgres", "time", "uuid"] }
uuid = { version = "1.23.5", features = ["v4", "serde"] }
time = { version = "0.3.49", features = ["formatting", "macros", "parsing", "serde"] }
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] }
uuid = { version = "1.23.3", features = ["v4", "serde"] }
dotenvy = { version = "0.15.7" }
const_format = { version = "0.2.36" }
josekit = { version = "0.10.3" }
-22
View File
@@ -1,22 +0,0 @@
Copyright (c) 2026 Kun Deng.
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.
-2
View File
@@ -1,2 +0,0 @@
# schedtxt_models
Models library for the `schedtxt` project.
-22
View File
@@ -19,25 +19,3 @@ impl TwilioConfig {
println!("Number: {:?}", self.phone_number);
}
}
pub fn load_config() -> Result<TwilioConfig, std::io::Error> {
let auth_sid_var = crate::envy::environment::get_env("TWILIO_AUTH_SID");
let service_sid_var = crate::envy::environment::get_env("TWILIO_SERVICE_SID");
let auth_token_var = crate::envy::environment::get_env("TWILIO_AUTH_TOKEN");
let phone_number_var = crate::envy::environment::get_env("TWILIO_PHONE_NUMBER");
if auth_sid_var.value.is_empty()
|| service_sid_var.value.is_empty()
|| auth_token_var.value.is_empty()
|| phone_number_var.value.is_empty()
{
Err(std::io::Error::other("Config not set"))
} else {
Ok(TwilioConfig {
service_sid: service_sid_var.value,
auth_token: auth_token_var.value,
account_sid: auth_sid_var.value,
phone_number: phone_number_var.value,
})
}
}
+3
View File
@@ -4,10 +4,13 @@
pub struct Contact {
#[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub id: Option<uuid::Uuid>,
// empty?
#[serde(skip_serializing_if = "Option::is_none")]
pub firstname: Option<String>,
// empty?
#[serde(skip_serializing_if = "Option::is_none")]
pub lastname: Option<String>,
// empty?
#[serde(skip_serializing_if = "Option::is_none")]
pub nickname: Option<String>,
pub phone_number: String,
+16 -16
View File
@@ -1,4 +1,4 @@
pub fn get_db_url() -> crate::envy::EnvVar {
pub async fn get_db_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::DB_URL;
let value = std::env::var(key).expect(key);
@@ -6,7 +6,7 @@ pub fn get_db_url() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_secret_main_key() -> crate::envy::EnvVar {
pub async fn get_secret_main_key() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SECRET_MAIN_KEY;
let value = std::env::var(key).expect(key);
@@ -14,7 +14,7 @@ pub fn get_secret_main_key() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_service_passphrase() -> crate::envy::EnvVar {
pub async fn get_service_passphrase() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SERVICE_PASSPHRASE;
let value = std::env::var(key).expect(key);
@@ -22,7 +22,7 @@ pub fn get_service_passphrase() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_secret_key() -> crate::envy::EnvVar {
pub async fn get_secret_key() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SECRET_KEY;
let value = std::env::var(key).expect(key);
@@ -30,7 +30,7 @@ pub fn get_secret_key() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_root_directory() -> crate::envy::EnvVar {
pub async fn get_root_directory() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::ROOT_DIRECTORY;
let value = std::env::var(key).expect(key);
@@ -38,23 +38,23 @@ pub fn get_root_directory() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_app_base_api_url() -> crate::envy::EnvVar {
pub async fn get_app_base_api_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SCHEDTXT_BASE_API_URL;
let key = crate::envy::keys::TEXTSENDER_BASE_API_URL;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub fn get_app_auth_base_api_url() -> crate::envy::EnvVar {
pub async fn get_app_auth_base_api_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SCHEDTXT_AUTH_BASE_API_URL;
let key = crate::envy::keys::TEXTSENDER_AUTH_BASE_API_URL;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub fn get_app_env() -> crate::envy::EnvVar {
pub async fn get_app_env() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::APP_ENV;
let value = std::env::var(key).expect(key);
@@ -62,14 +62,14 @@ pub fn get_app_env() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_backend_port() -> crate::envy::EnvVar {
pub async fn get_backend_port() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::BACKEND_PORT;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub fn get_frontend_url() -> crate::envy::EnvVar {
pub async fn get_frontend_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::FRONTEND_URL;
let value = std::env::var(key).expect(key);
@@ -77,7 +77,7 @@ pub fn get_frontend_url() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_rust_log() -> crate::envy::EnvVar {
pub async fn get_rust_log() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::RUST_LOG;
let value = std::env::var(key).expect(key);
@@ -85,7 +85,7 @@ pub fn get_rust_log() -> crate::envy::EnvVar {
crate::envy::init_envvar(key, &value)
}
pub fn get_allowed_origins() -> crate::envy::EnvVar {
pub async fn get_allowed_origins() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::ALLOWED_ORIGINS;
let value = std::env::var(key).expect(key);
@@ -96,8 +96,8 @@ pub fn get_allowed_origins() -> crate::envy::EnvVar {
envvar
}
/// Get environment not specified in the library
pub fn get_env(environment: &str) -> crate::envy::EnvVar {
/// Get environment not specified in the code
pub async fn get_env(environment: &str) -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let my_error = format!("{environment} {}", crate::envy::keys::error::GENERAL_ERROR);
let value = std::env::var(environment).expect(&my_error);
+8 -8
View File
@@ -2,7 +2,7 @@
pub const DB_URL: &str = "DATABASE_URL";
/// Environment key for secret main key
/// Used for the schedtxt app
/// Used for the textsender app
pub const SECRET_MAIN_KEY: &str = "SECRET_MAIN_KEY";
/// Environment key for service logins
@@ -15,11 +15,11 @@ pub const SECRET_KEY: &str = "SECRET_KEY";
/// Environment key for root directory for the textsender app
pub const ROOT_DIRECTORY: &str = "ROOT_DIRECTORY";
/// Environment key for schedtxt api url
pub const SCHEDTXT_BASE_API_URL: &str = "SCHEDTXT_BASE_API_URL";
/// Environment key for textsender api url
pub const TEXTSENDER_BASE_API_URL: &str = "TEXTSENDER_BASE_API_URL";
/// Environment key for textsender auth api url
pub const SCHEDTXT_AUTH_BASE_API_URL: &str = "SCHEDTXT_AUTH_BASE_API_URL";
pub const TEXTSENDER_AUTH_BASE_API_URL: &str = "TEXTSENDER_AUTH_BASE_API_URL";
/// Environment key for App status
pub const APP_ENV: &str = "APP_ENV";
@@ -41,10 +41,10 @@ pub mod error {
pub const SERVICE_LOGIN: &str = concatcp!(super::SERVICE_PASSPHRASE, " ", GENERAL_ERROR);
pub const SECRET_KEY: &str = concatcp!(super::SECRET_KEY, " ", GENERAL_ERROR);
pub const ROOT_DIRECTORY: &str = concatcp!(super::ROOT_DIRECTORY, " ", GENERAL_ERROR);
pub const SCHEDTXT_BASE_API_URL: &str =
concatcp!(super::SCHEDTXT_BASE_API_URL, " ", GENERAL_ERROR);
pub const SCHEDTXT_AUTH_BASE_API_URL: &str =
concatcp!(super::SCHEDTXT_AUTH_BASE_API_URL, " ", GENERAL_ERROR);
pub const TEXTSENDER_BASE_API_URL: &str =
concatcp!(super::TEXTSENDER_BASE_API_URL, " ", GENERAL_ERROR);
pub const TEXTSENDER_AUTH_BASE_API_URL: &str =
concatcp!(super::TEXTSENDER_AUTH_BASE_API_URL, " ", GENERAL_ERROR);
pub const APP_ENV: &str = concatcp!(super::APP_ENV, " ", GENERAL_ERROR);
pub const BACKEND_PORT: &str = concatcp!(super::BACKEND_PORT, " ", GENERAL_ERROR);
pub const FRONTEND_URL: &str = concatcp!(super::FRONTEND_URL, " ", GENERAL_ERROR);
+8 -26
View File
@@ -20,17 +20,16 @@ pub fn init_envvar(key: &str, value: &str) -> EnvVar {
}
pub fn init_delimiter(envvar: &mut EnvVar, delimiter: char) {
let amount_of_delimiters_found: i32 = {
let mut count = 0;
for v in envvar.value.chars() {
if v == delimiter {
count += 1;
}
}
let mut amount_of_delimiters_found: i32 = 0;
for v in envvar.value.chars() {
if v == delimiter {
amount_of_delimiters_found += 1;
}
}
count
};
let has_delimiter = amount_of_delimiters_found >= 1;
if has_delimiter {
envvar.has_delimiter = has_delimiter;
envvar.delimiter = delimiter;
@@ -38,20 +37,3 @@ pub fn init_delimiter(envvar: &mut EnvVar, delimiter: char) {
envvar.has_delimiter = has_delimiter;
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_init_delimiter() {
let delimiter: char = ',';
let value = format!("red,green,white,black");
let mut env_var = super::EnvVar {
key: String::from("COLORS"),
value: value.clone(),
..Default::default()
};
super::init_delimiter(&mut env_var, delimiter);
assert_eq!(value, env_var.value, "Colors do not match");
}
}
+3 -41
View File
@@ -2,52 +2,14 @@
/// extract it into some strings
pub fn delimitize(var: &crate::envy::EnvVar) -> Result<Vec<String>, std::io::Error> {
if var.has_delimiter {
let values: Vec<String> = match var
Ok(var
.value
.split(var.delimiter)
.map(|c| c.parse::<String>())
.collect()
{
Ok(v) => v,
Err(err) => {
return Err(std::io::Error::other(err));
}
};
Ok(values)
.map(|c| c.parse::<String>().unwrap())
.collect())
} else {
Err(std::io::Error::other(
"Environment variable does not have a delimiter",
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_delimitize() {
let envvar = crate::envy::EnvVar {
key: "OCEANS".to_string(),
value: "Atlantic|Pacific|Indian|Arctic".to_string(),
has_delimiter: true,
delimiter: '|',
};
let all_values = vec![
"Atlantic".to_string(),
"Pacific".to_string(),
"Indian".to_string(),
"Arctic".to_string(),
];
match delimitize(&envvar) {
Ok(values) => {
assert_eq!(values, all_values, "Failure in delimitizing EnvVar values");
}
Err(err) => {
assert!(false, "Error delimitizing: {err:?}");
}
}
}
}
+1 -4
View File
@@ -1,6 +1,4 @@
/// Message status - Instant
pub const MESSAGE_EVENT_RESPONSE_STATUS_INSTANT: &str = "INSTANT";
/// Message status - Scheduled
pub const MESSAGE_EVENT_RESPONSE_STATUS_SCHEDULED: &str = "SCHEDULED";
#[derive(
@@ -8,8 +6,7 @@ pub const MESSAGE_EVENT_RESPONSE_STATUS_SCHEDULED: &str = "SCHEDULED";
)]
pub struct MessageEventResponse {
pub id: uuid::Uuid,
#[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub scheduled_message_event_id: Option<uuid::Uuid>,
pub scheduled_message_event_id: uuid::Uuid,
/// Stores a json response of the sent message
pub response: serde_json::Value,
pub user_id: uuid::Uuid,
+20 -125
View File
@@ -54,7 +54,7 @@ mod util {
pub fn time_to_std_time(
provided_time: &time::OffsetDateTime,
) -> Result<std::time::SystemTime, std::time::SystemTimeError> {
let converted: std::time::SystemTime = (*provided_time).into();
let converted = std::time::SystemTime::from(*provided_time);
Ok(converted)
}
}
@@ -70,65 +70,21 @@ pub struct TokenResource {
/// Token type
pub const TOKEN_TYPE: &str = "JWT";
pub struct CreateTokenResult {
pub access_token: String,
pub issued: i64,
pub expires_in: i64,
pub token_issued: time::OffsetDateTime,
}
pub fn create_token(
key: &str,
token_resource: TokenResource,
key: &String,
token_resource: &TokenResource,
duration: time::Duration,
) -> Result<CreateTokenResult, josekit::JoseError> {
) -> Result<(String, i64), josekit::JoseError> {
let mut header = josekit::jws::JwsHeader::new();
header.set_token_type(TOKEN_TYPE);
match init_payload(token_resource, duration) {
Ok((payload, issued, expire)) => {
let signer = match josekit::jws::alg::hmac::HmacJwsAlgorithm::Hs256
.signer_from_bytes(key.as_bytes())
{
Ok(signer) => signer,
Err(err) => {
return Err(err);
}
};
let access_token = match josekit::jwt::encode_with_signer(&payload, &header, &signer) {
Ok(access_token) => access_token,
Err(err) => {
return Err(err);
}
};
Ok(CreateTokenResult {
access_token,
issued: issued.unix_timestamp(),
expires_in: expire.unix_timestamp(),
token_issued: issued,
})
}
Err(e) => Err(josekit::JoseError::InvalidClaim(e.into())),
}
}
fn init_payload(
token_resource: TokenResource,
duration: time::Duration,
) -> Result<
(
josekit::jwt::JwtPayload,
time::OffsetDateTime,
time::OffsetDateTime,
),
josekit::JoseError,
> {
let mut payload = josekit::jwt::JwtPayload::new();
payload.set_subject(token_resource.message);
payload.set_issuer(token_resource.issuer);
payload.set_audience(token_resource.audiences);
let message = &token_resource.message;
let issuer = &token_resource.issuer;
let audiences: &Vec<String> = &token_resource.audiences;
payload.set_subject(message);
payload.set_issuer(issuer);
payload.set_audience(audiences.clone());
if !token_resource.user_id.is_nil() {
match payload.set_claim("user_id", Some(serde_json::json!(token_resource.user_id))) {
Ok(_) => {}
@@ -137,81 +93,20 @@ fn init_payload(
}
}
}
match init_payload_issued(&mut payload, duration) {
Ok((issued, expire)) => Ok((payload, issued, expire)),
Err(err) => Err(err),
}
}
fn init_payload_issued(
payload: &mut josekit::jwt::JwtPayload,
duration: time::Duration,
) -> Result<(time::OffsetDateTime, time::OffsetDateTime), josekit::JoseError> {
match get_issued() {
Ok(issued) => {
let expire = issued + duration;
let issued_at = match util::time_to_std_time(&issued) {
Ok(issued_at) => issued_at,
Err(err) => {
return Err(josekit::JoseError::InvalidClaim(err.into()));
}
};
let expires_at = match util::time_to_std_time(&expire) {
Ok(expires_at) => expires_at,
Err(err) => {
return Err(josekit::JoseError::InvalidClaim(err.into()));
}
};
payload.set_issued_at(&util::time_to_std_time(&issued).unwrap());
payload.set_expires_at(&util::time_to_std_time(&expire).unwrap());
payload.set_issued_at(&issued_at);
payload.set_expires_at(&expires_at);
Ok((issued, expire))
}
Err(err) => Err(josekit::JoseError::InvalidClaim(err.into())),
}
}
#[cfg(test)]
mod tests {
const TEST_MESSAGE: &str = "Testing for schedtxt";
const TEST_ISSUER: &str = "schedtxt-test";
const TEST_AUDIENCE: &str = "area-test";
const TEST_USER_ID: uuid::Uuid = uuid::uuid!("9ab1c75f-d184-4913-ae99-544b4dcfcb41");
const TEST_KEY: &str = "8342nhf7ycrt4983q7ryfc93w478ryfc3w9487ryfc342w98i7cy";
#[test]
fn test_create_token() {
let token_resource = super::TokenResource {
message: String::from(TEST_MESSAGE),
issuer: String::from(TEST_ISSUER),
audiences: vec![String::from(TEST_AUDIENCE)],
user_id: TEST_USER_ID,
};
let token_duration = time::Duration::minutes(30);
let key = String::from(TEST_KEY);
match super::create_token(&key, token_resource, token_duration) {
Ok(cst) => match time::OffsetDateTime::from_unix_timestamp(cst.issued) {
Ok(d_result) => {
let they_match = {
d_result.year() == cst.token_issued.year()
&& d_result.month() == cst.token_issued.month()
&& d_result.day() == cst.token_issued.day()
&& d_result.hour() == cst.token_issued.hour()
&& d_result.minute() == cst.token_issued.minute()
&& d_result.second() == cst.token_issued.second()
};
assert!(they_match, "Issued times do not match");
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
},
Err(err) => {
assert!(false, "Error: {err:?}");
}
let signer = josekit::jws::alg::hmac::HmacJwsAlgorithm::Hs256
.signer_from_bytes(key.as_bytes())
.unwrap();
Ok((
josekit::jwt::encode_with_signer(&payload, &header, &signer).unwrap(),
(expire - time::OffsetDateTime::UNIX_EPOCH).whole_seconds(),
))
}
Err(e) => Err(josekit::JoseError::InvalidClaim(e.into())),
}
}
+4
View File
@@ -6,7 +6,9 @@ pub struct User {
pub phone_number: String,
pub username: String,
pub password: String,
// Firstname is a pointer
pub firstname: String,
// Lastname is a pointer
pub lastname: String,
#[serde(with = "time::serde::rfc3339::option")]
pub created: Option<time::OffsetDateTime>,
@@ -25,6 +27,7 @@ pub struct ServiceUser {
pub passphrase: String,
#[serde(with = "time::serde::rfc3339::option")]
pub created: Option<time::OffsetDateTime>,
// When serializing to json, if empty do not populate
#[serde(with = "time::serde::rfc3339::option")]
pub last_login: Option<time::OffsetDateTime>,
#[serde(skip)]
@@ -78,6 +81,7 @@ pub struct UserProfile {
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, sqlx::FromRow)]
pub struct Salt {
// #[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub id: uuid::Uuid,
#[serde(skip_serializing_if = "String::is_empty")]
pub salt: String,