first commit
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
use std::time::Duration;
|
||||
|
||||
const DEFAULT_MAX_CONCURRENT_EXECUTIONS: usize = 16;
|
||||
const DEFAULT_MAX_CONNECTED_DEVICES: usize = 10;
|
||||
const DEFAULT_MAX_EXECUTION_SECS: u64 = 3600;
|
||||
const DEFAULT_MAX_COMMAND_LENGTH: usize = 65_536;
|
||||
const DEFAULT_PING_INTERVAL_SECS: u64 = 30;
|
||||
const DEFAULT_PING_TIMEOUT_SECS: u64 = 10;
|
||||
|
||||
pub struct Config {
|
||||
pub max_concurrent_executions: usize,
|
||||
pub max_connected_devices: usize,
|
||||
pub max_execution_time: Duration,
|
||||
pub max_command_length: usize,
|
||||
pub ping_interval: Duration,
|
||||
pub ping_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_env() -> Self {
|
||||
Self {
|
||||
max_concurrent_executions: parse_env(
|
||||
"MAX_CONCURRENT_EXECUTIONS",
|
||||
DEFAULT_MAX_CONCURRENT_EXECUTIONS,
|
||||
),
|
||||
max_connected_devices: parse_env(
|
||||
"MAX_CONNECTED_DEVICES",
|
||||
DEFAULT_MAX_CONNECTED_DEVICES,
|
||||
),
|
||||
max_execution_time: Duration::from_secs(parse_env(
|
||||
"MAX_EXECUTION_SECS",
|
||||
DEFAULT_MAX_EXECUTION_SECS,
|
||||
)),
|
||||
max_command_length: parse_env("MAX_COMMAND_LENGTH", DEFAULT_MAX_COMMAND_LENGTH),
|
||||
ping_interval: Duration::from_secs(parse_env(
|
||||
"PING_INTERVAL_SECS",
|
||||
DEFAULT_PING_INTERVAL_SECS,
|
||||
)),
|
||||
ping_timeout: Duration::from_secs(parse_env(
|
||||
"PING_TIMEOUT_SECS",
|
||||
DEFAULT_PING_TIMEOUT_SECS,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_env<T: std::str::FromStr>(key: &str, default: T) -> T {
|
||||
std::env::var(key)
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
use crate::Database;
|
||||
|
||||
const AUTH_TOKENS_TABLE: &str = "auth_tokens";
|
||||
const API_TOKENS_TABLE: &str = "api_tokens";
|
||||
|
||||
pub async fn lookup_auth_token(database: &Database, token: &str) -> Result<String, String> {
|
||||
lookup_token(database, AUTH_TOKENS_TABLE, token).await
|
||||
}
|
||||
|
||||
pub async fn lookup_api_token(database: &Database, token: &str) -> Result<String, String> {
|
||||
lookup_token(database, API_TOKENS_TABLE, token).await
|
||||
}
|
||||
|
||||
async fn lookup_token(
|
||||
database: &Database,
|
||||
table: &'static str,
|
||||
token: &str,
|
||||
) -> Result<String, String> {
|
||||
let sql = format!(
|
||||
"SELECT t.user_id \
|
||||
FROM {table} t \
|
||||
JOIN users u ON u.id = t.user_id \
|
||||
WHERE t.token = ? \
|
||||
AND (t.expires_at IS NULL OR t.expires_at > DATETIME('now')) \
|
||||
AND (u.expires_at IS NULL OR u.expires_at > DATETIME('now'))"
|
||||
);
|
||||
|
||||
sqlx::query_scalar::<_, String>(sqlx::AssertSqlSafe(sql))
|
||||
.bind(token)
|
||||
.fetch_optional(database)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or_else(|| "Invalid or expired token".to_string())
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
pub fn validate_device_id(id: &str) -> Result<(), String> {
|
||||
if id.is_empty() {
|
||||
return Err("device_id cannot be empty".into());
|
||||
}
|
||||
if id.len() > 64 {
|
||||
return Err("device_id too long (max 64 characters)".into());
|
||||
}
|
||||
if !id
|
||||
.chars()
|
||||
.all(|c| c.is_alphanumeric() || c == '-' || c == '_')
|
||||
{
|
||||
return Err("device_id contains invalid characters (allowed: a-z A-Z 0-9 - _)".into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user