mangadex-home-rs/src/ping.rs

266 lines
8.9 KiB
Rust
Raw Normal View History

2021-07-15 04:54:31 +00:00
use std::net::{IpAddr, SocketAddr};
2021-04-19 04:16:13 +00:00
use std::sync::atomic::Ordering;
2021-03-26 04:07:32 +00:00
use std::{io::BufReader, sync::Arc};
2021-04-19 04:16:13 +00:00
2021-12-02 06:08:40 +00:00
use rustls::sign::{CertifiedKey, RsaSigningKey, SigningKey};
use rustls::{Certificate, PrivateKey};
use rustls_pemfile::{certs, rsa_private_keys};
2021-04-19 04:16:13 +00:00
use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Serialize};
use serde_repr::Deserialize_repr;
2021-03-18 01:45:16 +00:00
use sodiumoxide::crypto::box_::PrecomputedKey;
2021-07-13 03:23:51 +00:00
use tracing::{debug, error, info, warn};
2021-03-18 01:45:16 +00:00
use url::Url;
2021-07-15 16:29:55 +00:00
use crate::client::HTTP_CLIENT;
2021-07-18 22:35:22 +00:00
use crate::config::{ClientSecret, Config};
2021-04-24 16:47:33 +00:00
use crate::state::{
2021-12-02 06:08:40 +00:00
RwLockServerState, CERTIFIED_KEY, PREVIOUSLY_COMPROMISED, PREVIOUSLY_PAUSED,
TLS_PREVIOUSLY_CREATED,
2021-04-24 16:47:33 +00:00
};
2021-07-15 07:01:15 +00:00
use crate::units::{Bytes, BytesPerSecond, Port};
2021-07-09 21:18:43 +00:00
use crate::CLIENT_API_VERSION;
2021-03-18 01:45:16 +00:00
2021-03-22 21:47:56 +00:00
pub const CONTROL_CENTER_PING_URL: &str = "https://api.mangadex.network/ping";
#[derive(Serialize, Debug)]
2021-03-18 02:41:48 +00:00
pub struct Request<'a> {
2021-07-09 23:48:25 +00:00
secret: &'a ClientSecret,
2021-06-16 19:31:03 +00:00
port: Port,
2021-07-15 07:01:15 +00:00
disk_space: Bytes,
2021-07-09 21:18:43 +00:00
network_speed: BytesPerSecond,
build_version: usize,
2021-03-18 01:45:16 +00:00
tls_created_at: Option<String>,
2021-07-15 04:54:31 +00:00
ip_address: Option<IpAddr>,
2021-03-18 01:45:16 +00:00
}
2021-03-18 02:41:48 +00:00
impl<'a> Request<'a> {
2021-07-09 23:48:25 +00:00
fn from_config_and_state(secret: &'a ClientSecret, config: &Config) -> Self {
2021-03-18 01:45:16 +00:00
Self {
2021-03-26 01:06:54 +00:00
secret,
2021-07-15 04:54:31 +00:00
port: config
.external_address
.and_then(|v| Port::new(v.port()))
.unwrap_or(config.port),
2021-07-15 07:01:15 +00:00
disk_space: config.disk_quota.into(),
2021-07-09 21:18:43 +00:00
network_speed: config.network_speed.into(),
build_version: CLIENT_API_VERSION,
2021-04-24 04:56:58 +00:00
tls_created_at: TLS_PREVIOUSLY_CREATED
.get()
2021-05-12 01:01:01 +00:00
.map(|v| v.load().as_ref().clone()),
2021-07-15 04:54:31 +00:00
ip_address: config.external_address.as_ref().map(SocketAddr::ip),
2021-03-18 01:45:16 +00:00
}
}
}
2021-07-09 23:48:25 +00:00
impl<'a> From<(&'a ClientSecret, &Config)> for Request<'a> {
fn from((secret, config): (&'a ClientSecret, &Config)) -> Self {
2021-03-18 01:45:16 +00:00
Self {
2021-03-26 01:06:54 +00:00
secret,
2021-07-15 04:54:31 +00:00
port: config
.external_address
.and_then(|v| Port::new(v.port()))
.unwrap_or(config.port),
2021-07-15 07:01:15 +00:00
disk_space: config.disk_quota.into(),
2021-07-09 21:18:43 +00:00
network_speed: config.network_speed.into(),
build_version: CLIENT_API_VERSION,
2021-03-18 01:45:16 +00:00
tls_created_at: None,
2021-07-15 04:54:31 +00:00
ip_address: config.external_address.as_ref().map(SocketAddr::ip),
2021-03-18 01:45:16 +00:00
}
}
}
2021-03-22 21:47:56 +00:00
#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub enum Response {
2022-01-02 21:25:00 +00:00
Ok(Box<OkResponse>),
Error(ErrorResponse),
}
#[derive(Deserialize, Debug)]
pub struct OkResponse {
2021-03-18 02:41:48 +00:00
pub image_server: Url,
pub latest_build: usize,
2021-04-19 03:06:18 +00:00
pub url: Url,
2021-03-18 02:41:48 +00:00
pub token_key: Option<String>,
pub compromised: bool,
pub paused: bool,
pub tls: Option<Tls>,
2021-03-18 01:45:16 +00:00
}
#[derive(Deserialize, Debug)]
pub struct ErrorResponse {
pub error: String,
pub status: ErrorCode,
}
#[derive(Deserialize_repr, Debug, Copy, Clone)]
#[repr(u16)]
pub enum ErrorCode {
MalformedJson = 400,
InvalidSecret = 401,
InvalidContentType = 415,
}
2021-03-18 02:41:48 +00:00
pub struct Tls {
2021-03-18 01:45:16 +00:00
pub created_at: String,
2021-12-02 06:08:40 +00:00
pub priv_key: Arc<RsaSigningKey>,
2021-03-26 04:07:32 +00:00
pub certs: Vec<Certificate>,
}
impl<'de> Deserialize<'de> for Tls {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct TlsVisitor;
impl<'de> Visitor<'de> for TlsVisitor {
type Value = Tls;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a tls struct")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut created_at = None;
let mut priv_key = None;
let mut certificates = None;
while let Some((key, value)) = map.next_entry::<&str, String>()? {
match key {
"created_at" => created_at = Some(value.to_string()),
"private_key" => {
priv_key = rsa_private_keys(&mut BufReader::new(value.as_bytes()))
.ok()
.and_then(|mut v| {
2021-12-02 06:08:40 +00:00
v.pop()
.and_then(|key| RsaSigningKey::new(&PrivateKey(key)).ok())
2021-07-11 17:19:37 +00:00
});
2021-03-26 04:07:32 +00:00
}
"certificate" => {
2021-07-11 17:19:37 +00:00
certificates = certs(&mut BufReader::new(value.as_bytes())).ok();
2021-03-26 04:07:32 +00:00
}
_ => (), // Ignore extra fields
}
}
match (created_at, priv_key, certificates) {
(Some(created_at), Some(priv_key), Some(certificates)) => Ok(Tls {
created_at,
2021-12-02 06:08:40 +00:00
priv_key: Arc::new(priv_key),
certs: certificates.into_iter().map(Certificate).collect(),
2021-03-26 04:07:32 +00:00
}),
_ => Err(serde::de::Error::custom("Could not deserialize tls info")),
}
}
}
deserializer.deserialize_map(TlsVisitor)
}
}
2021-07-20 20:47:04 +00:00
#[cfg(not(tarpaulin_include))]
2021-03-26 04:07:32 +00:00
impl std::fmt::Debug for Tls {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Tls")
.field("created_at", &self.created_at)
.finish()
}
2021-03-18 01:45:16 +00:00
}
2021-07-09 23:48:25 +00:00
pub async fn update_server_state(
secret: &ClientSecret,
cli: &Config,
data: &mut Arc<RwLockServerState>,
) {
2021-04-24 16:46:18 +00:00
let req = Request::from_config_and_state(secret, cli);
debug!("Sending ping request: {:?}", req);
2021-07-15 16:29:55 +00:00
let resp = HTTP_CLIENT
.inner()
.post(CONTROL_CENTER_PING_URL)
.json(&req)
.send()
.await;
2021-03-18 01:45:16 +00:00
match resp {
2021-03-22 21:47:56 +00:00
Ok(resp) => match resp.json::<Response>().await {
Ok(Response::Ok(resp)) => {
2021-04-19 04:16:13 +00:00
debug!("got write guard for server state");
2021-03-18 01:45:16 +00:00
let mut write_guard = data.0.write();
2021-05-27 20:22:15 +00:00
let image_server_changed = write_guard.image_server != resp.image_server;
if !write_guard.url_overridden && image_server_changed {
2021-04-19 03:06:18 +00:00
write_guard.image_server = resp.image_server;
2021-05-27 20:22:15 +00:00
} else if image_server_changed {
2021-05-11 20:56:28 +00:00
warn!("Ignoring new upstream url!");
2021-04-19 03:06:18 +00:00
}
2021-03-18 01:45:16 +00:00
if let Some(key) = resp.token_key {
2022-03-26 23:28:58 +00:00
base64::decode(&key)
2021-03-22 21:47:56 +00:00
.ok()
.and_then(|k| PrecomputedKey::from_slice(&k))
2022-03-26 23:28:58 +00:00
.map_or_else(
|| error!("Failed to parse token key: got {}", key),
|key| write_guard.precomputed_key = key,
);
2021-03-18 01:45:16 +00:00
}
if let Some(tls) = resp.tls {
2021-04-24 04:56:58 +00:00
TLS_PREVIOUSLY_CREATED
.get()
.unwrap()
.swap(Arc::new(tls.created_at));
2021-12-02 06:08:40 +00:00
CERTIFIED_KEY.store(Some(Arc::new(CertifiedKey {
cert: tls.certs.clone(),
key: Arc::clone(&tls.priv_key) as Arc<dyn SigningKey>,
ocsp: None,
sct_list: None,
})));
2021-03-18 01:45:16 +00:00
}
let previously_compromised = PREVIOUSLY_COMPROMISED.load(Ordering::Acquire);
if resp.compromised != previously_compromised {
PREVIOUSLY_COMPROMISED.store(resp.compromised, Ordering::Release);
if resp.compromised {
error!("Got compromised response from control center!");
2021-05-27 20:22:15 +00:00
} else if previously_compromised {
info!("No longer compromised!");
}
2021-03-18 01:45:16 +00:00
}
let previously_paused = PREVIOUSLY_PAUSED.load(Ordering::Acquire);
if resp.paused != previously_paused {
PREVIOUSLY_PAUSED.store(resp.paused, Ordering::Release);
2021-03-23 03:19:56 +00:00
if resp.paused {
warn!("Control center has paused this node.");
} else {
info!("Control center is no longer pausing this node.");
}
2021-03-18 01:45:16 +00:00
}
if resp.url != write_guard.url {
info!("This client's URL has been updated to {}", resp.url);
}
2021-04-19 04:16:13 +00:00
debug!("dropping write guard for server state");
2021-03-18 01:45:16 +00:00
}
Ok(Response::Error(resp)) => {
error!(
"Got an {} error from upstream: {}",
resp.status as u16, resp.error
);
}
2021-03-18 01:45:16 +00:00
Err(e) => warn!("Got malformed response: {}", e),
},
Err(e) => match e {
2021-03-22 21:47:56 +00:00
e if e.is_timeout() => {
2021-07-11 17:19:37 +00:00
error!("Response timed out to control server. Is MangaDex down?");
2021-03-18 01:45:16 +00:00
}
e => warn!("Failed to send request: {}", e),
},
}
}