Compare commits
4 Commits
c65dc3af47
...
feature/ag
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f5596dc69 | ||
|
|
96e7f36731 | ||
|
|
410328a2af | ||
|
|
9f122566d0 |
@@ -33,3 +33,6 @@ reqwest = { version = "^0.12", features = ["json", "multipart", "stream"] }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
unwrap_used = "deny"
|
||||||
@@ -28,7 +28,7 @@ fn action(
|
|||||||
_matches: &clap::ArgMatches,
|
_matches: &clap::ArgMatches,
|
||||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>> {
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>> {
|
||||||
let output_path = _matches.get_one::<String>("output_path");
|
let output_path = _matches.get_one::<String>("output_path");
|
||||||
let output_path = output_path.unwrap().to_string();
|
let output_path = output_path.expect("output_path is required").to_string();
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
tracing::subscriber::with_default(log::make_temporary_subscriber(), || {
|
tracing::subscriber::with_default(log::make_temporary_subscriber(), || {
|
||||||
|
|||||||
@@ -11,15 +11,8 @@ use crate::{
|
|||||||
cmd::CliCommand,
|
cmd::CliCommand,
|
||||||
configs::{ProgramSettings, get_program_settings, logging::LoggingSettings},
|
configs::{ProgramSettings, get_program_settings, logging::LoggingSettings},
|
||||||
log,
|
log,
|
||||||
routes::{self, AppService, AppState},
|
routes::{self, AppState},
|
||||||
services::{
|
services::get_app_service,
|
||||||
auth::{
|
|
||||||
authentication::{AuthenticationServiceImpl, strategies::password::PasswordStrategy},
|
|
||||||
user::UserServiceImpl,
|
|
||||||
},
|
|
||||||
server_state::ServerStateService,
|
|
||||||
settings::SettingsService,
|
|
||||||
},
|
|
||||||
tasks,
|
tasks,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,19 +141,7 @@ fn get_app_state(
|
|||||||
AppState {
|
AppState {
|
||||||
database_connection: db_connection.clone(),
|
database_connection: db_connection.clone(),
|
||||||
config: Arc::new(settings.clone()),
|
config: Arc::new(settings.clone()),
|
||||||
service: Arc::new(AppService {
|
service: Arc::new(get_app_service(db_connection, settings)),
|
||||||
server_state: Arc::new(ServerStateService::new(db_connection.clone())),
|
|
||||||
settings: Arc::new(SettingsService::new(db_connection.clone())),
|
|
||||||
auth_state: routes::AuthState {
|
|
||||||
strategy: routes::AuthStrategy {
|
|
||||||
password: Arc::new(PasswordStrategy::new(db_connection.clone())),
|
|
||||||
},
|
|
||||||
authentication: Arc::new(AuthenticationServiceImpl::new(
|
|
||||||
settings.auth.jwt_secret.clone(),
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
user: Arc::new(UserServiceImpl::new(db_connection.clone())),
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub mod agent;
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
@@ -21,6 +22,7 @@ pub struct ProgramSettings {
|
|||||||
pub database: database::DatabaseSettings,
|
pub database: database::DatabaseSettings,
|
||||||
pub server: server::ServerSettings,
|
pub server: server::ServerSettings,
|
||||||
pub auth: auth::AuthSettings,
|
pub auth: auth::AuthSettings,
|
||||||
|
pub agent: agent::AgentSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromConfig for ProgramSettings {
|
impl FromConfig for ProgramSettings {
|
||||||
@@ -30,6 +32,7 @@ impl FromConfig for ProgramSettings {
|
|||||||
database: database::DatabaseSettings::from_config(_config)?,
|
database: database::DatabaseSettings::from_config(_config)?,
|
||||||
server: server::ServerSettings::from_config(_config)?,
|
server: server::ServerSettings::from_config(_config)?,
|
||||||
auth: auth::AuthSettings::from_config(_config)?,
|
auth: auth::AuthSettings::from_config(_config)?,
|
||||||
|
agent: agent::AgentSettings::from_config(_config)?,
|
||||||
};
|
};
|
||||||
config.validate()?;
|
config.validate()?;
|
||||||
Ok(config)
|
Ok(config)
|
||||||
@@ -50,6 +53,7 @@ impl FromConfig for ProgramSettings {
|
|||||||
database: database::DatabaseSettings::mock(),
|
database: database::DatabaseSettings::mock(),
|
||||||
server: server::ServerSettings::mock(),
|
server: server::ServerSettings::mock(),
|
||||||
auth: auth::AuthSettings::mock(),
|
auth: auth::AuthSettings::mock(),
|
||||||
|
agent: agent::AgentSettings::mock(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
apps/api/src/configs/agent.rs
Normal file
58
apps/api/src/configs/agent.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
use config::Config;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use crate::configs::key::AGENT_SOCK_PATH_KEY;
|
||||||
|
|
||||||
|
use super::FromConfig;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AgentSettings {
|
||||||
|
pub socket_path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromConfig for AgentSettings {
|
||||||
|
fn from_config(_config: &Config) -> Result<Self, String> {
|
||||||
|
Ok(AgentSettings {
|
||||||
|
socket_path: _config.get_string(AGENT_SOCK_PATH_KEY).map_err(|err| {
|
||||||
|
format!(
|
||||||
|
"Failed to get {} from configuration. Err: {}",
|
||||||
|
AGENT_SOCK_PATH_KEY, err
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self) -> Result<(), String> {
|
||||||
|
// ensure socket_path exists and is readable and writable
|
||||||
|
if !std::path::Path::new(&self.socket_path).exists() {
|
||||||
|
let msg = format!("Agent socket path '{}' does not exist", self.socket_path);
|
||||||
|
error!("{}", msg);
|
||||||
|
return Err(msg);
|
||||||
|
}
|
||||||
|
if std::path::Path::new(&self.socket_path)
|
||||||
|
.metadata()
|
||||||
|
.map(|meta| {
|
||||||
|
let permissions = meta.permissions();
|
||||||
|
// Check read and write permissions for the owner
|
||||||
|
!permissions.readonly()
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let msg = format!(
|
||||||
|
"Agent socket path '{}' is not readable/writable",
|
||||||
|
self.socket_path
|
||||||
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn mock() -> Self {
|
||||||
|
AgentSettings {
|
||||||
|
socket_path: "/tmp/agent.sock".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,3 +14,5 @@ pub(crate) const DATABASE_MIGRATE_ON_STARTUP_KEY: &str = "DATABASE.MIGRATION.MIG
|
|||||||
pub(crate) const AUTH_JWT_SECRET_KEY: &str = "AUTH.JWT_SECRET";
|
pub(crate) const AUTH_JWT_SECRET_KEY: &str = "AUTH.JWT_SECRET";
|
||||||
pub(crate) const AUTH_DEFAULT_ADMIN_USERNAME_KEY: &str = "AUTH.DEFAULT_ADMIN_USERNAME";
|
pub(crate) const AUTH_DEFAULT_ADMIN_USERNAME_KEY: &str = "AUTH.DEFAULT_ADMIN_USERNAME";
|
||||||
pub(crate) const AUTH_DEFAULT_ADMIN_PASSWORD_KEY: &str = "AUTH.DEFAULT_ADMIN_PASSWORD";
|
pub(crate) const AUTH_DEFAULT_ADMIN_PASSWORD_KEY: &str = "AUTH.DEFAULT_ADMIN_PASSWORD";
|
||||||
|
//
|
||||||
|
pub(crate) const AGENT_SOCK_PATH_KEY: &str = "AGENT.SOCK.PATH";
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ impl FromConfig for ServerSettings {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn mock() -> Self {
|
fn mock() -> Self {
|
||||||
ServerSettings {
|
ServerSettings {
|
||||||
address: "0.0.0.0".parse().unwrap(),
|
address: "0.0.0.0".parse().expect("Failed to parse mock IP address"),
|
||||||
port: 8080,
|
port: 8080,
|
||||||
serve_openapi: false,
|
serve_openapi: false,
|
||||||
cors: CORSSettings {
|
cors: CORSSettings {
|
||||||
|
|||||||
@@ -12,12 +12,8 @@ use crate::{
|
|||||||
configs::{ProgramSettings, server::CORSSettings},
|
configs::{ProgramSettings, server::CORSSettings},
|
||||||
middlewares,
|
middlewares,
|
||||||
services::{
|
services::{
|
||||||
auth::{
|
AppService, ServiceState,
|
||||||
authentication::{AuthenticationService, strategies::password::PasswordStrategy},
|
auth::authentication::{AuthenticationService, strategies::password::PasswordStrategy},
|
||||||
user::UserService,
|
|
||||||
},
|
|
||||||
server_state::ServerStateStore,
|
|
||||||
settings::SettingsStore,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,8 +24,6 @@ pub struct AppState {
|
|||||||
pub config: Arc<ProgramSettings>,
|
pub config: Arc<ProgramSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ServiceState<T> = Arc<T>;
|
|
||||||
|
|
||||||
pub struct AuthStrategy {
|
pub struct AuthStrategy {
|
||||||
pub password: ServiceState<PasswordStrategy>,
|
pub password: ServiceState<PasswordStrategy>,
|
||||||
}
|
}
|
||||||
@@ -39,13 +33,6 @@ pub struct AuthState {
|
|||||||
pub authentication: ServiceState<dyn AuthenticationService>,
|
pub authentication: ServiceState<dyn AuthenticationService>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppService {
|
|
||||||
pub settings: ServiceState<dyn SettingsStore>,
|
|
||||||
pub auth_state: AuthState,
|
|
||||||
pub user: ServiceState<dyn UserService>,
|
|
||||||
pub server_state: ServiceState<dyn ServerStateStore>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_root_router(
|
pub fn get_root_router(
|
||||||
state: impl Into<Arc<AppState>>,
|
state: impl Into<Arc<AppState>>,
|
||||||
cors_settings: Arc<CORSSettings>,
|
cors_settings: Arc<CORSSettings>,
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ pub async fn get_health_info(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::configs::FromConfig;
|
use crate::configs::FromConfig;
|
||||||
|
use crate::services::agent_client::AgentService;
|
||||||
use crate::{
|
use crate::{
|
||||||
routes::{AppState, api::health::state::HealthState},
|
routes::{AppState, api::health::state::HealthState},
|
||||||
services::{
|
services::{
|
||||||
@@ -94,6 +95,7 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use agent_client::apis::configuration::Configuration;
|
||||||
use axum::body::to_bytes;
|
use axum::body::to_bytes;
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
@@ -124,6 +126,7 @@ mod test {
|
|||||||
},
|
},
|
||||||
user: Arc::new(UserServiceImpl::new(db.clone())),
|
user: Arc::new(UserServiceImpl::new(db.clone())),
|
||||||
server_state: Arc::new(ServerStateService::new(db.clone())),
|
server_state: Arc::new(ServerStateService::new(db.clone())),
|
||||||
|
agent_client: Arc::new(AgentService::new(Configuration::default())),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -135,13 +138,21 @@ mod test {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
let response = app
|
let response = app
|
||||||
.oneshot(Request::builder().uri("/info").body(Body::empty()).unwrap())
|
.oneshot(
|
||||||
|
Request::builder()
|
||||||
|
.uri("/info")
|
||||||
|
.body(Body::empty())
|
||||||
|
.expect("Failed to build request"),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
let body = to_bytes(response.into_body(), 1024 * 1024).await.unwrap(); // Set limit to 1 MB
|
let body = to_bytes(response.into_body(), 1024 * 1024)
|
||||||
let health_info: HealthInfo = serde_json::from_slice(&body).unwrap();
|
.await
|
||||||
|
.expect("Failed to read response body"); // Set limit to 1 MB
|
||||||
|
let health_info: HealthInfo =
|
||||||
|
serde_json::from_slice(&body).expect("Failed to deserialize response body");
|
||||||
assert_eq!(health_info.status, STATUS_HEALTHY);
|
assert_eq!(health_info.status, STATUS_HEALTHY);
|
||||||
assert_eq!(health_info.version, env!("CARGO_PKG_VERSION"));
|
assert_eq!(health_info.version, env!("CARGO_PKG_VERSION"));
|
||||||
assert!(health_info.errors.is_none());
|
assert!(health_info.errors.is_none());
|
||||||
|
|||||||
@@ -2,3 +2,53 @@ pub mod agent_client;
|
|||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod server_state;
|
pub mod server_state;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ::agent_client::apis::configuration::Configuration;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
configs::ProgramSettings,
|
||||||
|
routes::{self, AuthState},
|
||||||
|
services::{
|
||||||
|
auth::{
|
||||||
|
authentication::{AuthenticationServiceImpl, strategies::password::PasswordStrategy},
|
||||||
|
user::{UserService, UserServiceImpl},
|
||||||
|
},
|
||||||
|
server_state::{ServerStateService, ServerStateStore},
|
||||||
|
settings::{SettingsService, SettingsStore},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type ServiceState<T> = Arc<T>;
|
||||||
|
|
||||||
|
pub struct AppService {
|
||||||
|
pub settings: ServiceState<dyn SettingsStore>,
|
||||||
|
pub auth_state: AuthState,
|
||||||
|
pub user: ServiceState<dyn UserService>,
|
||||||
|
pub server_state: ServiceState<dyn ServerStateStore>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub agent_client: ServiceState<agent_client::AgentService>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_app_service(
|
||||||
|
db_connection: &Arc<sea_orm::DatabaseConnection>,
|
||||||
|
settings: &ProgramSettings,
|
||||||
|
) -> AppService {
|
||||||
|
AppService {
|
||||||
|
server_state: Arc::new(ServerStateService::new(db_connection.clone())),
|
||||||
|
settings: Arc::new(SettingsService::new(db_connection.clone())),
|
||||||
|
auth_state: routes::AuthState {
|
||||||
|
strategy: routes::AuthStrategy {
|
||||||
|
password: Arc::new(PasswordStrategy::new(db_connection.clone())),
|
||||||
|
},
|
||||||
|
authentication: Arc::new(AuthenticationServiceImpl::new(
|
||||||
|
settings.auth.jwt_secret.clone(),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
user: Arc::new(UserServiceImpl::new(db_connection.clone())),
|
||||||
|
agent_client: Arc::new(agent_client::AgentService::new(Configuration::from(
|
||||||
|
settings.agent.clone(),
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,32 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use agent_client::apis::{ApiClient, configuration::Configuration};
|
use agent_client::apis::{ApiClient, configuration::Configuration};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
use crate::configs::agent::AgentSettings;
|
||||||
|
|
||||||
pub struct AgentService {
|
pub struct AgentService {
|
||||||
client: Arc<ApiClient>,
|
client: Arc<ApiClient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<AgentSettings> for Configuration {
|
||||||
|
fn from(settings: AgentSettings) -> Self {
|
||||||
|
let mut config = Configuration::default();
|
||||||
|
let mut builder = reqwest::Client::builder();
|
||||||
|
|
||||||
|
let url = settings.socket_path;
|
||||||
|
if url.starts_with("unix://") {
|
||||||
|
builder = builder.unix_socket(url.to_string());
|
||||||
|
config.client = builder.build().expect("Failed to build reqwest client");
|
||||||
|
} else {
|
||||||
|
warn!("AgentSettings contains a non-unix socket path: {}", url);
|
||||||
|
config.base_path = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AgentService {
|
impl AgentService {
|
||||||
pub fn new(config: impl Into<Arc<Configuration>>) -> Self {
|
pub fn new(config: impl Into<Arc<Configuration>>) -> Self {
|
||||||
let client = ApiClient::new(config.into());
|
let client = ApiClient::new(config.into());
|
||||||
@@ -14,6 +35,7 @@ impl AgentService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn get_client(&self) -> Arc<ApiClient> {
|
pub fn get_client(&self) -> Arc<ApiClient> {
|
||||||
Arc::clone(&self.client)
|
Arc::clone(&self.client)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,14 +197,17 @@ mod tests {
|
|||||||
let (token, _) = service
|
let (token, _) = service
|
||||||
.generate_jwt(user_id, 60)
|
.generate_jwt(user_id, 60)
|
||||||
.await
|
.await
|
||||||
.expect("generate jwt");
|
.expect("Failed to generate jwt");
|
||||||
|
|
||||||
let valid = service
|
let valid = service
|
||||||
.is_valid_jwt(&token, None)
|
.is_valid_jwt(&token, None)
|
||||||
.await
|
.await
|
||||||
.expect("validate jwt");
|
.expect("Failed to validate jwt");
|
||||||
assert!(valid.is_some(), "Generated token should be valid");
|
assert!(valid.is_some(), "Generated token should be valid");
|
||||||
let claims = service.parse_jwt(&token).await.expect("parse jwt");
|
let claims = service
|
||||||
|
.parse_jwt(&token)
|
||||||
|
.await
|
||||||
|
.expect("Failed to parse jwt");
|
||||||
assert_eq!(claims.sub, user_id.to_string());
|
assert_eq!(claims.sub, user_id.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,10 +216,16 @@ mod tests {
|
|||||||
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
||||||
|
|
||||||
let user_id = Uuid::new_v4();
|
let user_id = Uuid::new_v4();
|
||||||
let (token, _) = service.generate_jwt(user_id, 60).await.unwrap();
|
let (token, _) = service
|
||||||
|
.generate_jwt(user_id, 60)
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate jwt");
|
||||||
|
|
||||||
let other_sub = Uuid::new_v4().to_string();
|
let other_sub = Uuid::new_v4().to_string();
|
||||||
let valid = service.is_valid_jwt(&token, Some(other_sub)).await.unwrap();
|
let valid = service
|
||||||
|
.is_valid_jwt(&token, Some(other_sub))
|
||||||
|
.await
|
||||||
|
.expect("jwt is not valid");
|
||||||
assert!(
|
assert!(
|
||||||
valid.is_none(),
|
valid.is_none(),
|
||||||
"Token should be invalid for a different subject"
|
"Token should be invalid for a different subject"
|
||||||
@@ -236,10 +245,19 @@ mod tests {
|
|||||||
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
||||||
|
|
||||||
let user_id = Uuid::new_v4();
|
let user_id = Uuid::new_v4();
|
||||||
let (token, _) = service.generate_jwt(user_id, 60).await.unwrap();
|
let (token, _) = service
|
||||||
let new_token = service.refresh_jwt(&token, 120).await.unwrap();
|
.generate_jwt(user_id, 60)
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate jwt");
|
||||||
|
let new_token = service
|
||||||
|
.refresh_jwt(&token, 120)
|
||||||
|
.await
|
||||||
|
.expect("Failed to refresh jwt");
|
||||||
|
|
||||||
let claims = service.parse_jwt(&new_token).await.unwrap();
|
let claims = service
|
||||||
|
.parse_jwt(&new_token)
|
||||||
|
.await
|
||||||
|
.expect("Failed to parse refreshed jwt");
|
||||||
assert_eq!(claims.sub, user_id.to_string());
|
assert_eq!(claims.sub, user_id.to_string());
|
||||||
assert_eq!(claims.exp - claims.iat, 120);
|
assert_eq!(claims.exp - claims.iat, 120);
|
||||||
}
|
}
|
||||||
@@ -249,10 +267,16 @@ mod tests {
|
|||||||
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
||||||
|
|
||||||
let user_id = Uuid::new_v4();
|
let user_id = Uuid::new_v4();
|
||||||
let (token, claims) = service.generate_jwt(user_id, 1).await.unwrap();
|
let (token, claims) = service
|
||||||
|
.generate_jwt(user_id, 1)
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate jwt");
|
||||||
sleep(Duration::from_secs(2)).await;
|
sleep(Duration::from_secs(2)).await;
|
||||||
|
|
||||||
let valid = service.is_valid_jwt(&token, None).await.unwrap();
|
let valid = service
|
||||||
|
.is_valid_jwt(&token, None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to validate jwt");
|
||||||
assert!(
|
assert!(
|
||||||
valid.is_none(),
|
valid.is_none(),
|
||||||
"Token should be expired and thus invalid. Current time: {:?}. Diff: {}",
|
"Token should be expired and thus invalid. Current time: {:?}. Diff: {}",
|
||||||
@@ -266,9 +290,15 @@ mod tests {
|
|||||||
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
|
||||||
|
|
||||||
let user_id = Uuid::new_v4();
|
let user_id = Uuid::new_v4();
|
||||||
let (token, _) = service.generate_jwt(user_id, 1).await.unwrap();
|
let (token, _) = service
|
||||||
|
.generate_jwt(user_id, 1)
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate jwt");
|
||||||
|
|
||||||
service.invalidate_jwt(&token).await.unwrap();
|
service
|
||||||
|
.invalidate_jwt(&token)
|
||||||
|
.await
|
||||||
|
.expect("Failed to invalidate jwt");
|
||||||
|
|
||||||
// ensure entry is present
|
// ensure entry is present
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ mod test {
|
|||||||
"CorrectPassword".as_bytes(),
|
"CorrectPassword".as_bytes(),
|
||||||
&SaltString::generate(&mut OsRng),
|
&SaltString::generate(&mut OsRng),
|
||||||
)
|
)
|
||||||
.unwrap()
|
.expect("Failed to hash password")
|
||||||
.to_string();
|
.to_string();
|
||||||
let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite)
|
let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite)
|
||||||
.append_query_results(vec![vec![user::Model {
|
.append_query_results(vec![vec![user::Model {
|
||||||
@@ -281,7 +281,7 @@ mod test {
|
|||||||
"CorrectPassword".as_bytes(),
|
"CorrectPassword".as_bytes(),
|
||||||
&SaltString::generate(&mut OsRng),
|
&SaltString::generate(&mut OsRng),
|
||||||
)
|
)
|
||||||
.unwrap()
|
.expect("Failed to hash password")
|
||||||
.to_string();
|
.to_string();
|
||||||
let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite)
|
let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite)
|
||||||
.append_query_results(vec![vec![user::Model {
|
.append_query_results(vec![vec![user::Model {
|
||||||
|
|||||||
Reference in New Issue
Block a user