mangadex-home-rs/src/state.rs

136 lines
4.4 KiB
Rust
Raw Normal View History

2021-03-25 19:58:07 -07:00
use std::io::BufReader;
use std::sync::{atomic::Ordering, Arc};
2021-03-22 14:47:56 -07:00
2021-03-25 19:58:07 -07:00
use crate::config::{SEND_SERVER_VERSION, VALIDATE_TOKENS};
2021-03-22 14:47:56 -07:00
use crate::ping::{Request, Response, Tls, CONTROL_CENTER_PING_URL};
2021-03-25 18:06:54 -07:00
use crate::{cache::Cache, config::CliArgs};
2021-03-22 20:19:56 -07:00
use log::{error, info, warn};
2021-03-22 14:47:56 -07:00
use parking_lot::RwLock;
use rustls::internal::pemfile::{certs, rsa_private_keys};
use rustls::sign::{CertifiedKey, RSASigningKey};
use rustls::ResolvesServerCert;
use sodiumoxide::crypto::box_::PrecomputedKey;
use url::Url;
pub struct ServerState {
pub precomputed_key: PrecomputedKey,
pub image_server: Url,
pub tls_config: Tls,
pub url: String,
pub cache: Cache,
2021-03-22 20:19:56 -07:00
pub log_state: LogState,
}
pub struct LogState {
pub was_paused_before: bool,
2021-03-22 14:47:56 -07:00
}
impl ServerState {
2021-03-25 18:06:54 -07:00
pub async fn init(secret: &str, config: &CliArgs) -> Result<Self, ()> {
2021-03-22 14:47:56 -07:00
let resp = reqwest::Client::new()
.post(CONTROL_CENTER_PING_URL)
2021-03-25 18:06:54 -07:00
.json(&Request::from((secret, config)))
2021-03-22 14:47:56 -07:00
.send()
.await;
2021-03-25 19:58:07 -07:00
if config.enable_server_string {
warn!("Client will send Server header in responses. This is not recommended!");
SEND_SERVER_VERSION.store(true, Ordering::Release);
}
2021-03-25 18:06:54 -07:00
2021-03-22 14:47:56 -07:00
match resp {
Ok(resp) => match resp.json::<Response>().await {
Ok(resp) => {
let key = resp
.token_key
.and_then(|key| {
if let Some(key) = base64::decode(&key)
.ok()
.and_then(|k| PrecomputedKey::from_slice(&k))
{
Some(key)
} else {
error!("Failed to parse token key: got {}", key);
None
}
})
.unwrap();
if resp.compromised {
2021-03-22 20:19:56 -07:00
error!("Got compromised response from control center!");
2021-03-22 14:47:56 -07:00
}
if resp.paused {
2021-03-22 20:19:56 -07:00
warn!("Control center has paused this node!");
2021-03-22 14:47:56 -07:00
}
info!("This client's URL has been set to {}", resp.url);
if resp.force_tokens {
2021-03-22 20:19:56 -07:00
info!("This client will validate tokens.");
} else {
info!("This client will not validate tokens.");
2021-03-22 14:47:56 -07:00
}
2021-03-25 19:58:07 -07:00
VALIDATE_TOKENS.store(resp.force_tokens, Ordering::Release);
2021-03-22 14:47:56 -07:00
Ok(Self {
precomputed_key: key,
image_server: resp.image_server,
tls_config: resp.tls.unwrap(),
url: resp.url,
cache: Cache::new(
2021-03-25 18:06:54 -07:00
config.memory_quota.get(),
2021-03-22 14:47:56 -07:00
config.disk_quota,
2021-03-25 18:06:54 -07:00
config.cache_path.clone(),
2021-03-22 14:47:56 -07:00
),
2021-03-22 20:19:56 -07:00
log_state: LogState {
was_paused_before: resp.paused,
},
2021-03-22 14:47:56 -07:00
})
}
Err(e) => {
warn!("Got malformed response: {}", e);
Err(())
}
},
Err(e) => match e {
e if e.is_timeout() => {
error!("Response timed out to control server. Is MangaDex down?");
Err(())
}
e => {
warn!("Failed to send request: {}", e);
Err(())
}
},
}
}
}
pub struct RwLockServerState(pub RwLock<ServerState>);
impl ResolvesServerCert for RwLockServerState {
fn resolve(&self, _: rustls::ClientHello) -> Option<CertifiedKey> {
let read_guard = self.0.read();
let priv_key = rsa_private_keys(&mut BufReader::new(
read_guard.tls_config.private_key.as_bytes(),
))
.ok()?
.pop()
.unwrap();
let certs = certs(&mut BufReader::new(
read_guard.tls_config.certificate.as_bytes(),
))
.ok()?;
Some(CertifiedKey {
cert: certs,
key: Arc::new(Box::new(RSASigningKey::new(&priv_key).unwrap())),
ocsp: None,
sct_list: None,
})
}
}