Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
3.4 kB · 101 lines
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102use std::{ net::SocketAddr, path::{Path, PathBuf},};
use anyhow::{Context, ensure};use base64::{Engine, engine::general_purpose::STANDARD};use confique::Config as _;use jacquard_common::types::string::Did;use k256::ecdsa::SigningKey;
#[derive(confique::Config)]pub struct Config { #[config(env = "GATE_BIND", default = "0.0.0.0:3100")] pub bind: SocketAddr, #[config(env = "GATE_DID")] pub did: String, #[config(env = "GATE_SIGNING_KEY")] pub signing_key: String, #[config(env = "GATE_TRANQUIL_URL")] pub tranquil_url: String, #[config(env = "GATE_TRANQUIL_DID")] pub tranquil_did: String, #[config(env = "GATE_DELIBERI_URL")] pub deliberi_url: String, #[config(env = "GATE_DELIBERI_DID")] pub deliberi_did: String, #[config(env = "GATE_PLC_URL")] pub plc_url: String, #[config(env = "GATE_EXTRA_CA_FILE")] pub extra_ca_file: Option<PathBuf>, #[config(env = "GATE_REQUIRE_VERIFIED_EMAIL", default = true)] pub require_verified_email: bool, #[config(nested)] pub log: LogConfig,}
#[derive(confique::Config)]pub struct LogConfig { #[config(env = "GATE_LOG_FORMAT", default = "text")] pub format: String, #[config(env = "RUST_LOG", default = "info")] pub filter: String,}
impl Config { pub fn load(path: Option<&Path>) -> anyhow::Result<Self> { let mut builder = Self::builder().env(); if let Some(path) = path { builder = builder.preloaded(confique::File::new(path)?.required().load()?); } let config = builder .file("/etc/tranquil-gate/config.toml") .load() .context("load gate configuration")?; config.validate()?; Ok(config) }
pub fn validate(&self) -> anyhow::Result<()> { for (name, value) in [ ("did", &self.did), ("tranquil_did", &self.tranquil_did), ("deliberi_did", &self.deliberi_did), ] { Did::new(value.as_str()).with_context(|| format!("invalid {name}"))?; } for (name, value) in [ ("tranquil_url", &self.tranquil_url), ("deliberi_url", &self.deliberi_url), ("plc_url", &self.plc_url), ] { let url = reqwest::Url::parse(value).with_context(|| format!("invalid {name}"))?; ensure!( matches!(url.scheme(), "http" | "https") && url.host_str().is_some() && url.username().is_empty() && url.password().is_none() && url.query().is_none() && url.fragment().is_none(), "{name} must be an HTTP(S) base URL without credentials, query, or fragment" ); } self.signing_key()?; ensure!( matches!(self.log.format.as_str(), "text" | "json"), "log.format must be text or json" ); tracing_subscriber::EnvFilter::try_new(format!("info,{}", self.log.filter)) .context("invalid log.filter")?; Ok(()) }
pub(crate) fn signing_key(&self) -> anyhow::Result<SigningKey> { let bytes = STANDARD .decode(&self.signing_key) .context("signing_key must be base64")?; SigningKey::from_slice(&bytes) .context("signing_key must be a 32-byte secp256k1 private key") }}