dependencies = [
"chrono",
"mime",
- "serde 1.0.123",
+ "serde",
"serde_json",
"thiserror",
"url",
checksum = "bb8e19a0810cc25df3535061a08b7d8f8a734d309ea4411c57a9767e4a2ffa0e"
dependencies = [
"activitystreams",
- "serde 1.0.123",
+ "serde",
"serde_json",
]
"pin-project 1.0.4",
"rand 0.7.3",
"regex",
- "serde 1.0.123",
+ "serde",
"serde_json",
"serde_urlencoded",
"sha-1 0.9.3",
"http",
"log",
"regex",
- "serde 1.0.123",
+ "serde",
]
[[package]]
"pin-project 1.0.4",
"regex",
"rustls",
- "serde 1.0.123",
+ "serde",
"serde_json",
"serde_urlencoded",
"socket2",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
-[[package]]
-name = "arrayvec"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
-
[[package]]
name = "async-mutex"
version = "1.4.0"
"percent-encoding",
"rand 0.7.3",
"rustls",
- "serde 1.0.123",
+ "serde",
"serde_json",
"serde_urlencoded",
]
"log",
"num_cpus",
"rand 0.7.3",
- "serde 1.0.123",
+ "serde",
"serde_json",
"thiserror",
"tokio 0.2.25",
"async-trait",
"chrono",
"log",
- "serde 1.0.123",
+ "serde",
"serde_json",
"thiserror",
"tokio 0.2.25",
dependencies = [
"libc",
"num-integer",
- "num-traits 0.2.14",
- "serde 1.0.123",
+ "num-traits",
+ "serde",
"time 0.1.44",
"winapi 0.3.9",
]
"xdg",
]
-[[package]]
-name = "config"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3"
-dependencies = [
- "lazy_static",
- "nom 5.1.2",
- "serde 1.0.123",
- "serde-hjson",
-]
-
[[package]]
name = "const_fn"
version = "0.4.5"
"syn",
]
+[[package]]
+name = "deser-hjson"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d995b60ff81bc6af01a98f0bf5db70a7418a1ac8bd74ada633968f388139da5e"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "diesel"
version = "1.4.5"
"termcolor",
]
+[[package]]
+name = "envy"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "event-listener"
version = "2.5.1"
"jpeg-decoder",
"num-iter",
"num-rational",
- "num-traits 0.2.14",
+ "num-traits",
"png",
"scoped_threadpool",
"tiff",
"base64 0.12.3",
"pem",
"ring",
- "serde 1.0.123",
+ "serde",
"serde_json",
"simple_asn1",
]
"openssl",
"rand 0.8.3",
"reqwest",
- "serde 1.0.123",
+ "serde",
"serde_json",
"sha2",
"strum",
"lemmy_db_views_moderator",
"lemmy_utils",
"log",
- "serde 1.0.123",
+ "serde",
"serde_json",
"url",
]
"percent-encoding",
"rand 0.8.3",
"reqwest",
- "serde 1.0.123",
+ "serde",
"serde_json",
"sha2",
"strum",
"lemmy_utils",
"log",
"regex",
- "serde 1.0.123",
+ "serde",
"serde_json",
"serial_test",
"sha2",
"chrono",
"diesel",
"log",
- "serde 1.0.123",
+ "serde",
"serde_json",
"url",
]
"lemmy_db_queries",
"lemmy_db_schema",
"log",
- "serde 1.0.123",
+ "serde",
"serial_test",
"url",
]
"diesel",
"lemmy_db_queries",
"lemmy_db_schema",
- "serde 1.0.123",
+ "serde",
]
[[package]]
"diesel",
"lemmy_db_queries",
"lemmy_db_schema",
- "serde 1.0.123",
+ "serde",
]
[[package]]
"lemmy_websocket",
"log",
"rss",
- "serde 1.0.123",
+ "serde",
"sha2",
"strum",
"url",
"log",
"openssl",
"reqwest",
- "serde 1.0.123",
+ "serde",
"serde_json",
"strum",
"tokio 0.3.7",
"anyhow",
"chrono",
"comrak",
- "config",
+ "deser-hjson",
"diesel",
+ "envy",
"futures",
"http",
"itertools",
"lazy_static",
"lettre",
"log",
+ "merge",
"openssl",
"percent-encoding",
"rand 0.8.3",
"regex",
"reqwest",
- "serde 1.0.123",
+ "serde",
"serde_json",
"strum",
"strum_macros",
"log",
"rand 0.8.3",
"reqwest",
- "serde 1.0.123",
+ "serde",
"serde_json",
"strum",
"strum_macros",
"idna",
"mime",
"native-tls",
- "nom 6.1.0",
+ "nom",
"once_cell",
"quoted_printable",
"r2d2",
"rand 0.8.3",
"regex",
- "serde 1.0.123",
+ "serde",
"serde_json",
"uuid",
]
-[[package]]
-name = "lexical-core"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616"
-dependencies = [
- "arrayvec",
- "bitflags",
- "cfg-if 0.1.10",
- "ryu",
- "static_assertions",
-]
-
[[package]]
name = "libc"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
-[[package]]
-name = "linked-hash-map"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
-dependencies = [
- "serde 0.8.23",
- "serde_test",
-]
-
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
- "linked-hash-map 0.5.4",
+ "linked-hash-map",
]
[[package]]
"autocfg",
]
+[[package]]
+name = "merge"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"
+dependencies = [
+ "merge_derive",
+ "num-traits",
+]
+
+[[package]]
+name = "merge_derive"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "migrations_internals"
version = "1.4.1"
"winapi 0.3.9",
]
-[[package]]
-name = "nom"
-version = "5.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
-dependencies = [
- "lexical-core",
- "memchr",
- "version_check",
-]
-
[[package]]
name = "nom"
version = "6.1.0"
dependencies = [
"autocfg",
"num-integer",
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
dependencies = [
"autocfg",
"num-integer",
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
dependencies = [
"autocfg",
"num-integer",
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
-dependencies = [
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
"vcpkg",
]
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
"native-tls",
"percent-encoding",
"pin-project-lite 0.2.4",
- "serde 1.0.123",
+ "serde",
"serde_json",
"serde_urlencoded",
"tokio 0.2.25",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-[[package]]
-name = "serde"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
-
[[package]]
name = "serde"
version = "1.0.123"
"serde_derive",
]
-[[package]]
-name = "serde-hjson"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
-dependencies = [
- "lazy_static",
- "linked-hash-map 0.3.0",
- "num-traits 0.1.43",
- "regex",
- "serde 0.8.23",
-]
-
[[package]]
name = "serde_derive"
version = "1.0.123"
"indexmap",
"itoa",
"ryu",
- "serde 1.0.123",
-]
-
-[[package]]
-name = "serde_test"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
-dependencies = [
- "serde 0.8.23",
+ "serde",
]
[[package]]
"form_urlencoded",
"itoa",
"ryu",
- "serde 1.0.123",
+ "serde",
]
[[package]]
dependencies = [
"chrono",
"num-bigint",
- "num-traits 0.2.14",
+ "num-traits",
]
[[package]]
"version_check",
]
-[[package]]
-name = "static_assertions"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-
[[package]]
name = "stdweb"
version = "0.4.20"
dependencies = [
"proc-macro2",
"quote",
- "serde 1.0.123",
+ "serde",
"serde_derive",
"syn",
]
"base-x",
"proc-macro2",
"quote",
- "serde 1.0.123",
+ "serde",
"serde_derive",
"serde_json",
"sha1",
"idna",
"matches",
"percent-encoding",
- "serde 1.0.123",
+ "serde",
]
[[package]]
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom 0.2.2",
- "serde 1.0.123",
+ "serde",
]
[[package]]
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
dependencies = [
"cfg-if 1.0.0",
- "serde 1.0.123",
+ "serde",
"serde_json",
"wasm-bindgen-macro",
]
# https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist
#
# comma separated list of instances with which federation is allowed
- # allowed_instances: ""
+ # Only one of these blocks should be uncommented
+ # allowed_instances: ["instance1.tld","instance2.tld"]
# comma separated list of instances which are blocked from federating
- # blocked_instances: ""
+ # blocked_instances: []
}
}
#!/bin/bash
set -e
-export LEMMY_JWT_SECRET=changeme
-export LEMMY_FEDERATION__ENABLED=true
-export LEMMY_TLS_ENABLED=false
-export LEMMY_SETUP__ADMIN_PASSWORD=lemmy
-export LEMMY_RATE_LIMIT__POST=99999
-export LEMMY_RATE_LIMIT__REGISTER=99999
-export LEMMY_CAPTCHA__ENABLED=false
export LEMMY_TEST_SEND_SYNC=1
export RUST_BACKTRACE=1
killall lemmy_server || true
+echo "$PWD"
+
echo "start alpha"
LEMMY_HOSTNAME=lemmy-alpha:8541 \
- LEMMY_PORT=8541 \
+ LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_alpha.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_alpha" \
- LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma,lemmy-delta,lemmy-epsilon \
- LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha \
- LEMMY_SETUP__SITE_NAME=lemmy-alpha \
- target/lemmy_server >/dev/null 2>&1 &
+ LEMMY_HOSTNAME="lemmy-alpha:8541" \
+ target/lemmy_server >/tmp/lemmy_alpha.out 2>&1 &
echo "start beta"
LEMMY_HOSTNAME=lemmy-beta:8551 \
- LEMMY_PORT=8551 \
+ LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_beta.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_beta" \
- LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma,lemmy-delta,lemmy-epsilon \
- LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta \
- LEMMY_SETUP__SITE_NAME=lemmy-beta \
- target/lemmy_server >/dev/null 2>&1 &
+ target/lemmy_server >/tmp/lemmy_beta.out 2>&1 &
echo "start gamma"
LEMMY_HOSTNAME=lemmy-gamma:8561 \
- LEMMY_PORT=8561 \
+ LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_gamma.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_gamma" \
- LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta,lemmy-delta,lemmy-epsilon \
- LEMMY_SETUP__ADMIN_USERNAME=lemmy_gamma \
- LEMMY_SETUP__SITE_NAME=lemmy-gamma \
- target/lemmy_server >/dev/null 2>&1 &
+ target/lemmy_server >/tmp/lemmy_gamma.out 2>&1 &
echo "start delta"
# An instance with only an allowlist for beta
LEMMY_HOSTNAME=lemmy-delta:8571 \
- LEMMY_PORT=8571 \
+ LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_delta.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_delta" \
- LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta \
- LEMMY_SETUP__ADMIN_USERNAME=lemmy_delta \
- LEMMY_SETUP__SITE_NAME=lemmy-delta \
- target/lemmy_server >/dev/null 2>&1 &
+ target/lemmy_server >/tmp/lemmy_delta.out 2>&1 &
echo "start epsilon"
# An instance who has a blocklist, with lemmy-alpha blocked
LEMMY_HOSTNAME=lemmy-epsilon:8581 \
- LEMMY_PORT=8581 \
+ LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_epsilon.hjson \
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_epsilon" \
- LEMMY_FEDERATION__BLOCKED_INSTANCES=lemmy-alpha \
- LEMMY_SETUP__ADMIN_USERNAME=lemmy_epsilon \
- LEMMY_SETUP__SITE_NAME=lemmy-epsilon \
- target/lemmy_server >/dev/null 2>&1 &
+ target/lemmy_server >/tmp/lemmy_epsilon.out 2>&1 &
echo "wait for all instances to start"
while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8541/api/v2/site')" != "200" ]]; do sleep 1; done
# https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist
#
# comma separated list of instances with which federation is allowed
- allowed_instances: ""
+ # Only one of these blocks should be uncommented
+ # allowed_instances: ["instance1.tld","instance2.tld"]
# comma separated list of instances which are blocked from federating
- blocked_instances: ""
+ # blocked_instances: []
}
captcha: {
enabled: true
community_user_ban_view::CommunityUserBanView,
community_view::CommunityView,
};
-use lemmy_utils::{claims::Claims, settings::Settings, ApiError, ConnectionId, LemmyError};
+use lemmy_utils::{
+ claims::Claims,
+ settings::structs::Settings,
+ ApiError,
+ ConnectionId,
+ LemmyError,
+};
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
use serde::Deserialize;
use std::process::Command;
pub(crate) async fn build_federated_instances(
pool: &DbPool,
) -> Result<Option<FederatedInstances>, LemmyError> {
- if Settings::get().federation.enabled {
+ if Settings::get().federation().enabled {
let distinct_communities = blocking(pool, move |conn| {
Community::distinct_federated_communities(conn)
})
.map(|actor_id| Ok(Url::parse(actor_id)?.host_str().unwrap_or("").to_string()))
.collect::<Result<Vec<String>, LemmyError>>()?;
- linked.extend_from_slice(&allowed);
- linked.retain(|a| !blocked.contains(a) && !a.eq("") && !a.eq(&Settings::get().hostname));
+ if let Some(allowed) = allowed.as_ref() {
+ linked.extend_from_slice(allowed);
+ }
+
+ if let Some(blocked) = blocked.as_ref() {
+ linked.retain(|a| !blocked.contains(a) && !a.eq(&Settings::get().hostname()));
+ }
// Sort and remove dupes
linked.sort_unstable();
};
use lemmy_utils::{
location_info,
- settings::Settings,
+ settings::structs::Settings,
utils::{check_slurs, check_slurs_opt},
version,
ApiError,
Ok(site_view) => Some(site_view),
// If the site isn't created yet, check the setup
Err(_) => {
- if let Some(setup) = Settings::get().setup.as_ref() {
+ if let Some(setup) = Settings::get().setup().as_ref() {
let register = Register {
username: setup.admin_username.to_owned(),
email: setup.admin_email.to_owned(),
claims::Claims,
email::send_email,
location_info,
- settings::Settings,
+ settings::structs::Settings,
utils::{
check_slurs,
generate_random_string,
// Return the jwt
Ok(LoginResponse {
- jwt: Claims::jwt(user.id, Settings::get().hostname)?,
+ jwt: Claims::jwt(user.id, Settings::get().hostname())?,
})
}
}
.await??;
// If its not the admin, check the captcha
- if !no_admins && Settings::get().captcha.enabled {
+ if !no_admins && Settings::get().captcha().enabled {
let check = context
.chat_server()
.send(CheckCaptcha {
// Return the jwt
Ok(LoginResponse {
- jwt: Claims::jwt(inserted_user.id, Settings::get().hostname)?,
+ jwt: Claims::jwt(inserted_user.id, Settings::get().hostname())?,
})
}
}
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
- let captcha_settings = Settings::get().captcha;
+ let captcha_settings = Settings::get().captcha();
if !captcha_settings.enabled {
return Ok(GetCaptchaResponse { ok: None });
// Return the jwt
Ok(LoginResponse {
- jwt: Claims::jwt(updated_user.id, Settings::get().hostname)?,
+ jwt: Claims::jwt(updated_user.id, Settings::get().hostname())?,
})
}
}
// Return the jwt
Ok(LoginResponse {
- jwt: Claims::jwt(updated_user.id, Settings::get().hostname)?,
+ jwt: Claims::jwt(updated_user.id, Settings::get().hostname())?,
})
}
}
user::User_,
user_mention::{UserMention, UserMentionForm},
};
-use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError};
+use lemmy_utils::{email::send_email, settings::structs::Settings, utils::MentionData, LemmyError};
use log::error;
use serde::{Deserialize, Serialize};
use url::Url;
let subject = &format!(
"{} - {} {}",
subject_text,
- Settings::get().hostname,
+ Settings::get().hostname(),
user.name,
);
let html = &format!(
#[derive(Serialize)]
pub struct FederatedInstances {
pub linked: Vec<String>,
- pub allowed: Vec<String>,
- pub blocked: Vec<String>,
+ pub allowed: Option<Vec<String>>,
+ pub blocked: Option<Vec<String>>,
}
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post, user::User_};
use lemmy_utils::{
request::{retry, RecvError},
- settings::Settings,
+ settings::structs::Settings,
utils::{scrape_text_for_mentions, MentionData},
LemmyError,
};
-use lemmy_utils::settings::Settings;
+use lemmy_utils::settings::structs::Settings;
use url::{ParseError, Url};
use uuid::Uuid;
use itertools::Itertools;
use lemmy_db_queries::DbPool;
use lemmy_db_schema::source::{community::Community, user::User_};
-use lemmy_utils::{location_info, settings::Settings, LemmyError};
+use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use log::{debug, warn};
use reqwest::Client;
.await?
.iter()
.unique()
- .filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname))
+ .filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname()))
.filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
.map(|inbox| inbox.to_owned())
.collect();
Kind: Serialize,
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
{
- if !Settings::get().federation.enabled || inboxes.is_empty() {
+ if !Settings::get().federation().enabled || inboxes.is_empty() {
return Ok(());
}
};
use lemmy_db_views::{comment_view::CommentView, post_view::PostView};
use lemmy_db_views_actor::{community_view::CommunityView, user_view::UserViewSafe};
-use lemmy_utils::{settings::Settings, LemmyError};
+use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use log::debug;
use url::Url;
use lemmy_api_structs::blocking;
use lemmy_db_queries::source::activity::Activity_;
use lemmy_db_schema::source::activity::Activity;
-use lemmy_utils::{settings::Settings, LemmyError};
+use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
DbPool,
};
use lemmy_db_schema::source::{activity::Activity, community::Community, user::User_};
-use lemmy_utils::{location_info, settings::Settings, LemmyError};
+use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::Serialize;
use std::fmt::Debug;
let id = activity.id_unchecked().context(location_info!())?;
let activity_domain = id.domain().context(location_info!())?;
- if activity_domain == Settings::get().hostname {
+ if activity_domain == Settings::get().hostname() {
return Err(
anyhow!(
"Error: received activity which was sent by local instance: {:?}",
private_message::PrivateMessage,
user::User_,
};
-use lemmy_utils::{location_info, settings::Settings, LemmyError};
+use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::Serialize;
use std::net::IpAddr;
let domain = apub_id.domain().context(location_info!())?.to_string();
let local_instance = settings.get_hostname_without_port()?;
- if !settings.federation.enabled {
+ if !settings.federation().enabled {
return if domain == local_instance {
Ok(())
} else {
return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into());
}
- let mut allowed_instances = Settings::get().get_allowed_instances();
+ let allowed_instances = Settings::get().get_allowed_instances();
let blocked_instances = Settings::get().get_blocked_instances();
- if allowed_instances.is_empty() && blocked_instances.is_empty() {
+
+ if allowed_instances.is_none() && blocked_instances.is_none() {
Ok(())
- } else if !allowed_instances.is_empty() {
+ } else if let Some(mut allowed) = allowed_instances {
// need to allow this explicitly because apub receive might contain objects from our local
// instance. split is needed to remove the port in our federation test setup.
- allowed_instances.push(local_instance);
+ allowed.push(local_instance);
- if allowed_instances.contains(&domain) {
+ if allowed.contains(&domain) {
Ok(())
} else {
Err(anyhow!("{} not in federation allowlist", domain).into())
}
- } else if !blocked_instances.is_empty() {
- if blocked_instances.contains(&domain) {
+ } else if let Some(blocked) = blocked_instances {
+ if blocked.contains(&domain) {
Err(anyhow!("{} is in federation blocklist", domain).into())
} else {
Ok(())
use lemmy_db_schema::source::community::Community;
use lemmy_utils::{
location_info,
- settings::Settings,
+ settings::structs::Settings,
utils::{convert_datetime, markdown_to_html},
LemmyError,
};
let domain = object_id.domain().context(location_info!())?;
// if its a local object, return it directly from the database
- if Settings::get().hostname == domain {
+ if Settings::get().hostname() == domain {
let object = blocking(context.pool(), move |conn| {
To::read_from_apub_id(conn, &object_id.into())
})
};
use lemmy_utils::{
location_info,
- settings::Settings,
+ settings::structs::Settings,
utils::{check_slurs, check_slurs_opt, convert_datetime},
LemmyError,
};
) -> Result<User_, LemmyError> {
let user_id = person.id_unchecked().context(location_info!())?.to_owned();
let domain = user_id.domain().context(location_info!())?;
- if domain == Settings::get().hostname {
+ if domain == Settings::get().hostname() {
let user = blocking(context.pool(), move |conn| {
User_::read_from_apub_id(conn, &user_id.into())
})
};
use actix_web::*;
use http_signature_normalization_actix::digest::middleware::VerifyDigest;
-use lemmy_utils::settings::Settings;
+use lemmy_utils::settings::structs::Settings;
use sha2::{Digest, Sha256};
static APUB_JSON_CONTENT_TYPE_LONG: &str =
"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"";
pub fn config(cfg: &mut web::ServiceConfig) {
- if Settings::get().federation.enabled {
- println!("federation enabled, host is {}", Settings::get().hostname);
+ if Settings::get().federation().enabled {
+ println!("federation enabled, host is {}", Settings::get().hostname());
let digest_verifier = VerifyDigest::new(Sha256::new());
let header_guard_accept = guard::Any(guard::Header("Accept", APUB_JSON_CONTENT_TYPE))
source::user::{UserForm, UserSafeSettings, User_},
Url,
};
-use lemmy_utils::settings::Settings;
+use lemmy_utils::settings::structs::Settings;
mod safe_type {
use crate::ToSafe;
site_view::SiteView,
};
use lemmy_db_views_actor::user_mention_view::{UserMentionQueryBuilder, UserMentionView};
-use lemmy_utils::{claims::Claims, settings::Settings, utils::markdown_to_html, LemmyError};
+use lemmy_utils::{
+ claims::Claims,
+ settings::structs::Settings,
+ utils::markdown_to_html,
+ LemmyError,
+};
use lemmy_websocket::LemmyContext;
use rss::{
extension::dublincore::DublinCoreExtensionBuilder,
) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(&conn)?;
let user = User_::find_by_username(&conn, &user_name)?;
- let user_url = user.get_profile_url(&Settings::get().hostname);
+ let user_url = user.get_profile_url(&Settings::get().hostname());
let posts = PostQueryBuilder::create(&conn)
.listing_type(&ListingType::All)
use actix::clock::Duration;
use actix_web::{body::BodyStream, http::StatusCode, *};
use awc::Client;
-use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::Settings};
+use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::structs::Settings};
use serde::{Deserialize, Serialize};
pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
return Ok(HttpResponse::Unauthorized().finish());
};
- let mut client_req =
- client.request_from(format!("{}/image", Settings::get().pictrs_url), req.head());
+ let mut client_req = client.request_from(
+ format!("{}/image", Settings::get().pictrs_url()),
+ req.head(),
+ );
if let Some(addr) = req.head().peer_addr {
client_req = client_req.header("X-Forwarded-For", addr.to_string())
// If there are no query params, the URL is original
let url = if params.format.is_none() && params.thumbnail.is_none() {
- format!("{}/image/original/{}", Settings::get().pictrs_url, name,)
+ format!("{}/image/original/{}", Settings::get().pictrs_url(), name,)
} else {
// Use jpg as a default when none is given
let format = params.format.unwrap_or_else(|| "jpg".to_string());
let mut url = format!(
"{}/image/process.{}?src={}",
- Settings::get().pictrs_url,
+ Settings::get().pictrs_url(),
format,
name,
);
let url = format!(
"{}/image/delete/{}/{}",
- Settings::get().pictrs_url,
+ Settings::get().pictrs_url(),
&token,
&file
);
use anyhow::anyhow;
use lemmy_api_structs::blocking;
use lemmy_db_views::site_view::SiteView;
-use lemmy_utils::{settings::Settings, version, LemmyError};
+use lemmy_utils::{settings::structs::Settings, version, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use url::Url;
.await?
.map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?;
- let protocols = if Settings::get().federation.enabled {
+ let protocols = if Settings::get().federation().enabled {
vec!["activitypub".to_string()]
} else {
vec![]
use lemmy_db_queries::source::{community::Community_, user::User};
use lemmy_db_schema::source::{community::Community, user::User_};
use lemmy_utils::{
- settings::Settings,
+ settings::structs::Settings,
LemmyError,
WEBFINGER_COMMUNITY_REGEX,
WEBFINGER_USER_REGEX,
}
pub fn config(cfg: &mut web::ServiceConfig) {
- if Settings::get().federation.enabled {
+ if Settings::get().federation().enabled {
cfg.route(
".well-known/webfinger",
web::get().to(get_webfinger_response),
[dependencies]
regex = "1.4.3"
-config = { version = "0.10.1", default-features = false, features = ["hjson"] }
chrono = { version = "0.4.19", features = ["serde"] }
lettre = "0.10.0-alpha.5"
log = "0.4.14"
diesel = "1.4.5"
http = "0.2.3"
jsonwebtoken = "7.2.0"
+deser-hjson = "0.1.12"
+merge = "0.1.0"
+envy = "0.4.2"
-use crate::settings::Settings;
+use crate::settings::structs::Settings;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
use serde::{Deserialize, Serialize};
};
decode::<Claims>(
&jwt,
- &DecodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
+ &DecodingKey::from_secret(Settings::get().jwt_secret().as_ref()),
&v,
)
}
encode(
&Header::default(),
&my_claims,
- &EncodingKey::from_secret(Settings::get().jwt_secret.as_ref()),
+ &EncodingKey::from_secret(Settings::get().jwt_secret().as_ref()),
)
}
}
-use crate::settings::Settings;
+use crate::settings::structs::Settings;
use lettre::{
message::{header, Mailbox, MultiPart, SinglePart},
transport::smtp::{
to_username: &str,
html: &str,
) -> Result<(), String> {
- let email_config = Settings::get().email.ok_or("no_email_setup")?;
- let domain = Settings::get().hostname;
+ let email_config = Settings::get().email().ok_or("no_email_setup")?;
+ let domain = Settings::get().hostname();
let (smtp_server, smtp_port) = {
let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();
pub mod rate_limit;
pub mod request;
pub mod settings;
+
#[cfg(test)]
mod test;
pub mod utils;
pub mod version;
-use crate::settings::Settings;
+use crate::settings::structs::Settings;
use http::StatusCode;
use regex::Regex;
use thiserror::Error;
lazy_static! {
pub static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
"^group:([a-z0-9_]{{3, 20}})@{}$",
- Settings::get().hostname
+ Settings::get().hostname()
))
.unwrap();
pub static ref WEBFINGER_USER_REGEX: Regex = Regex::new(&format!(
"^acct:([a-z0-9_]{{3, 20}})@{}$",
- Settings::get().hostname
+ Settings::get().hostname()
))
.unwrap();
}
use crate::{
- settings::{RateLimitConfig, Settings},
+ settings::structs::{RateLimitConfig, Settings},
utils::get_ip,
LemmyError,
};
{
// Does not need to be blocking because the RwLock in settings never held across await points,
// and the operation here locks only long enough to clone
- let rate_limit: RateLimitConfig = Settings::get().rate_limit;
+ let rate_limit: RateLimitConfig = Settings::get().rate_limit();
// before
{
-use crate::{settings::Settings, LemmyError};
+use crate::{settings::structs::Settings, LemmyError};
use anyhow::anyhow;
use log::error;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
client: &Client,
url: &str,
) -> Result<IframelyResponse, LemmyError> {
- let fetch_url = format!("{}/oembed?url={}", Settings::get().iframely_url, url);
+ let fetch_url = format!("{}/oembed?url={}", Settings::get().iframely_url(), url);
let response = retry(|| client.get(&fetch_url).send()).await?;
let fetch_url = format!(
"{}/image/download?url={}",
- Settings::get().pictrs_url,
+ Settings::get().pictrs_url(),
utf8_percent_encode(image_url, NON_ALPHANUMERIC) // TODO this might not be needed
);
+++ /dev/null
-use crate::location_info;
-use anyhow::Context;
-use config::{Config, ConfigError, Environment, File};
-use serde::Deserialize;
-use std::{env, fs, io::Error, net::IpAddr, sync::RwLock};
-
-static CONFIG_FILE_DEFAULTS: &str = "config/defaults.hjson";
-static CONFIG_FILE: &str = "config/config.hjson";
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct Settings {
- pub setup: Option<Setup>,
- pub database: DatabaseConfig,
- pub hostname: String,
- pub bind: IpAddr,
- pub port: u16,
- pub tls_enabled: bool,
- pub jwt_secret: String,
- pub pictrs_url: String,
- pub iframely_url: String,
- pub rate_limit: RateLimitConfig,
- pub email: Option<EmailConfig>,
- pub federation: FederationConfig,
- pub captcha: CaptchaConfig,
-}
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct Setup {
- pub admin_username: String,
- pub admin_password: String,
- pub admin_email: Option<String>,
- pub site_name: String,
-}
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct RateLimitConfig {
- pub message: i32,
- pub message_per_second: i32,
- pub post: i32,
- pub post_per_second: i32,
- pub register: i32,
- pub register_per_second: i32,
- pub image: i32,
- pub image_per_second: i32,
-}
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct EmailConfig {
- pub smtp_server: String,
- pub smtp_login: Option<String>,
- pub smtp_password: Option<String>,
- pub smtp_from_address: String,
- pub use_tls: bool,
-}
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct CaptchaConfig {
- pub enabled: bool,
- pub difficulty: String, // easy, medium, or hard
-}
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct DatabaseConfig {
- pub user: String,
- pub password: String,
- pub host: String,
- pub port: i32,
- pub database: String,
- pub pool_size: u32,
-}
-
-#[derive(Debug, Deserialize, Clone)]
-pub struct FederationConfig {
- pub enabled: bool,
- pub allowed_instances: String,
- pub blocked_instances: String,
-}
-
-lazy_static! {
- static ref SETTINGS: RwLock<Settings> = RwLock::new(match Settings::init() {
- Ok(c) => c,
- Err(e) => panic!("{}", e),
- });
-}
-
-impl Settings {
- /// Reads config from the files and environment.
- /// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
- /// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
- /// added to the config.
- ///
- /// Note: The env var `LEMMY_DATABASE_URL` is parsed in
- /// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()`
- fn init() -> Result<Self, ConfigError> {
- let mut s = Config::new();
-
- s.merge(File::with_name(&Self::get_config_defaults_location()))?;
-
- s.merge(File::with_name(&Self::get_config_location()).required(false))?;
-
- // Add in settings from the environment (with a prefix of LEMMY)
- // Eg.. `LEMMY_DEBUG=1 ./target/app` would set the `debug` key
- // Note: we need to use double underscore here, because otherwise variables containing
- // underscore cant be set from environmnet.
- // https://github.com/mehcode/config-rs/issues/73
- s.merge(Environment::with_prefix("LEMMY").separator("__"))?;
-
- s.try_into()
- }
-
- /// Returns the config as a struct.
- pub fn get() -> Self {
- SETTINGS.read().unwrap().to_owned()
- }
-
- pub fn get_database_url(&self) -> String {
- format!(
- "postgres://{}:{}@{}:{}/{}",
- self.database.user,
- self.database.password,
- self.database.host,
- self.database.port,
- self.database.database
- )
- }
-
- pub fn get_config_defaults_location() -> String {
- env::var("LEMMY_CONFIG_DEFAULTS_LOCATION").unwrap_or_else(|_| CONFIG_FILE_DEFAULTS.to_string())
- }
-
- pub fn get_config_location() -> String {
- env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
- }
-
- pub fn read_config_file() -> Result<String, Error> {
- fs::read_to_string(Self::get_config_location())
- }
-
- pub fn get_allowed_instances(&self) -> Vec<String> {
- let mut allowed_instances: Vec<String> = self
- .federation
- .allowed_instances
- .split(',')
- .map(|d| d.trim().to_string())
- .collect();
-
- // The defaults.hjson config always returns a [""]
- allowed_instances.retain(|d| !d.eq(""));
-
- allowed_instances
- }
-
- pub fn get_blocked_instances(&self) -> Vec<String> {
- let mut blocked_instances: Vec<String> = self
- .federation
- .blocked_instances
- .split(',')
- .map(|d| d.trim().to_string())
- .collect();
-
- // The defaults.hjson config always returns a [""]
- blocked_instances.retain(|d| !d.eq(""));
-
- blocked_instances
- }
-
- /// Returns either "http" or "https", depending on tls_enabled setting
- pub fn get_protocol_string(&self) -> &'static str {
- if self.tls_enabled {
- "https"
- } else {
- "http"
- }
- }
-
- /// Returns something like `http://localhost` or `https://lemmy.ml`,
- /// with the correct protocol and hostname.
- pub fn get_protocol_and_hostname(&self) -> String {
- format!("{}://{}", self.get_protocol_string(), self.hostname)
- }
-
- /// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname`
- /// variable will be like `lemmy-alpha:8541`. This method removes the port and returns
- /// `lemmy-alpha` instead. It has no effect in production.
- pub fn get_hostname_without_port(&self) -> Result<String, anyhow::Error> {
- Ok(
- self
- .hostname
- .split(':')
- .collect::<Vec<&str>>()
- .first()
- .context(location_info!())?
- .to_string(),
- )
- }
-
- pub fn save_config_file(data: &str) -> Result<String, Error> {
- fs::write(CONFIG_FILE, data)?;
-
- // Reload the new settings
- // From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
- let mut new_settings = SETTINGS.write().unwrap();
- *new_settings = match Settings::init() {
- Ok(c) => c,
- Err(e) => panic!("{}", e),
- };
-
- Self::read_config_file()
- }
-}
--- /dev/null
+use crate::settings::{CaptchaConfig, DatabaseConfig, FederationConfig, RateLimitConfig, Settings};
+use std::net::{IpAddr, Ipv4Addr};
+
+impl Default for Settings {
+ fn default() -> Self {
+ Self {
+ database: Some(DatabaseConfig::default()),
+ rate_limit: Some(RateLimitConfig::default()),
+ federation: Some(FederationConfig::default()),
+ captcha: Some(CaptchaConfig::default()),
+ email: None,
+ setup: None,
+ hostname: None,
+ bind: Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))),
+ port: Some(8536),
+ tls_enabled: Some(true),
+ jwt_secret: Some("changeme".into()),
+ pictrs_url: Some("http://pictrs:8080".into()),
+ iframely_url: Some("http://iframely".into()),
+ }
+ }
+}
+
+impl Default for DatabaseConfig {
+ fn default() -> Self {
+ Self {
+ user: "lemmy".into(),
+ password: "password".into(),
+ host: "localhost".into(),
+ port: 5432,
+ database: "lemmy".into(),
+ pool_size: 5,
+ }
+ }
+}
+
+impl Default for CaptchaConfig {
+ fn default() -> Self {
+ Self {
+ enabled: true,
+ difficulty: "medium".into(),
+ }
+ }
+}
+
+impl Default for FederationConfig {
+ fn default() -> Self {
+ Self {
+ enabled: false,
+ allowed_instances: None,
+ blocked_instances: None,
+ }
+ }
+}
+
+impl Default for RateLimitConfig {
+ fn default() -> Self {
+ Self {
+ message: 180,
+ message_per_second: 60,
+ post: 6,
+ post_per_second: 600,
+ register: 3,
+ register_per_second: 3600,
+ image: 6,
+ image_per_second: 3600,
+ }
+ }
+}
--- /dev/null
+use crate::{
+ location_info,
+ settings::structs::{
+ CaptchaConfig,
+ DatabaseConfig,
+ EmailConfig,
+ FederationConfig,
+ RateLimitConfig,
+ Settings,
+ SetupConfig,
+ },
+ LemmyError,
+};
+use anyhow::{anyhow, Context};
+use deser_hjson::from_str;
+use merge::Merge;
+use std::{env, fs, io::Error, net::IpAddr, sync::RwLock};
+
+pub(crate) mod defaults;
+pub mod structs;
+
+static CONFIG_FILE: &str = "config/config.hjson";
+
+lazy_static! {
+ static ref SETTINGS: RwLock<Settings> = RwLock::new(match Settings::init() {
+ Ok(c) => c,
+ Err(e) => panic!("{}", e),
+ });
+}
+
+impl Settings {
+ /// Reads config from the files and environment.
+ /// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
+ /// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
+ /// added to the config.
+ ///
+ /// Note: The env var `LEMMY_DATABASE_URL` is parsed in
+ /// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()`
+ fn init() -> Result<Self, LemmyError> {
+ // Read the config file
+ let mut custom_config = from_str::<Settings>(&Self::read_config_file()?)?;
+
+ // Merge with env vars
+ custom_config.merge(envy::prefixed("LEMMY_").from_env::<Settings>()?);
+
+ // Merge with default
+ custom_config.merge(Settings::default());
+
+ if custom_config.hostname == Settings::default().hostname {
+ return Err(anyhow!("Hostname variable is not set!").into());
+ }
+
+ Ok(custom_config)
+ }
+
+ /// Returns the config as a struct.
+ pub fn get() -> Self {
+ SETTINGS.read().unwrap().to_owned()
+ }
+
+ pub fn get_database_url(&self) -> String {
+ let conf = self.database();
+ format!(
+ "postgres://{}:{}@{}:{}/{}",
+ conf.user, conf.password, conf.host, conf.port, conf.database,
+ )
+ }
+
+ pub fn get_config_location() -> String {
+ env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
+ }
+
+ pub fn read_config_file() -> Result<String, Error> {
+ fs::read_to_string(Self::get_config_location())
+ }
+
+ pub fn get_allowed_instances(&self) -> Option<Vec<String>> {
+ self.federation().allowed_instances
+ }
+
+ pub fn get_blocked_instances(&self) -> Option<Vec<String>> {
+ self.federation().blocked_instances
+ }
+
+ /// Returns either "http" or "https", depending on tls_enabled setting
+ pub fn get_protocol_string(&self) -> &'static str {
+ if let Some(tls_enabled) = self.tls_enabled {
+ if tls_enabled {
+ "https"
+ } else {
+ "http"
+ }
+ } else {
+ "http"
+ }
+ }
+
+ /// Returns something like `http://localhost` or `https://lemmy.ml`,
+ /// with the correct protocol and hostname.
+ pub fn get_protocol_and_hostname(&self) -> String {
+ format!("{}://{}", self.get_protocol_string(), self.hostname())
+ }
+
+ /// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname`
+ /// variable will be like `lemmy-alpha:8541`. This method removes the port and returns
+ /// `lemmy-alpha` instead. It has no effect in production.
+ pub fn get_hostname_without_port(&self) -> Result<String, anyhow::Error> {
+ Ok(
+ self
+ .hostname()
+ .split(':')
+ .collect::<Vec<&str>>()
+ .first()
+ .context(location_info!())?
+ .to_string(),
+ )
+ }
+
+ pub fn save_config_file(data: &str) -> Result<String, Error> {
+ fs::write(CONFIG_FILE, data)?;
+
+ // Reload the new settings
+ // From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
+ let mut new_settings = SETTINGS.write().unwrap();
+ *new_settings = match Settings::init() {
+ Ok(c) => c,
+ Err(e) => panic!("{}", e),
+ };
+
+ Self::read_config_file()
+ }
+
+ pub fn database(&self) -> DatabaseConfig {
+ self.database.to_owned().unwrap_or_default()
+ }
+ pub fn hostname(&self) -> String {
+ self.hostname.to_owned().unwrap_or_default()
+ }
+ pub fn bind(&self) -> IpAddr {
+ self.bind.unwrap()
+ }
+ pub fn port(&self) -> u16 {
+ self.port.unwrap_or_default()
+ }
+ pub fn tls_enabled(&self) -> bool {
+ self.tls_enabled.unwrap_or_default()
+ }
+ pub fn jwt_secret(&self) -> String {
+ self.jwt_secret.to_owned().unwrap_or_default()
+ }
+ pub fn pictrs_url(&self) -> String {
+ self.pictrs_url.to_owned().unwrap_or_default()
+ }
+ pub fn iframely_url(&self) -> String {
+ self.iframely_url.to_owned().unwrap_or_default()
+ }
+ pub fn rate_limit(&self) -> RateLimitConfig {
+ self.rate_limit.to_owned().unwrap_or_default()
+ }
+ pub fn federation(&self) -> FederationConfig {
+ self.federation.to_owned().unwrap_or_default()
+ }
+ pub fn captcha(&self) -> CaptchaConfig {
+ self.captcha.to_owned().unwrap_or_default()
+ }
+ pub fn email(&self) -> Option<EmailConfig> {
+ self.email.to_owned()
+ }
+ pub fn setup(&self) -> Option<SetupConfig> {
+ self.setup.to_owned()
+ }
+}
--- /dev/null
+use merge::Merge;
+use serde::Deserialize;
+use std::net::IpAddr;
+
+#[derive(Debug, Deserialize, Clone, Merge)]
+pub struct Settings {
+ pub(crate) database: Option<DatabaseConfig>,
+ pub(crate) rate_limit: Option<RateLimitConfig>,
+ pub(crate) federation: Option<FederationConfig>,
+ pub(crate) hostname: Option<String>,
+ pub(crate) bind: Option<IpAddr>,
+ pub(crate) port: Option<u16>,
+ pub(crate) tls_enabled: Option<bool>,
+ pub(crate) jwt_secret: Option<String>,
+ pub(crate) pictrs_url: Option<String>,
+ pub(crate) iframely_url: Option<String>,
+ pub(crate) captcha: Option<CaptchaConfig>,
+ pub(crate) email: Option<EmailConfig>,
+ pub(crate) setup: Option<SetupConfig>,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct CaptchaConfig {
+ pub enabled: bool,
+ pub difficulty: String,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct DatabaseConfig {
+ pub user: String,
+ pub password: String,
+ pub host: String,
+ pub port: i32,
+ pub database: String,
+ pub pool_size: u32,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct EmailConfig {
+ pub smtp_server: String,
+ pub smtp_login: Option<String>,
+ pub smtp_password: Option<String>,
+ pub smtp_from_address: String,
+ pub use_tls: bool,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct FederationConfig {
+ pub enabled: bool,
+ pub allowed_instances: Option<Vec<String>>,
+ pub blocked_instances: Option<Vec<String>>,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct RateLimitConfig {
+ pub message: i32,
+ pub message_per_second: i32,
+ pub post: i32,
+ pub post_per_second: i32,
+ pub register: i32,
+ pub register_per_second: i32,
+ pub image: i32,
+ pub image_per_second: i32,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct SetupConfig {
+ pub admin_username: String,
+ pub admin_password: String,
+ pub admin_email: Option<String>,
+ pub site_name: String,
+}
-use crate::{settings::Settings, ApiError};
+use crate::{settings::structs::Settings, ApiError};
use actix_web::dev::ConnectionInfo;
use chrono::{DateTime, FixedOffset, NaiveDateTime};
use itertools::Itertools;
impl MentionData {
pub fn is_local(&self) -> bool {
- Settings::get().hostname.eq(&self.domain)
+ Settings::get().hostname().eq(&self.domain)
}
pub fn full_name(&self) -> String {
format!("@{}@{}", &self.name, &self.domain)
RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy
# Copy resources
-COPY --chown=lemmy:lemmy config/defaults.hjson /config/defaults.hjson
COPY --chown=lemmy:lemmy --from=builder /app/lemmy_server /app/lemmy
RUN chown lemmy:lemmy /app/lemmy
- lemmy-alpha
lemmy-alpha:
image: lemmy-federation:latest
+ volumes:
+ - ./lemmy_alpha.hjson:/config/config.hjson
environment:
- - LEMMY_HOSTNAME=lemmy-alpha:8541
- - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_alpha:5432/lemmy
- - LEMMY_JWT_SECRET=changeme
- - LEMMY_FEDERATION__ENABLED=true
- - LEMMY_TLS_ENABLED=false
- - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma,lemmy-delta,lemmy-epsilon
- - LEMMY_PORT=8541
- - LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha
- - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
- - LEMMY_SETUP__SITE_NAME=lemmy-alpha
- - LEMMY_RATE_LIMIT__POST=99999
- - LEMMY_RATE_LIMIT__REGISTER=99999
- - LEMMY_CAPTCHA__ENABLED=false
- LEMMY_TEST_SEND_SYNC=1
- RUST_BACKTRACE=1
- RUST_LOG=debug
- lemmy-beta
lemmy-beta:
image: lemmy-federation:latest
+ volumes:
+ - ./lemmy_beta.hjson:/config/config.hjson
environment:
- - LEMMY_HOSTNAME=lemmy-beta:8551
- - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_beta:5432/lemmy
- - LEMMY_JWT_SECRET=changeme
- - LEMMY_FEDERATION__ENABLED=true
- - LEMMY_TLS_ENABLED=false
- - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma,lemmy-delta,lemmy-epsilon
- - LEMMY_PORT=8551
- - LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta
- - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
- - LEMMY_SETUP__SITE_NAME=lemmy-beta
- - LEMMY_RATE_LIMIT__POST=99999
- - LEMMY_RATE_LIMIT__REGISTER=99999
- - LEMMY_CAPTCHA__ENABLED=false
- LEMMY_TEST_SEND_SYNC=1
- RUST_BACKTRACE=1
- RUST_LOG=debug
- lemmy-gamma
lemmy-gamma:
image: lemmy-federation:latest
+ volumes:
+ - ./lemmy_gamma.hjson:/config/config.hjson
environment:
- - LEMMY_HOSTNAME=lemmy-gamma:8561
- - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_gamma:5432/lemmy
- - LEMMY_JWT_SECRET=changeme
- - LEMMY_FEDERATION__ENABLED=true
- - LEMMY_TLS_ENABLED=false
- - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta,lemmy-delta,lemmy-epsilon
- - LEMMY_PORT=8561
- - LEMMY_SETUP__ADMIN_USERNAME=lemmy_gamma
- - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
- - LEMMY_SETUP__SITE_NAME=lemmy-gamma
- - LEMMY_RATE_LIMIT__POST=99999
- - LEMMY_RATE_LIMIT__REGISTER=99999
- - LEMMY_CAPTCHA__ENABLED=false
- LEMMY_TEST_SEND_SYNC=1
- RUST_BACKTRACE=1
- RUST_LOG=debug
- lemmy-delta
lemmy-delta:
image: lemmy-federation:latest
+ volumes:
+ - ./lemmy_delta.hjson:/config/config.hjson
environment:
- - LEMMY_HOSTNAME=lemmy-delta:8571
- - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_delta:5432/lemmy
- - LEMMY_JWT_SECRET=changeme
- - LEMMY_FEDERATION__ENABLED=true
- - LEMMY_TLS_ENABLED=false
- - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta
- - LEMMY_PORT=8571
- - LEMMY_SETUP__ADMIN_USERNAME=lemmy_delta
- - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
- - LEMMY_SETUP__SITE_NAME=lemmy-delta
- - LEMMY_RATE_LIMIT__POST=99999
- - LEMMY_RATE_LIMIT__REGISTER=99999
- - LEMMY_CAPTCHA__ENABLED=false
- LEMMY_TEST_SEND_SYNC=1
- RUST_BACKTRACE=1
- RUST_LOG=debug
- lemmy-epsilon
lemmy-epsilon:
image: lemmy-federation:latest
+ volumes:
+ - ./lemmy_epsilon.hjson:/config/config.hjson
environment:
- - LEMMY_HOSTNAME=lemmy-epsilon:8581
- - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_epsilon:5432/lemmy
- - LEMMY_JWT_SECRET=changeme
- - LEMMY_FEDERATION__ENABLED=true
- - LEMMY_TLS_ENABLED=false
- - LEMMY_FEDERATION__BLOCKED_INSTANCES=lemmy-alpha
- - LEMMY_PORT=8581
- - LEMMY_SETUP__ADMIN_USERNAME=lemmy_epsilon
- - LEMMY_SETUP__ADMIN_PASSWORD=lemmy
- - LEMMY_SETUP__SITE_NAME=lemmy-epsilon
- - LEMMY_RATE_LIMIT__POST=99999
- - LEMMY_RATE_LIMIT__REGISTER=99999
- - LEMMY_CAPTCHA__ENABLED=false
- LEMMY_TEST_SEND_SYNC=1
- RUST_BACKTRACE=1
- RUST_LOG=debug
--- /dev/null
+{
+ port: 8541
+ tls_enabled: false
+ jwt_secret: changeme
+ setup: {
+ admin_username: lemmy_alpha
+ admin_password: lemmy
+ site_name: lemmy-alpha
+ }
+ database: {
+ database: lemmy
+ user: lemmy
+ password: password
+ host: postgres_alpha
+ port: 5432
+ pool_size: 5
+ }
+ federation: {
+ enabled: true
+ allowed_instances: ["lemmy-beta","lemmy-gamma","lemmy-delta","lemmy-epsilon"]
+ }
+ captcha: {
+ enabled: false
+ difficulty: medium
+ }
+ rate_limit: {
+ message: 180
+ message_per_second: 60
+ post: 99999
+ post_per_second: 600
+ register: 99999
+ register_per_second: 3600
+ image: 6
+ image_per_second: 3600
+ }
+}
--- /dev/null
+{
+ hostname: lemmy-beta:8551
+ port: 8551
+ tls_enabled: false
+ jwt_secret: changeme
+ setup: {
+ admin_username: lemmy_beta
+ admin_password: lemmy
+ site_name: lemmy-beta
+ }
+ database: {
+ database: lemmy
+ user: lemmy
+ password: password
+ host: postgres_beta
+ port: 5432
+ pool_size: 5
+ }
+ federation: {
+ enabled: true
+ allowed_instances: ["lemmy-alpha","lemmy-gamma","lemmy-delta","lemmy-epsilon"]
+ }
+ captcha: {
+ enabled: false
+ difficulty: medium
+ }
+ rate_limit: {
+ message: 180
+ message_per_second: 60
+ post: 99999
+ post_per_second: 600
+ register: 99999
+ register_per_second: 3600
+ image: 6
+ image_per_second: 3600
+ }
+}
--- /dev/null
+{
+ hostname: lemmy-delta:8571
+ port: 8571
+ tls_enabled: false
+ jwt_secret: changeme
+ setup: {
+ admin_username: lemmy_delta
+ admin_password: lemmy
+ site_name: lemmy-delta
+ }
+ database: {
+ database: lemmy
+ user: lemmy
+ password: password
+ host: postgres_delta
+ port: 5432
+ pool_size: 5
+ }
+ federation: {
+ enabled: true
+ allowed_instances: ["lemmy-beta"]
+ }
+ captcha: {
+ enabled: false
+ difficulty: medium
+ }
+ rate_limit: {
+ message: 180
+ message_per_second: 60
+ post: 99999
+ post_per_second: 600
+ register: 99999
+ register_per_second: 3600
+ image: 6
+ image_per_second: 3600
+ }
+}
--- /dev/null
+{
+ hostname: lemmy-epsilon:8581
+ port: 8581
+ tls_enabled: false
+ jwt_secret: changeme
+ setup: {
+ admin_username: lemmy_epsilon
+ admin_password: lemmy
+ site_name: lemmy-epsilon
+ }
+ database: {
+ database: lemmy
+ user: lemmy
+ password: password
+ host: postgres_epsilon
+ port: 5432
+ pool_size: 5
+ }
+ federation: {
+ enabled: true
+ blocked_instances: ["lemmy-alpha"]
+ }
+ captcha: {
+ enabled: false
+ difficulty: medium
+ }
+ rate_limit: {
+ message: 180
+ message_per_second: 60
+ post: 99999
+ post_per_second: 600
+ register: 99999
+ register_per_second: 3600
+ image: 6
+ image_per_second: 3600
+ }
+}
--- /dev/null
+{
+ hostname: lemmy-gamma:8561
+ port: 8561
+ tls_enabled: false
+ jwt_secret: changeme
+ setup: {
+ admin_username: lemmy_gamma
+ admin_password: lemmy
+ site_name: lemmy-gamma
+ }
+ database: {
+ database: lemmy
+ user: lemmy
+ password: password
+ host: postgres_gamma
+ port: 5432
+ pool_size: 5
+ }
+ federation: {
+ enabled: true
+ allowed_instances: ["lemmy-alpha","lemmy-beta","lemmy-delta","lemmy-epsilon"]
+ }
+ captcha: {
+ enabled: false
+ difficulty: medium
+ }
+ rate_limit: {
+ message: 180
+ message_per_second: 60
+ post: 99999
+ post_per_second: 600
+ register: 99999
+ register_per_second: 3600
+ image: 6
+ image_per_second: 3600
+ }
+}
password: "password"
# host where postgres is running
host: "postgres"
+ # port where postgres can be accessed
+ port: 5432
+ # maximum number of active sql connections
+ pool_size: 5
}
# # optional: email sending configuration
# email: {
RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy
# Copy resources
-COPY --chown=lemmy:lemmy config/defaults.hjson /config/defaults.hjson
COPY --chown=lemmy:lemmy --from=builder /app/lemmy_server /app/lemmy
RUN chown lemmy:lemmy /app/lemmy
RUN adduser --no-create-home --shell /bin/sh --uid 1000 --gid 1000 lemmy
# Copy resources
-COPY --chown=lemmy:lemmy config/defaults.hjson /config/defaults.hjson
COPY --chown=lemmy:lemmy --from=builder /app/lemmy_server /app/lemmy
RUN chown lemmy:lemmy /app/lemmy
user::{UserForm, User_},
},
};
-use lemmy_utils::{apub::generate_actor_keypair, settings::Settings, LemmyError};
+use lemmy_utils::{apub::generate_actor_keypair, settings::structs::Settings, LemmyError};
use log::info;
pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), LemmyError> {
use lemmy_server::{code_migrations::run_advanced_migrations, scheduled_tasks};
use lemmy_utils::{
rate_limit::{rate_limiter::RateLimiter, RateLimit},
- settings::Settings,
+ settings::structs::Settings,
LemmyError,
};
use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
};
let manager = ConnectionManager::<PgConnection>::new(&db_url);
let pool = Pool::builder()
- .max_size(settings.database.pool_size)
+ .max_size(settings.database().pool_size)
.build(manager)
.unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
println!(
"Starting http server at {}:{}",
- settings.bind, settings.port
+ settings.bind(),
+ settings.port()
);
let activity_queue = create_activity_queue();
.configure(nodeinfo::config)
.configure(webfinger::config)
})
- .bind((settings.bind, settings.port))?
+ .bind((settings.bind(), settings.port()))?
.run()
.await?;