license and some functions
This commit is contained in:
1 parent
0655cfe48c
commit
ef8dfc67c1
56 files changed
+2586
-547
No files matched your search
+58
-22
@@ -1,8 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Mateusz Gruszczyński @linuxiarz.pl
|
||||
* Source-Available Code / Dual-Licensed.
|
||||
*
|
||||
* Free for non-commercial and evaluation use under terms of BSL/GPLv3.
|
||||
* Commercial or production use requires a valid paid license.
|
||||
* See LICENSE file in repository root for details.
|
||||
*/
|
||||
|
||||
mod smtp;
|
||||
mod values;
|
||||
|
||||
use std::{net::IpAddr, path::Path};
|
||||
use smtp::load_smtp;
|
||||
use std::{net::IpAddr, path::Path};
|
||||
use values::ConfigValues;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -14,7 +23,12 @@ pub enum AuthorizationType {
|
||||
|
||||
impl AuthorizationType {
|
||||
fn from_values(values: &ConfigValues) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
match values.get("AUTHORIZATION_TYPE", "local").trim().to_ascii_lowercase().as_str() {
|
||||
match values
|
||||
.get("AUTHORIZATION_TYPE", "local")
|
||||
.trim()
|
||||
.to_ascii_lowercase()
|
||||
.as_str()
|
||||
{
|
||||
"local" => Ok(Self::Local),
|
||||
"ldap" => Ok(Self::Ldap),
|
||||
"ad" => Ok(Self::Ad),
|
||||
@@ -63,13 +77,22 @@ impl Config {
|
||||
let port = values.get("APP_PORT", "3000").parse()?;
|
||||
let database_max_connections = values.get("DATABASE_MAX_CONNECTIONS", "8").parse()?;
|
||||
let upload_max_size_mb: usize = values.get("UPLOAD_MAX_SIZE_MB", "20").parse()?;
|
||||
let anonymous_access_token_ttl_days = values.positive_i64("ANONYMOUS_ACCESS_TOKEN_TTL_DAYS", 7)?;
|
||||
let anonymous_access_token_ttl_days =
|
||||
values.positive_i64("ANONYMOUS_ACCESS_TOKEN_TTL_DAYS", 7)?;
|
||||
let user_session_ttl_days = values.positive_i64("USER_SESSION_TTL_DAYS", 3)?;
|
||||
let unconfirmed_account_ttl_days = values.positive_i64("UNCONFIRMED_ACCOUNT_TTL_DAYS", 3)?;
|
||||
let unconfirmed_account_ttl_days =
|
||||
values.positive_i64("UNCONFIRMED_ACCOUNT_TTL_DAYS", 3)?;
|
||||
let files_dir = values.get("FILES_DIR", "data/files");
|
||||
|
||||
let storage = match values.get("STORAGE_DRIVER", "local").trim().to_ascii_lowercase().as_str() {
|
||||
"local" => crate::storage::StorageConfig::Local { root: files_dir.clone().into() },
|
||||
let storage = match values
|
||||
.get("STORAGE_DRIVER", "local")
|
||||
.trim()
|
||||
.to_ascii_lowercase()
|
||||
.as_str()
|
||||
{
|
||||
"local" => crate::storage::StorageConfig::Local {
|
||||
root: files_dir.clone().into(),
|
||||
},
|
||||
"s3" => crate::storage::StorageConfig::S3 {
|
||||
endpoint: values.optional("S3_ENDPOINT"),
|
||||
region: values.get("S3_REGION", "us-east-1"),
|
||||
@@ -92,7 +115,10 @@ impl Config {
|
||||
let context = format!("AUTHORIZATION_TYPE={}", authorization_type.as_str());
|
||||
let (default_filter, default_username_attribute) = match authorization_type {
|
||||
AuthorizationType::Ldap => ("(uid={username})", "uid"),
|
||||
AuthorizationType::Ad => ("(|(sAMAccountName={username})(userPrincipalName={username}))", "sAMAccountName"),
|
||||
AuthorizationType::Ad => (
|
||||
"(|(sAMAccountName={username})(userPrincipalName={username}))",
|
||||
"sAMAccountName",
|
||||
),
|
||||
AuthorizationType::Local => unreachable!(),
|
||||
};
|
||||
Some(crate::auth::ldap::LdapConfig {
|
||||
@@ -102,21 +128,28 @@ impl Config {
|
||||
bind_password: values.get("LDAP_BIND_PASSWORD", ""),
|
||||
base_dn: values.required("LDAP_BASE_DN", &context)?,
|
||||
user_filter: values.get("LDAP_USER_FILTER", default_filter),
|
||||
username_attribute: values.get("LDAP_USERNAME_ATTRIBUTE", default_username_attribute),
|
||||
username_attribute: values
|
||||
.get("LDAP_USERNAME_ATTRIBUTE", default_username_attribute),
|
||||
email_attribute: values.get("LDAP_EMAIL_ATTRIBUTE", "mail"),
|
||||
display_name_attribute: values.get("LDAP_DISPLAY_NAME_ATTRIBUTE", "displayName"),
|
||||
external_id_attribute: values.get("LDAP_EXTERNAL_ID_ATTRIBUTE", match authorization_type {
|
||||
AuthorizationType::Ldap => "entryUUID",
|
||||
AuthorizationType::Ad => "objectGUID",
|
||||
AuthorizationType::Local => unreachable!(),
|
||||
}),
|
||||
display_name_attribute: values
|
||||
.get("LDAP_DISPLAY_NAME_ATTRIBUTE", "displayName"),
|
||||
external_id_attribute: values.get(
|
||||
"LDAP_EXTERNAL_ID_ATTRIBUTE",
|
||||
match authorization_type {
|
||||
AuthorizationType::Ldap => "entryUUID",
|
||||
AuthorizationType::Ad => "objectGUID",
|
||||
AuthorizationType::Local => unreachable!(),
|
||||
},
|
||||
),
|
||||
organization: values.get("LDAP_ORGANIZATION", "organization"),
|
||||
provider: authorization_type.as_str().to_owned(),
|
||||
email_required: values.bool("LDAP_EMAIL_REQUIRED", true)?,
|
||||
link_existing_by_email: values.bool("LDAP_LINK_EXISTING_BY_EMAIL", false)?,
|
||||
tls_verify: values.bool("LDAP_TLS_VERIFY", true)?,
|
||||
connect_timeout_seconds: values.positive_u64("LDAP_CONNECT_TIMEOUT_SECONDS", 5)?,
|
||||
operation_timeout_seconds: values.positive_u64("LDAP_OPERATION_TIMEOUT_SECONDS", 10)?,
|
||||
connect_timeout_seconds: values
|
||||
.positive_u64("LDAP_CONNECT_TIMEOUT_SECONDS", 5)?,
|
||||
operation_timeout_seconds: values
|
||||
.positive_u64("LDAP_OPERATION_TIMEOUT_SECONDS", 10)?,
|
||||
})
|
||||
}
|
||||
};
|
||||
@@ -131,10 +164,14 @@ impl Config {
|
||||
static_dir: values.get("STATIC_DIR", "static"),
|
||||
files_dir,
|
||||
storage,
|
||||
upload_max_size_bytes: upload_max_size_mb.checked_mul(1024 * 1024).ok_or("UPLOAD_MAX_SIZE_MB is too large")?,
|
||||
upload_max_size_bytes: upload_max_size_mb
|
||||
.checked_mul(1024 * 1024)
|
||||
.ok_or("UPLOAD_MAX_SIZE_MB is too large")?,
|
||||
asset_version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||
asset_cache_max_age_seconds: values.nonnegative_u64("ASSET_CACHE_MAX_AGE_SECONDS", 600)?,
|
||||
file_cache_max_age_seconds: values.nonnegative_u64("FILE_CACHE_MAX_AGE_SECONDS", 600)?,
|
||||
asset_cache_max_age_seconds: values
|
||||
.nonnegative_u64("ASSET_CACHE_MAX_AGE_SECONDS", 600)?,
|
||||
file_cache_max_age_seconds: values
|
||||
.nonnegative_u64("FILE_CACHE_MAX_AGE_SECONDS", 600)?,
|
||||
smtp,
|
||||
registration_enabled: values.bool("REGISTRATION_ENABLED", false)?,
|
||||
account_confirmation_required: values.bool("ACCOUNT_CONFIRMATION_REQUIRED", false)?,
|
||||
@@ -165,12 +202,11 @@ impl Config {
|
||||
return Err("STATIC_DIR and FILES_DIR cannot be empty".into());
|
||||
}
|
||||
if let Some(smtp) = &self.smtp {
|
||||
if !(smtp.public_url.starts_with("http://") || smtp.public_url.starts_with("https://")) {
|
||||
if !(smtp.public_url.starts_with("http://") || smtp.public_url.starts_with("https://"))
|
||||
{
|
||||
return Err("PUBLIC_URL must start with http:// or https://".into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user