relays usually Announce(Create), so the Create is not from them but the announce is, and it gets processed properly. Lemmy does the correct thing: it sends Announce(...activity...), so the "topmost" activity effectively comes from the sending server and can be verified. however aode relay sends activities as-is, without wrapping. so if we receive activities from someone else, it won't match the http signature and we thus can't be sure this wasn't falsified. added an option to directly fetch such cases. it's probably not great, so defaults to OFF
215 lines
6.8 KiB
Rust
215 lines
6.8 KiB
Rust
#[serde_inline_default::serde_inline_default]
|
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
|
|
pub struct Config {
|
|
#[serde(default)]
|
|
pub instance: InstanceConfig,
|
|
|
|
#[serde(default)]
|
|
pub datasource: DatasourceConfig,
|
|
|
|
#[serde(default)]
|
|
pub security: SecurityConfig,
|
|
|
|
#[serde(default)]
|
|
pub compat: CompatibilityConfig,
|
|
|
|
#[serde(default)]
|
|
pub files: FileStorageConfig,
|
|
|
|
#[serde(default)]
|
|
pub reject: RejectConfig,
|
|
|
|
// TODO should i move app keys here?
|
|
}
|
|
|
|
#[serde_inline_default::serde_inline_default]
|
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
|
|
pub struct InstanceConfig {
|
|
#[serde_inline_default("μpub".into())]
|
|
/// instance name, shown in noedinfo and instance actor
|
|
pub name: String,
|
|
|
|
#[serde_inline_default("micro social network, federated".into())]
|
|
/// description, shown in nodeinfo and instance actor
|
|
pub description: String,
|
|
|
|
#[serde_inline_default("http://127.0.0.1:3000".into())]
|
|
/// domain of current instance, must change this for prod
|
|
pub domain: String,
|
|
|
|
#[serde(default)]
|
|
/// contact information for an administrator, currently unused
|
|
pub contact: String,
|
|
|
|
#[serde(default)]
|
|
/// base url for frontend, will be used to compose pretty urls
|
|
pub frontend: String,
|
|
}
|
|
|
|
#[serde_inline_default::serde_inline_default]
|
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
|
|
pub struct DatasourceConfig {
|
|
#[serde_inline_default("sqlite://./upub.db?mode=rwc".into())]
|
|
pub connection_string: String,
|
|
|
|
#[serde_inline_default(32)]
|
|
pub max_connections: u32,
|
|
|
|
#[serde_inline_default(1)]
|
|
pub min_connections: u32,
|
|
|
|
#[serde_inline_default(90u64)]
|
|
pub connect_timeout_seconds: u64,
|
|
|
|
#[serde_inline_default(30u64)]
|
|
pub acquire_timeout_seconds: u64,
|
|
|
|
#[serde_inline_default(10u64)]
|
|
/// threshold for queries to be considered slow
|
|
pub slow_query_warn_seconds: u64,
|
|
|
|
#[serde_inline_default(true)]
|
|
/// enable logging warn for slow queries
|
|
pub slow_query_warn_enable: bool,
|
|
}
|
|
|
|
#[serde_inline_default::serde_inline_default]
|
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
|
|
pub struct SecurityConfig {
|
|
#[serde(default)]
|
|
/// allow new users to register autonomously
|
|
pub allow_registration: bool,
|
|
|
|
#[serde(default)] // TODO i don't like the name of this
|
|
/// newly registered users require manual activation
|
|
pub require_user_approval: bool,
|
|
|
|
#[serde(default)]
|
|
/// allow anonymous users access to fetch debugger (explore screen)
|
|
pub allow_public_debugger: bool,
|
|
|
|
#[serde(default)]
|
|
/// allow anonymous users to perform full-text searches
|
|
pub allow_public_search: bool,
|
|
|
|
#[serde_inline_default(30)]
|
|
/// max time, in seconds, before requests fail with timeout
|
|
pub request_timeout: u64,
|
|
|
|
#[serde_inline_default("definitely-change-this-in-prod".to_string())]
|
|
/// secret for media proxy, set this to something random
|
|
pub proxy_secret: String,
|
|
|
|
#[serde_inline_default(true)]
|
|
/// allow expired tokens to be refreshed
|
|
pub allow_login_refresh: bool,
|
|
|
|
#[serde_inline_default(7 * 24)]
|
|
/// how long do login sessions last
|
|
pub session_duration_hours: i64,
|
|
|
|
#[serde_inline_default(2)]
|
|
/// how many times we allow an object to redirect
|
|
pub max_id_redirects: u32, // TODO not sure it fits here
|
|
|
|
#[serde_inline_default(20)]
|
|
/// how deep should threads be crawled for fetching replies
|
|
pub thread_crawl_depth: u32, // TODO doesn't really fit here
|
|
|
|
#[serde_inline_default(30)]
|
|
/// how long before a job is considered stale and dropped
|
|
pub job_expiration_days: u32, // TODO doesn't really fit here
|
|
|
|
#[serde_inline_default(100)]
|
|
/// how many times to attempt inserting back incomplete jobs
|
|
pub reinsertion_attempt_limit: u32, // TODO doesn't really fit here
|
|
}
|
|
|
|
#[serde_inline_default::serde_inline_default]
|
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
|
|
pub struct CompatibilityConfig {
|
|
#[serde_inline_default(true)]
|
|
/// compatibility with almost everything: set image attachments as images
|
|
pub fix_attachment_images_media_type: bool,
|
|
|
|
#[serde_inline_default(true)]
|
|
/// compatibility with mastodon and misskey (and somewhat lemmy?): notify like receiver
|
|
pub add_explicit_target_to_likes_if_local: bool,
|
|
|
|
#[serde_inline_default(true)]
|
|
/// compatibility with lemmy: avoid showing images twice
|
|
pub skip_single_attachment_if_image_is_set: bool,
|
|
|
|
#[serde_inline_default(false)]
|
|
/// compatibility with most relays: since they send us other server's activities, we must fetch
|
|
/// them to verify that they aren't falsified by the relay itself. this is quite expensive, as
|
|
/// relays send a lot of activities and we effectively end up fetching again all these, so this
|
|
/// defaults to false
|
|
pub verify_relayed_activities_by_fetching: bool,
|
|
}
|
|
|
|
#[serde_inline_default::serde_inline_default]
|
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
|
|
pub struct FileStorageConfig {
|
|
#[serde_inline_default("files/".to_string())]
|
|
/// path where media files should be stored
|
|
pub path: String,
|
|
}
|
|
|
|
#[serde_inline_default::serde_inline_default]
|
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
|
|
pub struct RejectConfig {
|
|
#[serde(default)]
|
|
/// discard incoming activities from these instances
|
|
pub incoming: Vec<String>,
|
|
|
|
#[serde(default)]
|
|
/// prevent fetching content from these instances
|
|
pub fetch: Vec<String>,
|
|
|
|
#[serde(default)]
|
|
/// prevent content from these instances from being displayed publicly
|
|
/// this effectively removes the public (aka NULL) addressing: only other addressees (followers,
|
|
/// mentions) will be able to see content from these instances on timelines and directly
|
|
pub public: Vec<String>,
|
|
|
|
#[serde(default)]
|
|
/// prevent proxying media coming from these instances
|
|
pub media: Vec<String>,
|
|
|
|
#[serde(default)]
|
|
/// skip delivering to these instances
|
|
pub delivery: Vec<String>,
|
|
|
|
#[serde(default)]
|
|
/// prevent fetching private content from these instances
|
|
pub access: Vec<String>,
|
|
|
|
#[serde(default)]
|
|
/// reject any request from these instances (ineffective as they can still fetch anonymously)
|
|
pub requests: Vec<String>,
|
|
}
|
|
|
|
impl Config {
|
|
pub fn load(path: Option<&std::path::PathBuf>) -> Self {
|
|
let Some(cfg_path) = path else { return Config::default() };
|
|
match std::fs::read_to_string(cfg_path) {
|
|
Ok(x) => match toml::from_str(&x) {
|
|
Ok(cfg) => return cfg,
|
|
Err(e) => tracing::error!("failed parsing config file: {e}"),
|
|
},
|
|
Err(e) => tracing::error!("failed reading config file: {e}"),
|
|
}
|
|
Config::default()
|
|
}
|
|
|
|
// TODO this is very magic... can we do better? maybe formalize frontend url as an attribute of
|
|
// our application?
|
|
pub fn frontend_url(&self, url: &str) -> Option<String> {
|
|
if !self.instance.frontend.is_empty() {
|
|
Some(format!("{}{url}", self.instance.frontend))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|