use oiseau::config::{Configuration, DatabaseConfig};
use pathbufd::PathBufD;
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::Result;
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct SecurityConfig {
#[serde(default = "default_security_registration_enabled")]
pub registration_enabled: bool,
#[serde(default = "default_real_ip_header")]
pub real_ip_header: String,
#[serde(default = "default_enable_invite_codes")]
pub enable_invite_codes: bool,
}
fn default_security_registration_enabled() -> bool {
true
}
fn default_real_ip_header() -> String {
"CF-Connecting-IP".to_string()
}
fn default_enable_invite_codes() -> bool {
false
}
impl Default for SecurityConfig {
fn default() -> Self {
Self {
registration_enabled: default_security_registration_enabled(),
real_ip_header: default_real_ip_header(),
enable_invite_codes: default_enable_invite_codes(),
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct DirsConfig {
#[serde(default = "default_dir_templates")]
pub templates: String,
#[serde(default = "default_dir_assets")]
pub assets: String,
#[serde(default = "default_dir_media")]
pub media: String,
#[serde(default = "default_dir_icons")]
pub icons: String,
#[serde(default = "default_dir_docs")]
pub docs: String,
#[serde(default = "default_dir_rustdoc")]
pub rustdoc: String,
}
fn default_dir_templates() -> String {
"html".to_string()
}
fn default_dir_assets() -> String {
"public".to_string()
}
fn default_dir_media() -> String {
"media".to_string()
}
fn default_dir_icons() -> String {
"icons".to_string()
}
fn default_dir_docs() -> String {
"docs".to_string()
}
fn default_dir_rustdoc() -> String {
"reference".to_string()
}
impl Default for DirsConfig {
fn default() -> Self {
Self {
templates: default_dir_templates(),
assets: default_dir_assets(),
media: default_dir_media(),
icons: default_dir_icons(),
docs: default_dir_docs(),
rustdoc: default_dir_rustdoc(),
}
}
}
impl Configuration for Config {
fn db_config(&self) -> DatabaseConfig {
self.database.to_owned()
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct PoliciesConfig {
pub terms_of_service: String,
pub privacy: String,
#[serde(default)]
pub last_updated: usize,
}
impl Default for PoliciesConfig {
fn default() -> Self {
Self {
terms_of_service: "/public/tos.html".to_string(),
privacy: "/public/privacy.html".to_string(),
last_updated: 0,
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct TurnstileConfig {
pub site_key: String,
pub secret_key: String,
}
impl Default for TurnstileConfig {
fn default() -> Self {
Self {
site_key: "1x00000000000000000000AA".to_string(), secret_key: "1x0000000000000000000000000000000AA".to_string(), }
}
}
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct ConnectionsConfig {
#[serde(default)]
pub spotify_client_id: Option<String>,
#[serde(default)]
pub last_fm_key: Option<String>,
#[serde(default)]
pub last_fm_secret: Option<String>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct StripeConfig {
pub secret: String,
pub payment_links: StripePaymentLinks,
pub webhook_signing_secret: String,
pub billing_portal_url: String,
pub price_texts: StripePriceTexts,
pub product_ids: StripeProductIds,
pub price_ids: StripePriceIds,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct StripePriceTexts {
pub supporter: String,
pub dev_pass: String,
pub coins_100: String,
pub coins_400: String,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct StripePaymentLinks {
pub supporter: String,
pub dev_pass: String,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct StripeProductIds {
pub supporter: String,
pub dev_pass: String,
pub coins_100: String,
pub coins_400: String,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct StripePriceIds {
pub coins_100: String,
pub coins_400: String,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct ManualsConfig {
pub search_help: String,
}
impl Default for ManualsConfig {
fn default() -> Self {
Self {
search_help: "".to_string(),
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct ServiceHostsConfig {
pub buckets: String,
#[serde(default)]
pub littleweb: String,
#[serde(default)]
pub tawny: String,
}
impl Default for ServiceHostsConfig {
fn default() -> Self {
Self {
buckets: String::new(),
littleweb: String::new(),
tawny: String::new(),
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
pub enum StringBan {
String(String),
Unicode(u32),
}
impl Default for StringBan {
fn default() -> Self {
Self::String(String::new())
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Config {
#[serde(default = "default_name")]
pub name: String,
#[serde(default = "default_description")]
pub description: String,
#[serde(default = "default_color")]
pub color: String,
#[serde(default = "default_port")]
pub port: u16,
#[serde(default = "default_banned_hosts")]
pub banned_hosts: Vec<String>,
#[serde(default = "default_host")]
pub host: String,
#[serde(default = "default_service_hosts")]
pub service_hosts: ServiceHostsConfig,
#[serde(default = "default_security")]
pub security: SecurityConfig,
#[serde(default = "default_dirs")]
pub dirs: DirsConfig,
#[serde(default = "default_database")]
pub database: DatabaseConfig,
#[serde(default = "default_no_track")]
pub no_track: Vec<String>,
#[serde(default = "default_banned_usernames")]
pub banned_usernames: Vec<String>,
#[serde(default = "default_policies")]
pub policies: PoliciesConfig,
#[serde(default = "default_turnstile")]
pub turnstile: TurnstileConfig,
#[serde(default)]
pub town_square: usize,
#[serde(default)]
pub town_square_forum: usize,
#[serde(default)]
pub town_square_forum_topic: usize,
#[serde(default)]
pub system_user: usize,
#[serde(default)]
pub connections: ConnectionsConfig,
#[serde(default)]
pub html_footer_path: String,
#[serde(default)]
pub stripe: Option<StripeConfig>,
#[serde(default)]
pub manuals: ManualsConfig,
#[serde(default)]
pub banned_data: Vec<StringBan>,
#[serde(default)]
pub enable_user_ads: bool,
}
fn default_name() -> String {
"Tetratto".to_string()
}
fn default_description() -> String {
"🐇 tetratto!".to_string()
}
fn default_color() -> String {
"#c9b1bc".to_string()
}
fn default_port() -> u16 {
4118
}
fn default_banned_hosts() -> Vec<String> {
Vec::new()
}
fn default_host() -> String {
String::new()
}
fn default_service_hosts() -> ServiceHostsConfig {
ServiceHostsConfig::default()
}
fn default_security() -> SecurityConfig {
SecurityConfig::default()
}
fn default_dirs() -> DirsConfig {
DirsConfig::default()
}
fn default_database() -> DatabaseConfig {
DatabaseConfig::default()
}
fn default_no_track() -> Vec<String> {
Vec::new()
}
fn default_banned_usernames() -> Vec<String> {
vec![
"admin".to_string(),
"owner".to_string(),
"moderator".to_string(),
"api".to_string(),
"communities".to_string(),
"community".to_string(),
"notifs".to_string(),
"notification".to_string(),
"post".to_string(),
"void".to_string(),
"anonymous".to_string(),
"stacks".to_string(),
"stack".to_string(),
"search".to_string(),
"journals".to_string(),
"links".to_string(),
"app".to_string(),
"services".to_string(),
"domains".to_string(),
"mail".to_string(),
"product".to_string(),
"wallet".to_string(),
"products".to_string(),
]
}
fn default_policies() -> PoliciesConfig {
PoliciesConfig::default()
}
fn default_turnstile() -> TurnstileConfig {
TurnstileConfig::default()
}
fn default_connections() -> ConnectionsConfig {
ConnectionsConfig::default()
}
fn default_manuals() -> ManualsConfig {
ManualsConfig::default()
}
fn default_banned_data() -> Vec<StringBan> {
Vec::new()
}
impl Default for Config {
fn default() -> Self {
Self {
name: default_name(),
description: default_description(),
color: default_color(),
port: default_port(),
banned_hosts: default_banned_hosts(),
host: default_host(),
service_hosts: default_service_hosts(),
database: default_database(),
security: default_security(),
dirs: default_dirs(),
no_track: default_no_track(),
banned_usernames: default_banned_usernames(),
policies: default_policies(),
turnstile: default_turnstile(),
town_square: 0,
town_square_forum: 0,
town_square_forum_topic: 0,
system_user: 0,
connections: default_connections(),
html_footer_path: String::new(),
stripe: None,
manuals: default_manuals(),
banned_data: default_banned_data(),
enable_user_ads: false,
}
}
}
impl Config {
pub fn read(contents: String) -> Self {
toml::from_str::<Self>(&contents).unwrap()
}
pub fn get_config() -> Self {
let path = PathBufD::current().join("tetratto.toml");
match fs::read_to_string(&path) {
Ok(c) => Config::read(c),
Err(_) => {
Self::update_config(Self::default()).expect("failed to write default config");
Self::default()
}
}
}
pub fn update_config(contents: Self) -> Result<()> {
let c = fs::canonicalize(".").unwrap();
let here = c.to_str().unwrap();
fs::write(
format!("{here}/tetratto.toml"),
toml::to_string_pretty::<Self>(&contents).unwrap(),
)
}
}