Skip to main content

lfsx_server/
config.rs

1use std::net::SocketAddr;
2use std::path::PathBuf;
3use std::time::Duration;
4
5use crate::model::Action;
6use crate::namespace::Namespace;
7
8#[derive(Debug, Clone)]
9pub struct Config {
10    pub bind: SocketAddr,
11    pub storage_root: PathBuf,
12    pub public_url: String,
13    pub action_lifetime: u32,
14    pub gc_grace: Duration,
15    pub auth: Auth,
16}
17
18#[derive(Debug, Clone)]
19pub enum Auth {
20    Github {
21        api_url: String,
22        cache_ttl: Duration,
23        rejection_ttl: Duration,
24    },
25    Disabled,
26}
27
28const GITHUB_API_URL: &str = "https://api.github.com";
29const CACHE_TTL: Duration = Duration::from_secs(60);
30const REJECTION_TTL: Duration = Duration::from_secs(10);
31const GC_GRACE: Duration = Duration::from_secs(14 * 24 * 60 * 60);
32
33impl Config {
34    pub fn from_env() -> Self {
35        let bind = std::env::var("LFSX_BIND")
36            .ok()
37            .and_then(|raw| raw.parse().ok())
38            .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], 8080)));
39
40        let storage_root = std::env::var("LFSX_STORAGE_ROOT")
41            .map(PathBuf::from)
42            .unwrap_or_else(|_| PathBuf::from("/var/lib/lfsx"));
43
44        let public_url = std::env::var("LFSX_PUBLIC_URL")
45            .unwrap_or_else(|_| format!("http://{bind}"))
46            .trim_end_matches('/')
47            .to_owned();
48
49        Self {
50            bind,
51            storage_root,
52            public_url,
53            action_lifetime: 1800,
54            gc_grace: seconds("LFSX_GC_GRACE").unwrap_or(GC_GRACE),
55            auth: Auth::from_env(),
56        }
57    }
58
59    pub fn object_url(&self, ns: &Namespace, oid: &str) -> String {
60        format!("{}/{ns}/objects/{oid}", self.public_url)
61    }
62
63    pub fn verify_url(&self, ns: &Namespace) -> String {
64        format!("{}/{ns}/objects/verify", self.public_url)
65    }
66
67    pub fn action(&self, href: String) -> Action {
68        Action {
69            href,
70            expires_in: self.action_lifetime,
71        }
72    }
73}
74
75impl Auth {
76    fn from_env() -> Self {
77        if std::env::var("LFSX_AUTH").as_deref() == Ok("disabled") {
78            tracing::warn!(
79                "LFSX_AUTH=disabled — every request is accepted, run this on a trusted network only"
80            );
81            return Self::Disabled;
82        }
83
84        let api_url = std::env::var("LFSX_GITHUB_API_URL")
85            .unwrap_or_else(|_| GITHUB_API_URL.to_owned())
86            .trim_end_matches('/')
87            .to_owned();
88
89        let cache_ttl = seconds("LFSX_AUTH_CACHE_TTL").unwrap_or(CACHE_TTL);
90
91        let rejection_ttl = seconds("LFSX_AUTH_REJECTION_TTL").unwrap_or(REJECTION_TTL);
92
93        Self::Github {
94            api_url,
95            cache_ttl,
96            rejection_ttl,
97        }
98    }
99}
100
101fn seconds(variable: &str) -> Option<Duration> {
102    std::env::var(variable)
103        .ok()
104        .and_then(|raw| raw.parse().ok())
105        .map(Duration::from_secs)
106}