mirror of https://github.com/spikecodes/libreddit
Addresses #50, #55. Co-authored-by: Daniel Valentine <Daniel-Valentine@users.noreply.github.com>
This commit is contained in:
parent
401061b7b7
commit
6a68241a7c
|
@ -356,14 +356,17 @@ dependencies = [
|
||||||
"hyper-rustls",
|
"hyper-rustls",
|
||||||
"libflate",
|
"libflate",
|
||||||
"lipsum",
|
"lipsum",
|
||||||
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"regex",
|
"regex",
|
||||||
"route-recognizer",
|
"route-recognizer",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
|
"sealed_test",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -382,6 +385,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fs_extra"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.24"
|
version = "0.3.24"
|
||||||
|
@ -768,9 +777,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.15.0"
|
version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
|
@ -846,6 +855,12 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.21"
|
version = "1.0.21"
|
||||||
|
@ -911,6 +926,15 @@ version = "0.6.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remove_dir_all"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.16.20"
|
version = "0.16.20"
|
||||||
|
@ -1005,6 +1029,18 @@ dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusty-forkfork"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ce85af4dfa2fb0c0143121ab5e424c71ea693867357c9159b8777b59984c218"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"quick-error",
|
||||||
|
"tempfile",
|
||||||
|
"wait-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
@ -1046,6 +1082,28 @@ dependencies = [
|
||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sealed_test"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a608d94641cc17fe203b102db2ae86d47a236630192f0244ddbbbb0044c0272"
|
||||||
|
dependencies = [
|
||||||
|
"fs_extra",
|
||||||
|
"rusty-forkfork",
|
||||||
|
"sealed_test_derive",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sealed_test_derive"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b672e005ae58fef5da619d90b9f1c5b44b061890f4a371b3c96257a8a15e697"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
|
@ -1168,6 +1226,20 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"remove_dir_all",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.15.1"
|
version = "0.15.1"
|
||||||
|
@ -1284,6 +1356,15 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-service"
|
name = "tower-service"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -1375,6 +1456,15 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waker-fn"
|
name = "waker-fn"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
|
@ -27,6 +27,9 @@ url = "2.2.2"
|
||||||
rust-embed = "6.4.0"
|
rust-embed = "6.4.0"
|
||||||
libflate = "1.2.0"
|
libflate = "1.2.0"
|
||||||
brotli = { version = "3.3.4", features = ["std"] }
|
brotli = { version = "3.3.4", features = ["std"] }
|
||||||
|
toml = "0.5.9"
|
||||||
|
once_cell = "1.16.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lipsum = "0.8.2"
|
lipsum = "0.8.2"
|
||||||
|
sealed_test = "1.0.0"
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::env::var;
|
||||||
|
|
||||||
|
// Waiting for https://github.com/rust-lang/rust/issues/74465 to land, so we
|
||||||
|
// can reduce reliance on once_cell.
|
||||||
|
//
|
||||||
|
// This is the local static that is initialized at runtime (technically at
|
||||||
|
// first request) and contains the instance settings.
|
||||||
|
static CONFIG: Lazy<Config> = Lazy::new(Config::load);
|
||||||
|
|
||||||
|
/// Stores the configuration parsed from the environment variables and the
|
||||||
|
/// config file. `Config::Default()` contains None for each setting.
|
||||||
|
#[derive(Default, serde::Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
#[serde(rename = "FERRIT_SFW_ONLY")]
|
||||||
|
sfw_only: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_THEME")]
|
||||||
|
default_theme: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_FRONT_PAGE")]
|
||||||
|
default_front_page: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_LAYOUT")]
|
||||||
|
default_layout: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_WIDE")]
|
||||||
|
default_wide: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_COMMENT_SORT")]
|
||||||
|
default_comment_sort: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_POST_SORT")]
|
||||||
|
default_post_sort: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_SHOW_NSFW")]
|
||||||
|
default_show_nsfw: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_BLUR_NSFW")]
|
||||||
|
default_blur_nsfw: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_USE_HLS")]
|
||||||
|
default_use_hls: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "FERRIT_DEFAULT_HIDE_HLS_NOTIFICATION")]
|
||||||
|
default_hide_hls_notification: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
/// Load the configuration from the environment variables and the config file.
|
||||||
|
/// In the case that there are no environment variables set and there is no
|
||||||
|
/// config file, this function returns a Config that contains all None values.
|
||||||
|
pub fn load() -> Self {
|
||||||
|
// Read from ferrit.toml config file. If for any reason, it fails, the
|
||||||
|
// default `Config` is used (all None values)
|
||||||
|
let config: Config = toml::from_str(&std::fs::read_to_string("ferrit.toml").unwrap_or_default()).unwrap_or_default();
|
||||||
|
// This function defines the order of preference - first check for
|
||||||
|
// environment variables with "FERRIT", then check for environment variables
|
||||||
|
// with "LIBREDDIT" for reverse compatibility, then check the config, then if
|
||||||
|
// both are `None`, return a `None` via the `map_or_else` function
|
||||||
|
let parse = |key: &str| -> Option<String> {
|
||||||
|
var(key)
|
||||||
|
.ok()
|
||||||
|
.map_or_else(|| var(key.replace("FERRIT", "LIBREDDIT")).ok(), Some)
|
||||||
|
.map_or_else(|| get_setting_from_config(key, &config), Some)
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
sfw_only: parse("FERRIT_SFW_ONLY"),
|
||||||
|
default_theme: parse("FERRIT_DEFAULT_THEME"),
|
||||||
|
default_front_page: parse("FERRIT_DEFAULT_FRONT_PAGE"),
|
||||||
|
default_layout: parse("FERRIT_DEFAULT_LAYOUT"),
|
||||||
|
default_post_sort: parse("FERRIT_DEFAULT_POST_SORT"),
|
||||||
|
default_wide: parse("FERRIT_DEFAULT_WIDE"),
|
||||||
|
default_comment_sort: parse("FERRIT_DEFAULT_COMMENT_SORT"),
|
||||||
|
default_show_nsfw: parse("FERRIT_DEFAULT_SHOW_NSFW"),
|
||||||
|
default_blur_nsfw: parse("FERRIT_DEFAULT_BLUR_NSFW"),
|
||||||
|
default_use_hls: parse("FERRIT_DEFAULT_USE_HLS"),
|
||||||
|
default_hide_hls_notification: parse("FERRIT_DEFAULT_HIDE_HLS"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_setting_from_config(name: &str, config: &Config) -> Option<String> {
|
||||||
|
match name {
|
||||||
|
"FERRIT_SFW_ONLY" => config.sfw_only.clone(),
|
||||||
|
"FERRIT_DEFAULT_THEME" => config.default_theme.clone(),
|
||||||
|
"FERRIT_DEFAULT_FRONT_PAGE" => config.default_front_page.clone(),
|
||||||
|
"FERRIT_DEFAULT_LAYOUT" => config.default_layout.clone(),
|
||||||
|
"FERRIT_DEFAULT_COMMENT_SORT" => config.default_comment_sort.clone(),
|
||||||
|
"FERRIT_DEFAULT_POST_SORT" => config.default_post_sort.clone(),
|
||||||
|
"FERRIT_DEFAULT_SHOW_NSFW" => config.default_show_nsfw.clone(),
|
||||||
|
"FERRIT_DEFAULT_BLUR_NSFW" => config.default_blur_nsfw.clone(),
|
||||||
|
"FERRIT_DEFAULT_USE_HLS" => config.default_use_hls.clone(),
|
||||||
|
"FERRIT_DEFAULT_HIDE_HLS_NOTIFICATION" => config.default_hide_hls_notification.clone(),
|
||||||
|
"FERRIT_DEFAULT_WIDE" => config.default_wide.clone(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves setting from environment variable or config file.
|
||||||
|
pub(crate) fn get_setting(name: &str) -> Option<String> {
|
||||||
|
get_setting_from_config(name, &CONFIG)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use sealed_test::prelude::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[sealed_test(env = [("FERRIT_SFW_ONLY", "1")])]
|
||||||
|
fn test_env_var() {
|
||||||
|
assert!(crate::utils::sfw_only())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[sealed_test(env = [("FERRIT_DEFAULT_COMMENT_SORT", "top"), ("LIBREDDIT_DEFAULT_COMMENT_SORT", "best")])]
|
||||||
|
fn test_env_precedence() {
|
||||||
|
assert_eq!(crate::config::get_setting("FERRIT_DEFAULT_COMMENT_SORT"), Some("top".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[sealed_test]
|
||||||
|
fn test_config() {
|
||||||
|
let config_to_write = r#"FERRIT_DEFAULT_COMMENT_SORT = "best""#;
|
||||||
|
std::fs::write("ferrit.toml", config_to_write).unwrap();
|
||||||
|
assert_eq!(crate::config::get_setting("FERRIT_DEFAULT_COMMENT_SORT"), Some("best".into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[sealed_test(env = [("FERRIT_DEFAULT_COMMENT_SORT", "top")])]
|
||||||
|
fn test_env_config_precedence() {
|
||||||
|
let config_to_write = r#"FERRIT_DEFAULT_COMMENT_SORT = "best""#;
|
||||||
|
std::fs::write("ferrit.toml", config_to_write).unwrap();
|
||||||
|
assert_eq!(crate::config::get_setting("FERRIT_DEFAULT_COMMENT_SORT"), Some("top".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[sealed_test(env = [("LIBREDDIT_DEFAULT_COMMENT_SORT", "top")])]
|
||||||
|
fn test_alt_env_config_precedence() {
|
||||||
|
let config_to_write = r#"FERRIT_DEFAULT_COMMENT_SORT = "best""#;
|
||||||
|
std::fs::write("Ferrit.toml", config_to_write).unwrap();
|
||||||
|
assert_eq!(crate::config::get_setting("FERRIT_DEFAULT_COMMENT_SORT"), Some("top".into()))
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#![allow(clippy::cmp_owned)]
|
#![allow(clippy::cmp_owned)]
|
||||||
|
|
||||||
// Reference local files
|
// Reference local files
|
||||||
|
mod config;
|
||||||
mod duplicates;
|
mod duplicates;
|
||||||
mod post;
|
mod post;
|
||||||
mod search;
|
mod search;
|
||||||
|
|
11
src/utils.rs
11
src/utils.rs
|
@ -680,8 +680,8 @@ pub fn setting(req: &Request<Body>, name: &str) -> String {
|
||||||
req
|
req
|
||||||
.cookie(name)
|
.cookie(name)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
// If there is no cookie for this setting, try receiving a default from an environment variable
|
// If there is no cookie for this setting, try receiving a default from the config
|
||||||
if let Ok(default) = std::env::var(format!("FERRIT_DEFAULT_{}", name.to_uppercase())) {
|
if let Some(default) = crate::config::get_setting(&format!("FERRIT_DEFAULT_{}", name.to_uppercase())) {
|
||||||
Cookie::new(name, default)
|
Cookie::new(name, default)
|
||||||
} else {
|
} else {
|
||||||
Cookie::named(name)
|
Cookie::named(name)
|
||||||
|
@ -866,11 +866,10 @@ pub async fn error(req: Request<Body>, msg: impl ToString) -> Result<Response<Bo
|
||||||
Ok(Response::builder().status(404).header("content-type", "text/html").body(body.into()).unwrap_or_default())
|
Ok(Response::builder().status(404).header("content-type", "text/html").body(body.into()).unwrap_or_default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the FERRIT_SFW_ONLY environment variable to anything, to enable SFW-only mode.
|
/// Retrieve the `FERRIT_SFW_ONLY` setting value from the config, based on
|
||||||
/// If environment variable is set, this bool will be true. Otherwise it will be false.
|
/// environment variables and the config file.
|
||||||
/// This variable is set by the instance operator, and as such, side-steps the user config
|
|
||||||
pub fn sfw_only() -> bool {
|
pub fn sfw_only() -> bool {
|
||||||
env::var("FERRIT_SFW_ONLY").is_ok()
|
crate::config::get_setting("FERRIT_SFW_ONLY").is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render the landing page for NSFW content when the user has not enabled
|
/// Render the landing page for NSFW content when the user has not enabled
|
||||||
|
|
Loading…
Reference in New Issue