use arc_swap for tls

This commit is contained in:
Edward Shen 2021-04-24 00:56:58 -04:00
parent 70015a7c38
commit 9abeec89bc
Signed by: edward
GPG key ID: 19182661E818369F
5 changed files with 40 additions and 14 deletions

7
Cargo.lock generated
View file

@ -234,6 +234,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "arc-swap"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d7d63395147b81a9e570bcc6243aaf71c017bd666d4909cfef0085bdda8d73"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.5.2" version = "0.5.2"
@ -1019,6 +1025,7 @@ name = "mangadex-home"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"actix-web", "actix-web",
"arc-swap",
"async-trait", "async-trait",
"base64", "base64",
"bincode", "bincode",

View file

@ -15,6 +15,7 @@ debug = 1
[dependencies] [dependencies]
actix-web = { version = "4.0.0-beta.4", features = [ "rustls" ] } actix-web = { version = "4.0.0-beta.4", features = [ "rustls" ] }
arc-swap = "1"
async-trait = "0.1" async-trait = "0.1"
base64 = "0.13" base64 = "0.13"
bincode = "1" bincode = "1"

View file

@ -25,6 +25,7 @@ use stop::send_stop;
use thiserror::Error; use thiserror::Error;
use crate::cache::MemoryLruCache; use crate::cache::MemoryLruCache;
use crate::state::DynamicServerCert;
mod cache; mod cache;
mod config; mod config;
@ -88,7 +89,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// What's nice is that Rustls only supports TLS 1.2 and 1.3. // What's nice is that Rustls only supports TLS 1.2 and 1.3.
let mut tls_config = ServerConfig::new(NoClientAuth::new()); let mut tls_config = ServerConfig::new(NoClientAuth::new());
tls_config.cert_resolver = data_0.clone(); tls_config.cert_resolver = Arc::new(DynamicServerCert);
// //
// At this point, the server is ready to start, and starts the necessary // At this point, the server is ready to start, and starts the necessary

View file

@ -11,9 +11,9 @@ use serde::{Deserialize, Serialize};
use sodiumoxide::crypto::box_::PrecomputedKey; use sodiumoxide::crypto::box_::PrecomputedKey;
use url::Url; use url::Url;
use crate::config::CliArgs; use crate::state::{PREVIOUSLY_PAUSED, TLS_CERTS, TLS_SIGNING_KEY};
use crate::state::PREVIOUSLY_PAUSED;
use crate::{client_api_version, state::PREVIOUSLY_COMPROMISED}; use crate::{client_api_version, state::PREVIOUSLY_COMPROMISED};
use crate::{config::CliArgs, state::TLS_PREVIOUSLY_CREATED};
use crate::{config::VALIDATE_TOKENS, state::RwLockServerState}; use crate::{config::VALIDATE_TOKENS, state::RwLockServerState};
pub const CONTROL_CENTER_PING_URL: &str = "https://api.mangadex.network/ping"; pub const CONTROL_CENTER_PING_URL: &str = "https://api.mangadex.network/ping";
@ -42,7 +42,9 @@ impl<'a> Request<'a> {
build_version: client_api_version!() build_version: client_api_version!()
.parse() .parse()
.expect("to parse the build version"), .expect("to parse the build version"),
tls_created_at: Some(state.0.read().tls_config.created_at.clone()), tls_created_at: TLS_PREVIOUSLY_CREATED
.get()
.map(|v| v.load().as_ref().to_owned()),
} }
} }
} }
@ -182,7 +184,12 @@ pub async fn update_server_state(secret: &str, cli: &CliArgs, data: &mut Arc<RwL
} }
if let Some(tls) = resp.tls { if let Some(tls) = resp.tls {
write_guard.tls_config = tls; TLS_PREVIOUSLY_CREATED
.get()
.unwrap()
.swap(Arc::new(tls.created_at));
TLS_SIGNING_KEY.get().unwrap().swap(tls.priv_key);
TLS_CERTS.get().unwrap().swap(Arc::new(tls.certs));
} }
let previously_compromised = PREVIOUSLY_COMPROMISED.load(Ordering::Acquire); let previously_compromised = PREVIOUSLY_COMPROMISED.load(Ordering::Acquire);

View file

@ -1,11 +1,13 @@
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use crate::config::{CliArgs, SEND_SERVER_VERSION, VALIDATE_TOKENS}; use crate::config::{CliArgs, SEND_SERVER_VERSION, VALIDATE_TOKENS};
use crate::ping::{Request, Response, Tls, CONTROL_CENTER_PING_URL}; use crate::ping::{Request, Response, CONTROL_CENTER_PING_URL};
use arc_swap::ArcSwap;
use log::{error, info, warn}; use log::{error, info, warn};
use once_cell::sync::OnceCell;
use parking_lot::RwLock; use parking_lot::RwLock;
use rustls::sign::CertifiedKey; use rustls::sign::{CertifiedKey, SigningKey};
use rustls::Certificate;
use rustls::{ClientHello, ResolvesServerCert}; use rustls::{ClientHello, ResolvesServerCert};
use sodiumoxide::crypto::box_::PrecomputedKey; use sodiumoxide::crypto::box_::PrecomputedKey;
use thiserror::Error; use thiserror::Error;
@ -14,7 +16,6 @@ use url::Url;
pub struct ServerState { pub struct ServerState {
pub precomputed_key: PrecomputedKey, pub precomputed_key: PrecomputedKey,
pub image_server: Url, pub image_server: Url,
pub tls_config: Tls,
pub url: Url, pub url: Url,
pub url_overridden: bool, pub url_overridden: bool,
} }
@ -22,6 +23,10 @@ pub struct ServerState {
pub static PREVIOUSLY_PAUSED: AtomicBool = AtomicBool::new(false); pub static PREVIOUSLY_PAUSED: AtomicBool = AtomicBool::new(false);
pub static PREVIOUSLY_COMPROMISED: AtomicBool = AtomicBool::new(false); pub static PREVIOUSLY_COMPROMISED: AtomicBool = AtomicBool::new(false);
pub static TLS_PREVIOUSLY_CREATED: OnceCell<ArcSwap<String>> = OnceCell::new();
pub static TLS_SIGNING_KEY: OnceCell<ArcSwap<Box<dyn SigningKey>>> = OnceCell::new();
pub static TLS_CERTS: OnceCell<ArcSwap<Vec<Certificate>>> = OnceCell::new();
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ServerInitError { pub enum ServerInitError {
#[error(transparent)] #[error(transparent)]
@ -96,10 +101,14 @@ impl ServerState {
VALIDATE_TOKENS.store(resp.force_tokens, Ordering::Release); VALIDATE_TOKENS.store(resp.force_tokens, Ordering::Release);
} }
let tls = resp.tls.unwrap();
TLS_PREVIOUSLY_CREATED.set(ArcSwap::from_pointee(tls.created_at));
TLS_SIGNING_KEY.set(ArcSwap::new(tls.priv_key));
TLS_CERTS.set(ArcSwap::from_pointee(tls.certs));
Ok(Self { Ok(Self {
precomputed_key: key, precomputed_key: key,
image_server: resp.image_server, image_server: resp.image_server,
tls_config: resp.tls.unwrap(),
url: resp.url, url: resp.url,
url_overridden: config.override_upstream.is_some(), url_overridden: config.override_upstream.is_some(),
}) })
@ -125,14 +134,15 @@ impl ServerState {
pub struct RwLockServerState(pub RwLock<ServerState>); pub struct RwLockServerState(pub RwLock<ServerState>);
impl ResolvesServerCert for RwLockServerState { pub struct DynamicServerCert;
impl ResolvesServerCert for DynamicServerCert {
fn resolve(&self, _: ClientHello) -> Option<CertifiedKey> { fn resolve(&self, _: ClientHello) -> Option<CertifiedKey> {
// TODO: wait for actix-web to use a new version of rustls so we can // TODO: wait for actix-web to use a new version of rustls so we can
// remove cloning the certs all the time // remove cloning the certs all the time
let read_guard = self.0.read();
Some(CertifiedKey { Some(CertifiedKey {
cert: read_guard.tls_config.certs.clone(), cert: TLS_CERTS.get().unwrap().load().as_ref().clone(),
key: Arc::clone(&read_guard.tls_config.priv_key), key: TLS_SIGNING_KEY.get().unwrap().load_full(),
ocsp: None, ocsp: None,
sct_list: None, sct_list: None,
}) })