bumped rustls & related pkgs (#1066)

This commit is contained in:
Eugene 2024-09-18 11:28:39 +02:00 committed by GitHub
parent 9ca95b7eb7
commit c191e54c07
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1002 additions and 565 deletions

1039
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,18 +7,18 @@ version = "0.10.2"
[dependencies] [dependencies]
anyhow = { version = "1.0", features = ["std"] } anyhow = { version = "1.0", features = ["std"] }
async-trait = "0.1" async-trait = "0.1"
bytes = "1.3" bytes = "1.4"
chrono = { version = "0.4", default-features = false } chrono = { version = "0.4", default-features = false }
futures = "0.3" futures = "0.3"
hex = "0.4" hex = "0.4"
mime_guess = { version = "2.0", default-features = false } mime_guess = { version = "2.0", default-features = false }
poem = { version = "1.3.50", features = [ poem = { version = "3.1", features = [
"cookie", "cookie",
"session", "session",
"anyhow", "anyhow",
"websocket", "websocket",
] } ] }
poem-openapi = { version = "2.0", features = [ poem-openapi = { version = "5.1", features = [
"swagger-ui", "swagger-ui",
"chrono", "chrono",
"uuid", "uuid",
@ -26,7 +26,7 @@ poem-openapi = { version = "2.0", features = [
] } ] }
russh = { version = "0.44.1", features = ["legacy-ed25519-pkcs8-parser"] } russh = { version = "0.44.1", features = ["legacy-ed25519-pkcs8-parser"] }
rust-embed = "8.3" rust-embed = "8.3"
sea-orm = { version = "0.12.2", features = [ sea-orm = { version = "0.12", features = [
"runtime-tokio-rustls", "runtime-tokio-rustls",
"macros", "macros",
], default-features = false } ], default-features = false }
@ -35,7 +35,7 @@ serde_json = "1.0"
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1.20", features = ["tracing"] } tokio = { version = "1.20", features = ["tracing"] }
tracing = "0.1" tracing = "0.1"
uuid = { version = "1.2", features = ["v4", "serde"] } uuid = { version = "1.3", features = ["v4", "serde"] }
warpgate-common = { version = "*", path = "../warpgate-common" } warpgate-common = { version = "*", path = "../warpgate-common" }
warpgate-core = { version = "*", path = "../warpgate-core" } warpgate-core = { version = "*", path = "../warpgate-core" }
warpgate-db-entities = { version = "*", path = "../warpgate-db-entities" } warpgate-db-entities = { version = "*", path = "../warpgate-db-entities" }

View file

@ -8,7 +8,7 @@ version = "0.10.2"
anyhow = "1.0" anyhow = "1.0"
argon2 = "0.4" argon2 = "0.4"
async-trait = "0.1" async-trait = "0.1"
bytes = "1.3" bytes = "1.4"
chrono = { version = "0.4", default-features = false, features = ["serde"] } chrono = { version = "0.4", default-features = false, features = ["serde"] }
data-encoding = "2.3" data-encoding = "2.3"
delegate = "0.6" delegate = "0.6"
@ -16,8 +16,8 @@ humantime-serde = "1.1"
futures = "0.3" futures = "0.3"
once_cell = "1.17" once_cell = "1.17"
password-hash = "0.4" password-hash = "0.4"
poem = { version = "1.3.50", features = ["rustls"] } poem = { version = "3.1", features = ["rustls"] }
poem-openapi = { version = "2.0", features = [ poem-openapi = { version = "5.1", features = [
"swagger-ui", "swagger-ui",
"chrono", "chrono",
"uuid", "uuid",
@ -38,8 +38,8 @@ totp-rs = { version = "5.0", features = ["otpauth"] }
tracing = "0.1" tracing = "0.1"
tracing-core = "0.1" tracing-core = "0.1"
url = "2.2" url = "2.2"
uuid = { version = "1.2", features = ["v4", "serde"] } uuid = { version = "1.3", features = ["v4", "serde"] }
warpgate-sso = { version = "*", path = "../warpgate-sso" } warpgate-sso = { version = "*", path = "../warpgate-sso" }
rustls = { version = "0.20", features = ["dangerous_configuration"] } rustls = { version = "0.23", features = ["ring"], default-features = false}
rustls-pemfile = "1.0" rustls-pemfile = "1.0"
webpki = "0.22" webpki = "0.22"

View file

@ -2,8 +2,8 @@ use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use poem::listener::RustlsCertificate; use poem::listener::RustlsCertificate;
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use rustls::sign::{CertifiedKey, SigningKey}; use rustls::sign::{CertifiedKey, SigningKey};
use rustls::{Certificate, PrivateKey};
use tokio::fs::File; use tokio::fs::File;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
@ -11,7 +11,7 @@ use crate::RustlsSetupError;
pub struct TlsCertificateBundle { pub struct TlsCertificateBundle {
bytes: Vec<u8>, bytes: Vec<u8>,
certificates: Vec<Certificate>, certificates: Vec<CertificateDer<'static>>,
} }
pub struct TlsPrivateKey { pub struct TlsPrivateKey {
@ -36,8 +36,8 @@ impl TlsCertificateBundle {
let certificates = rustls_pemfile::certs(&mut &bytes[..]).map(|mut certs| { let certificates = rustls_pemfile::certs(&mut &bytes[..]).map(|mut certs| {
certs certs
.drain(..) .drain(..)
.map(Certificate) .map(CertificateDer::from)
.collect::<Vec<Certificate>>() .collect::<Vec<CertificateDer>>()
})?; })?;
if certificates.is_empty() { if certificates.is_empty() {
return Err(RustlsSetupError::NoCertificates); return Err(RustlsSetupError::NoCertificates);
@ -61,17 +61,17 @@ impl TlsPrivateKey {
let mut key = rustls_pemfile::pkcs8_private_keys(&mut bytes.as_slice())? let mut key = rustls_pemfile::pkcs8_private_keys(&mut bytes.as_slice())?
.drain(..) .drain(..)
.next() .next()
.map(PrivateKey); .and_then(|x| PrivateKeyDer::try_from(x).ok());
if key.is_none() { if key.is_none() {
key = rustls_pemfile::rsa_private_keys(&mut bytes.as_slice())? key = rustls_pemfile::rsa_private_keys(&mut bytes.as_slice())?
.drain(..) .drain(..)
.next() .next()
.map(PrivateKey); .and_then(|x| PrivateKeyDer::try_from(x).ok());
} }
let key = key.ok_or(RustlsSetupError::NoKeys)?; let key = key.ok_or(RustlsSetupError::NoKeys)?;
let key = rustls::sign::any_supported_type(&key)?; let key = rustls::crypto::ring::sign::any_supported_type(&key)?;
Ok(Self { bytes, key }) Ok(Self { bytes, key })
} }
@ -105,7 +105,6 @@ impl From<TlsCertificateAndPrivateKey> for CertifiedKey {
cert: cert.certificates, cert: cert.certificates,
key: key.key, key: key.key,
ocsp: None, ocsp: None,
sct_list: None,
} }
} }
} }

View file

@ -1,9 +1,11 @@
use rustls::server::VerifierBuilderError;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum RustlsSetupError { pub enum RustlsSetupError {
#[error("rustls: {0}")] #[error("rustls: {0}")]
Rustls(#[from] rustls::Error), Rustls(#[from] rustls::Error),
#[error("sign: {0}")] #[error("verifier setup: {0}")]
Sign(#[from] rustls::sign::SignError), VerifierBuilder(#[from] VerifierBuilderError),
#[error("no certificates found in certificate file")] #[error("no certificates found in certificate file")]
NoCertificates, NoCertificates,
#[error("no private keys found in key file")] #[error("no private keys found in key file")]
@ -11,5 +13,5 @@ pub enum RustlsSetupError {
#[error("I/O: {0}")] #[error("I/O: {0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[error("PKI: {0}")] #[error("PKI: {0}")]
Pki(#[from] webpki::Error), Pki(webpki::Error),
} }

View file

@ -20,8 +20,8 @@ futures = "0.3"
once_cell = "1.17" once_cell = "1.17"
packet = "0.1" packet = "0.1"
password-hash = "0.4" password-hash = "0.4"
poem = { version = "1.3.50", features = ["rustls"] } poem = { version = "3.1", features = ["rustls"] }
poem-openapi = { version = "2.0", features = [ poem-openapi = { version = "5.1", features = [
"swagger-ui", "swagger-ui",
"chrono", "chrono",
"uuid", "uuid",
@ -30,7 +30,7 @@ poem-openapi = { version = "2.0", features = [
rand = "0.8" rand = "0.8"
rand_chacha = "0.3" rand_chacha = "0.3"
rand_core = { version = "0.6", features = ["std"] } rand_core = { version = "0.6", features = ["std"] }
sea-orm = { version = "0.12.2", features = [ sea-orm = { version = "0.12", features = [
"runtime-tokio-rustls", "runtime-tokio-rustls",
"macros", "macros",
], default-features = false } ], default-features = false }
@ -43,9 +43,9 @@ tracing = "0.1"
tracing-core = "0.1" tracing-core = "0.1"
tracing-subscriber = "0.3" tracing-subscriber = "0.3"
url = "2.2" url = "2.2"
uuid = { version = "1.2", features = ["v4", "serde"] } uuid = { version = "1.3", features = ["v4", "serde"] }
warpgate-sso = { version = "*", path = "../warpgate-sso" } warpgate-sso = { version = "*", path = "../warpgate-sso" }
rustls = { version = "0.20", features = ["dangerous_configuration"] } rustls = { version = "0.23", features = ["logging"], default-features = false }
rustls-pemfile = "1.0" rustls-pemfile = "1.0"
webpki = "0.22" webpki = "0.22"

View file

@ -14,11 +14,11 @@ authors = [
[dependencies] [dependencies]
tokio = { version = "1.20", features = ["io-util"] } tokio = { version = "1.20", features = ["io-util"] }
bitflags = { version = "1.3", default-features = false } bitflags = { version = "1.3", default-features = false }
bytes = "1.3" bytes = "1.4"
futures-core = { version = "0.3", default-features = false } futures-core = { version = "0.3", default-features = false }
futures-util = { version = "0.3", default-features = false, features = [ futures-util = { version = "0.3", default-features = false, features = [
"alloc", "alloc",
"sink", "sink",
] } ] }
memchr = { version = "2.5.0", default-features = false } memchr = { version = "2.5", default-features = false }
thiserror = "1.0" thiserror = "1.0"

View file

@ -6,8 +6,8 @@ version = "0.10.2"
[dependencies] [dependencies]
chrono = { version = "0.4", default-features = false, features = ["serde"] } chrono = { version = "0.4", default-features = false, features = ["serde"] }
poem-openapi = { version = "2.0", features = ["chrono", "uuid"] } poem-openapi = { version = "5.1", features = ["chrono", "uuid"] }
sea-orm = { version = "0.12.2", features = [ sea-orm = { version = "0.12", features = [
"macros", "macros",
"with-chrono", "with-chrono",
"with-uuid", "with-uuid",
@ -15,5 +15,5 @@ sea-orm = { version = "0.12.2", features = [
], default-features = false } ], default-features = false }
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
uuid = { version = "1.2", features = ["v4", "serde"] } uuid = { version = "1.3", features = ["v4", "serde"] }
warpgate-common = { version = "*", path = "../warpgate-common" } warpgate-common = { version = "*", path = "../warpgate-common" }

View file

@ -10,15 +10,15 @@ version = "0.10.2"
[dependencies] [dependencies]
async-std = { version = "^1.11", features = ["attributes"] } async-std = { version = "^1.11", features = ["attributes"] }
chrono = { version = "0.4", default-features = false, features = ["serde"] } chrono = { version = "0.4", default-features = false, features = ["serde"] }
sea-orm = { version = "0.12.2", features = [ sea-orm = { version = "0.12", features = [
"runtime-tokio-rustls", "runtime-tokio-rustls",
"macros", "macros",
"with-chrono", "with-chrono",
"with-uuid", "with-uuid",
"with-json", "with-json",
], default-features = false } ], default-features = false }
sea-orm-migration = { version = "0.12.2", default-features = false, features = [ sea-orm-migration = { version = "0.12", default-features = false, features = [
"cli", "cli",
] } ] }
uuid = { version = "1.2", features = ["v4", "serde"] } uuid = { version = "1.3", features = ["v4", "serde"] }
serde_json = "1.0" serde_json = "1.0"

View file

@ -8,13 +8,13 @@ version = "0.10.2"
anyhow = "1.0" anyhow = "1.0"
async-trait = "0.1" async-trait = "0.1"
chrono = { version = "0.4", default-features = false, features = ["serde"] } chrono = { version = "0.4", default-features = false, features = ["serde"] }
cookie = "0.16" cookie = "0.17"
data-encoding = "2.3" data-encoding = "2.3"
delegate = "0.6" delegate = "0.6"
futures = "0.3" futures = "0.3"
http = "0.2" http = "1.0"
once_cell = "1.17" once_cell = "1.17"
poem = { version = "^1.3.50", features = [ poem = { version = "3.1", features = [
"cookie", "cookie",
"session", "session",
"anyhow", "anyhow",
@ -23,15 +23,15 @@ poem = { version = "^1.3.50", features = [
"sse", "sse",
"embed", "embed",
] } ] }
poem-openapi = { version = "2.0", features = ["swagger-ui"] } poem-openapi = { version = "5.1", features = ["swagger-ui"] }
reqwest = { version = "0.11", features = [ reqwest = { version = "0.12", features = [
"rustls-tls-native-roots", "rustls-tls-native-roots",
"stream", "stream",
], default-features = false } ], default-features = false }
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
tokio = { version = "1.20", features = ["tracing", "signal"] } tokio = { version = "1.20", features = ["tracing", "signal"] }
tokio-tungstenite = { version = "0.17", features = ["rustls-tls-native-roots"] } tokio-tungstenite = { version = "0.24", features = ["rustls-tls-native-roots"] }
tracing = "0.1" tracing = "0.1"
warpgate-admin = { version = "*", path = "../warpgate-admin" } warpgate-admin = { version = "*", path = "../warpgate-admin" }
warpgate-common = { version = "*", path = "../warpgate-common" } warpgate-common = { version = "*", path = "../warpgate-common" }
@ -40,6 +40,6 @@ warpgate-db-entities = { version = "*", path = "../warpgate-db-entities" }
warpgate-web = { version = "*", path = "../warpgate-web" } warpgate-web = { version = "*", path = "../warpgate-web" }
warpgate-sso = { version = "*", path = "../warpgate-sso" } warpgate-sso = { version = "*", path = "../warpgate-sso" }
percent-encoding = "2.1" percent-encoding = "2.1"
uuid = { version = "1.2", features = ["v4"] } uuid = { version = "1.3", features = ["v4"] }
regex = "1.6" regex = "1.6"
url = "2.4.1" url = "2.4"

View file

@ -61,9 +61,9 @@ async fn get_target_for_request(
req: &Request, req: &Request,
services: &Services, services: &Services,
) -> poem::Result<Option<(Target, TargetHTTPOptions)>> { ) -> poem::Result<Option<(Target, TargetHTTPOptions)>> {
let session: &Session = <_>::from_request_without_body(req).await?; let session = <&Session>::from_request_without_body(req).await?;
let params: QueryParams = req.params()?; let params: QueryParams = req.params()?;
let auth: Data<&SessionAuthorization> = <_>::from_request_without_body(req).await?; let auth = Data::<&SessionAuthorization>::from_request_without_body(req).await?;
let selected_target_name; let selected_target_name;
let need_role_auth; let need_role_auth;

View file

@ -110,7 +110,7 @@ impl SessionAuthorization {
} }
async fn is_user_admin(req: &Request, auth: &SessionAuthorization) -> poem::Result<bool> { async fn is_user_admin(req: &Request, auth: &SessionAuthorization) -> poem::Result<bool> {
let services: Data<&Services> = <_>::from_request_without_body(req).await?; let services = Data::<&Services>::from_request_without_body(req).await?;
let SessionAuthorization::User(username) = auth else { let SessionAuthorization::User(username) = auth else {
return Ok(false); return Ok(false);
@ -133,7 +133,7 @@ async fn is_user_admin(req: &Request, auth: &SessionAuthorization) -> poem::Resu
pub fn endpoint_admin_auth<E: Endpoint + 'static>(e: E) -> impl Endpoint { pub fn endpoint_admin_auth<E: Endpoint + 'static>(e: E) -> impl Endpoint {
e.around(|ep, req| async move { e.around(|ep, req| async move {
let auth: Data<&SessionAuthorization> = <_>::from_request_without_body(&req).await?; let auth = Data::<&SessionAuthorization>::from_request_without_body(&req).await?;
if is_user_admin(&req, &auth).await? { if is_user_admin(&req, &auth).await? {
return Ok(ep.call(req).await?.into_response()); return Ok(ep.call(req).await?.into_response());
} }
@ -143,8 +143,8 @@ pub fn endpoint_admin_auth<E: Endpoint + 'static>(e: E) -> impl Endpoint {
pub fn page_admin_auth<E: Endpoint + 'static>(e: E) -> impl Endpoint { pub fn page_admin_auth<E: Endpoint + 'static>(e: E) -> impl Endpoint {
e.around(|ep, req| async move { e.around(|ep, req| async move {
let auth: Data<&SessionAuthorization> = <_>::from_request_without_body(&req).await?; let auth = Data::<&SessionAuthorization>::from_request_without_body(&req).await?;
let session: &Session = <_>::from_request_without_body(&req).await?; let session = <&Session>::from_request_without_body(&req).await?;
if is_user_admin(&req, &auth).await? { if is_user_admin(&req, &auth).await? {
return Ok(ep.call(req).await?.into_response()); return Ok(ep.call(req).await?.into_response());
} }
@ -157,7 +157,7 @@ pub async fn _inner_auth<E: Endpoint + 'static>(
ep: Arc<E>, ep: Arc<E>,
req: Request, req: Request,
) -> poem::Result<Option<E::Output>> { ) -> poem::Result<Option<E::Output>> {
let session: &Session = FromRequest::from_request_without_body(&req).await?; let session = <&Session>::from_request_without_body(&req).await?;
Ok(match session.get_auth() { Ok(match session.get_auth() {
Some(auth) => Some(ep.data(auth).call(req).await?), Some(auth) => Some(ep.data(auth).call(req).await?),
@ -235,9 +235,9 @@ pub async fn get_auth_state_for_request(
} }
pub async fn authorize_session(req: &Request, username: String) -> poem::Result<()> { pub async fn authorize_session(req: &Request, username: String) -> poem::Result<()> {
let session_middleware: Data<&Arc<Mutex<SessionStore>>> = let session_middleware =
<_>::from_request_without_body(req).await?; Data::<&Arc<Mutex<SessionStore>>>::from_request_without_body(req).await?;
let session: &Session = <_>::from_request_without_body(req).await?; let session = <&Session>::from_request_without_body(req).await?;
let server_handle = session_middleware let server_handle = session_middleware
.lock() .lock()

View file

@ -17,7 +17,7 @@ use std::time::Duration;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use async_trait::async_trait; use async_trait::async_trait;
use common::page_admin_auth; use common::page_admin_auth;
pub use common::{PROTOCOL_NAME, SsoLoginState}; pub use common::{SsoLoginState, PROTOCOL_NAME};
use http::HeaderValue; use http::HeaderValue;
use logging::{get_client_ip, log_request_result, span_for_request}; use logging::{get_client_ip, log_request_result, span_for_request};
use poem::endpoint::{EmbeddedFileEndpoint, EmbeddedFilesEndpoint}; use poem::endpoint::{EmbeddedFileEndpoint, EmbeddedFilesEndpoint};

View file

@ -35,7 +35,7 @@ pub fn log_request_result(method: &Method, url: &Uri, client_ip: String, status:
} }
pub async fn get_client_ip(req: &Request) -> poem::Result<String> { pub async fn get_client_ip(req: &Request) -> poem::Result<String> {
let services: Option<Data<&Services>> = <_>::from_request_without_body(req).await.ok(); let services = Data::<&Services>::from_request_without_body(req).await.ok();
let trust_x_forwarded_headers = if let Some(services) = services { let trust_x_forwarded_headers = if let Some(services) = services {
let config = services.config.lock().await; let config = services.config.lock().await;
config.store.http.trust_x_forwarded_headers config.store.http.trust_x_forwarded_headers

View file

@ -1,4 +1,5 @@
use async_trait::async_trait; use std::future::Future;
use http::header::Entry; use http::header::Entry;
use poem::web::cookie::Cookie; use poem::web::cookie::Cookie;
use poem::{Endpoint, IntoResponse, Middleware, Request, Response}; use poem::{Endpoint, IntoResponse, Middleware, Request, Response};
@ -25,17 +26,19 @@ impl<E: Endpoint> Middleware<E> for CookieHostMiddleware {
} }
} }
#[async_trait]
impl<E: Endpoint> Endpoint for CookieHostMiddlewareEndpoint<E> { impl<E: Endpoint> Endpoint for CookieHostMiddlewareEndpoint<E> {
type Output = Response; type Output = Response;
async fn call(&self, req: Request) -> poem::Result<Self::Output> { fn call(&self, req: Request) -> impl Future<Output = poem::Result<Self::Output>> + Send {
async move {
let host = req.original_uri().host().map(|x| x.to_string()); let host = req.original_uri().host().map(|x| x.to_string());
let mut resp = self.inner.call(req).await?.into_response(); let mut resp = self.inner.call(req).await?.into_response();
if let Some(host) = host { if let Some(host) = host {
if let Entry::Occupied(mut entry) = resp.headers_mut().entry(http::header::SET_COOKIE) { if let Entry::Occupied(mut entry) =
resp.headers_mut().entry(http::header::SET_COOKIE)
{
if let Ok(cookie_str) = entry.get().to_str() { if let Ok(cookie_str) = entry.get().to_str() {
if let Ok(mut cookie) = Cookie::parse(cookie_str) { if let Ok(mut cookie) = Cookie::parse(cookie_str) {
if cookie.name() == SESSION_COOKIE_NAME { if cookie.name() == SESSION_COOKIE_NAME {
@ -50,4 +53,5 @@ impl<E: Endpoint> Endpoint for CookieHostMiddlewareEndpoint<E> {
} }
Ok(resp) Ok(resp)
} }
}
} }

View file

@ -1,4 +1,5 @@
use async_trait::async_trait; use std::future::Future;
use poem::session::Session; use poem::session::Session;
use poem::web::{Data, FromRequest}; use poem::web::{Data, FromRequest};
use poem::{Endpoint, Middleware, Request}; use poem::{Endpoint, Middleware, Request};
@ -34,13 +35,13 @@ struct QueryParams {
ticket: Option<String>, ticket: Option<String>,
} }
#[async_trait]
impl<E: Endpoint> Endpoint for TicketMiddlewareEndpoint<E> { impl<E: Endpoint> Endpoint for TicketMiddlewareEndpoint<E> {
type Output = E::Output; type Output = E::Output;
async fn call(&self, req: Request) -> poem::Result<Self::Output> { fn call(&self, req: Request) -> impl Future<Output = poem::Result<Self::Output>> {
async move {
let mut session_is_temporary = false; let mut session_is_temporary = false;
let session: &Session = <_>::from_request_without_body(&req).await?; let session = <&Session>::from_request_without_body(&req).await?;
let session = session.clone(); let session = session.clone();
{ {
@ -61,7 +62,7 @@ impl<E: Endpoint> Endpoint for TicketMiddlewareEndpoint<E> {
} }
if let Some(ticket) = ticket_value { if let Some(ticket) = ticket_value {
let services: Data<&Services> = <_>::from_request_without_body(&req).await?; let services = Data::<&Services>::from_request_without_body(&req).await?;
if let Some(ticket_model) = { if let Some(ticket_model) = {
let ticket = Secret::new(ticket); let ticket = Secret::new(ticket);
@ -88,4 +89,5 @@ impl<E: Endpoint> Endpoint for TicketMiddlewareEndpoint<E> {
resp resp
} }
}
} }

View file

@ -5,7 +5,7 @@ use std::str::FromStr;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use cookie::Cookie; use cookie::Cookie;
use delegate::delegate; use delegate::delegate;
use futures::{SinkExt, StreamExt}; use futures::{SinkExt, StreamExt, TryStreamExt};
use http::header::HeaderName; use http::header::HeaderName;
use http::uri::{Authority, Scheme}; use http::uri::{Authority, Scheme};
use http::Uri; use http::Uri;
@ -313,7 +313,11 @@ async fn copy_client_body(
return Ok(()); return Ok(());
} }
response.set_body(Body::from_bytes_stream(client_response.bytes_stream())); response.set_body(Body::from_bytes_stream(
client_response
.bytes_stream()
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)),
));
Ok(()) Ok(())
} }
@ -397,6 +401,7 @@ async fn proxy_ws_inner(
.body(()) .body(())
.map_err(poem::error::InternalServerError)?, .map_err(poem::error::InternalServerError)?,
None, None,
true,
) )
.await .await
.map_err(poem::error::BadGateway)?; .map_err(poem::error::BadGateway)?;

View file

@ -1,9 +1,9 @@
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::future::Future;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use async_trait::async_trait; use poem::session::{MemoryStorage, Session, SessionStorage};
use poem::session::{Session, SessionStorage};
use poem::web::{Data, RemoteAddr}; use poem::web::{Data, RemoteAddr};
use poem::{FromRequest, Request}; use poem::{FromRequest, Request};
use serde_json::Value; use serde_json::Value;
@ -18,16 +18,16 @@ use crate::session_handle::{
}; };
#[derive(Clone)] #[derive(Clone)]
pub struct SharedSessionStorage(pub Arc<Mutex<Box<dyn SessionStorage>>>); pub struct SharedSessionStorage(pub Arc<Mutex<Box<MemoryStorage>>>);
static POEM_SESSION_ID_SESSION_KEY: &str = "poem_session_id"; static POEM_SESSION_ID_SESSION_KEY: &str = "poem_session_id";
#[async_trait]
impl SessionStorage for SharedSessionStorage { impl SessionStorage for SharedSessionStorage {
async fn load_session( fn load_session<'a>(
&self, &'a self,
session_id: &str, session_id: &'a str,
) -> poem::Result<Option<BTreeMap<String, Value>>> { ) -> impl Future<Output = poem::Result<Option<BTreeMap<String, Value>>>> + Send + 'a {
async move {
self.0.lock().await.load_session(session_id).await.map(|o| { self.0.lock().await.load_session(session_id).await.map(|o| {
o.map(|mut s| { o.map(|mut s| {
s.insert( s.insert(
@ -38,22 +38,30 @@ impl SessionStorage for SharedSessionStorage {
}) })
}) })
} }
}
async fn update_session( /// Insert or update a session.
&self, fn update_session<'a>(
session_id: &str, &'a self,
entries: &BTreeMap<String, Value>, session_id: &'a str,
entries: &'a BTreeMap<String, Value>,
expires: Option<Duration>, expires: Option<Duration>,
) -> poem::Result<()> { ) -> impl Future<Output = poem::Result<()>> + Send + 'a {
async move {
self.0 self.0
.lock() .lock()
.await .await
.update_session(session_id, entries, expires) .update_session(session_id, entries, expires)
.await .await
} }
}
async fn remove_session(&self, session_id: &str) -> poem::Result<()> { /// Remove a session by session id.
self.0.lock().await.remove_session(session_id).await fn remove_session<'a>(
&'a self,
session_id: &'a str,
) -> impl Future<Output = poem::Result<()>> + Send + 'a {
async move { self.0.lock().await.remove_session(session_id).await }
} }
} }
@ -78,7 +86,7 @@ impl SessionStore {
} }
pub async fn process_request(&mut self, req: Request) -> poem::Result<Request> { pub async fn process_request(&mut self, req: Request) -> poem::Result<Request> {
let session: &Session = <_>::from_request_without_body(&req).await?; let session = <&Session>::from_request_without_body(&req).await?;
let request_counter = session.get::<u64>(REQUEST_COUNTER_SESSION_KEY).unwrap_or(0); let request_counter = session.get::<u64>(REQUEST_COUNTER_SESSION_KEY).unwrap_or(0);
session.set(REQUEST_COUNTER_SESSION_KEY, request_counter + 1); session.set(REQUEST_COUNTER_SESSION_KEY, request_counter + 1);
@ -97,14 +105,14 @@ impl SessionStore {
&mut self, &mut self,
req: &Request, req: &Request,
) -> poem::Result<WarpgateServerHandleFromRequest> { ) -> poem::Result<WarpgateServerHandleFromRequest> {
let session: &Session = <_>::from_request_without_body(req).await?; let session = <&Session>::from_request_without_body(req).await?;
if let Some(handle) = self.handle_for(session) { if let Some(handle) = self.handle_for(session) {
return Ok(handle.into()); return Ok(handle.into());
} }
let services = Data::<&Services>::from_request_without_body(req).await?; let services = Data::<&Services>::from_request_without_body(req).await?;
let remote_address: &RemoteAddr = <_>::from_request_without_body(req).await?; let remote_address = <&RemoteAddr>::from_request_without_body(req).await?;
let session_storage = Data::<&SharedSessionStorage>::from_request_without_body(req).await?; let session_storage = Data::<&SharedSessionStorage>::from_request_without_body(req).await?;
let (session_handle, mut session_handle_rx) = HttpSessionHandle::new(); let (session_handle, mut session_handle_rx) = HttpSessionHandle::new();

View file

@ -1,4 +1,5 @@
use std::any::type_name; use std::any::type_name;
use std::future::Future;
use std::sync::Arc; use std::sync::Arc;
use poem::error::GetDataError; use poem::error::GetDataError;
@ -43,11 +44,14 @@ impl std::ops::Deref for WarpgateServerHandleFromRequest {
} }
} }
#[async_trait::async_trait]
impl<'a> FromRequest<'a> for WarpgateServerHandleFromRequest { impl<'a> FromRequest<'a> for WarpgateServerHandleFromRequest {
async fn from_request(req: &'a Request, _: &mut RequestBody) -> poem::Result<Self> { fn from_request(
req: &'a Request,
_: &mut RequestBody,
) -> impl Future<Output = poem::Result<Self>> {
async move {
let sm = Data::<&Arc<Mutex<SessionStore>>>::from_request_without_body(req).await?; let sm = Data::<&Arc<Mutex<SessionStore>>>::from_request_without_body(req).await?;
let session: &Session = <_>::from_request_without_body(req).await?; let session = <&Session>::from_request_without_body(req).await?;
Ok(sm Ok(sm
.lock() .lock()
.await .await
@ -55,6 +59,7 @@ impl<'a> FromRequest<'a> for WarpgateServerHandleFromRequest {
.map(WarpgateServerHandleFromRequest) .map(WarpgateServerHandleFromRequest)
.ok_or_else(|| GetDataError(type_name::<WarpgateServerHandle>()))?) .ok_or_else(|| GetDataError(type_name::<WarpgateServerHandle>()))?)
} }
}
} }
impl From<Arc<Mutex<WarpgateServerHandle>>> for WarpgateServerHandleFromRequest { impl From<Arc<Mutex<WarpgateServerHandle>>> for WarpgateServerHandleFromRequest {

View file

@ -13,15 +13,15 @@ anyhow = { version = "1.0", features = ["std"] }
async-trait = "0.1" async-trait = "0.1"
tokio = { version = "1.20", features = ["tracing", "signal"] } tokio = { version = "1.20", features = ["tracing", "signal"] }
tracing = "0.1" tracing = "0.1"
uuid = { version = "1.2", features = ["v4"] } uuid = { version = "1.3", features = ["v4"] }
bytes = "1.3" bytes = "1.4"
mysql_common = "0.29" mysql_common = "0.29"
rand = "0.8" rand = "0.8"
sha1 = "0.10.5" sha1 = "0.10"
password-hash = { version = "0.2", features = ["std"] } password-hash = { version = "0.2", features = ["std"] }
rustls = { version = "0.20", features = ["dangerous_configuration"] } rustls = { version = "0.23", features = ["ring"], default-features = false }
rustls-pemfile = "1.0" rustls-pemfile = "1.0"
tokio-rustls = "0.23" tokio-rustls = "0.26"
thiserror = "1.0" thiserror = "1.0"
webpki = "0.22" webpki = "0.22"
once_cell = "1.17" once_cell = "1.17"

View file

@ -97,7 +97,7 @@ impl MySqlClient {
.upgrade(( .upgrade((
target target
.host .host
.as_str() .clone()
.try_into() .try_into()
.map_err(|_| MySqlError::InvalidDomainName)?, .map_err(|_| MySqlError::InvalidDomainName)?,
client_config, client_config,

View file

@ -63,9 +63,10 @@ impl ProtocolServer for MySQLProtocolServer {
} }
}; };
let tls_config = ServerConfig::builder() let tls_config =
.with_safe_defaults() ServerConfig::builder_with_provider(Arc::new(rustls::crypto::ring::default_provider()))
.with_client_cert_verifier(NoClientAuth::new()) .with_safe_default_protocol_versions()?
.with_client_cert_verifier(Arc::new(NoClientAuth))
.with_cert_resolver(Arc::new(ResolveServerCert(Arc::new( .with_cert_resolver(Arc::new(ResolveServerCert(Arc::new(
certificate_and_key.into(), certificate_and_key.into(),
)))); ))));

View file

@ -3,7 +3,8 @@ use std::sync::Arc;
use std::task::Poll; use std::task::Poll;
use async_trait::async_trait; use async_trait::async_trait;
use rustls::{ClientConfig, ServerConfig, ServerName}; use rustls::pki_types::ServerName;
use rustls::{ClientConfig, ServerConfig};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tracing::*; use tracing::*;
@ -126,7 +127,7 @@ impl<S> UpgradableStream<tokio_rustls::client::TlsStream<S>> for S
where where
S: AsyncRead + AsyncWrite + Unpin + Send, S: AsyncRead + AsyncWrite + Unpin + Send,
{ {
type UpgradeConfig = (ServerName, Arc<ClientConfig>); type UpgradeConfig = (ServerName<'static>, Arc<ClientConfig>);
async fn upgrade( async fn upgrade(
mut self, mut self,

View file

@ -1,15 +1,17 @@
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime;
use rustls::client::{ServerCertVerified, ServerCertVerifier, WebPkiVerifier}; use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::client::WebPkiServerVerifier;
use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use rustls::server::{ClientHello, ResolvesServerCert}; use rustls::server::{ClientHello, ResolvesServerCert};
use rustls::sign::CertifiedKey; use rustls::sign::CertifiedKey;
use rustls::{ClientConfig, Error as TlsError, ServerName}; use rustls::{CertificateError, ClientConfig, Error as TlsError, SignatureScheme};
use warpgate_common::RustlsSetupError; use warpgate_common::RustlsSetupError;
use super::ROOT_CERT_STORE; use super::ROOT_CERT_STORE;
#[derive(Debug)]
pub struct ResolveServerCert(pub Arc<CertifiedKey>); pub struct ResolveServerCert(pub Arc<CertifiedKey>);
impl ResolvesServerCert for ResolveServerCert { impl ResolvesServerCert for ResolveServerCert {
@ -23,10 +25,13 @@ pub async fn configure_tls_connector(
accept_invalid_hostnames: bool, accept_invalid_hostnames: bool,
root_cert: Option<&[u8]>, root_cert: Option<&[u8]>,
) -> Result<ClientConfig, RustlsSetupError> { ) -> Result<ClientConfig, RustlsSetupError> {
let config = ClientConfig::builder().with_safe_defaults(); let config =
ClientConfig::builder_with_provider(Arc::new(rustls::crypto::ring::default_provider()))
.with_safe_default_protocol_versions()?;
let config = if accept_invalid_certs { let config = if accept_invalid_certs {
config config
.dangerous()
.with_custom_certificate_verifier(Arc::new(DummyTlsVerifier)) .with_custom_certificate_verifier(Arc::new(DummyTlsVerifier))
.with_no_client_auth() .with_no_client_auth()
} else { } else {
@ -36,14 +41,15 @@ pub async fn configure_tls_connector(
let mut cursor = Cursor::new(data); let mut cursor = Cursor::new(data);
for cert in rustls_pemfile::certs(&mut cursor)? { for cert in rustls_pemfile::certs(&mut cursor)? {
cert_store.add(&rustls::Certificate(cert))?; cert_store.add(CertificateDer::from(cert))?;
} }
} }
if accept_invalid_hostnames { if accept_invalid_hostnames {
let verifier = WebPkiVerifier::new(cert_store, None); let verifier = WebPkiServerVerifier::builder(Arc::new(cert_store)).build()?;
config config
.dangerous()
.with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier }))
.with_no_client_auth() .with_no_client_auth()
} else { } else {
@ -56,50 +62,105 @@ pub async fn configure_tls_connector(
Ok(config) Ok(config)
} }
#[derive(Debug)]
pub struct DummyTlsVerifier; pub struct DummyTlsVerifier;
impl ServerCertVerifier for DummyTlsVerifier { impl ServerCertVerifier for DummyTlsVerifier {
fn verify_server_cert( fn verify_server_cert(
&self, &self,
_end_entity: &rustls::Certificate, _end_entity: &CertificateDer<'_>,
_intermediates: &[rustls::Certificate], _intermediates: &[CertificateDer<'_>],
_server_name: &ServerName, _server_name: &ServerName<'_>,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8], _ocsp_response: &[u8],
_now: SystemTime, _now: UnixTime,
) -> Result<ServerCertVerified, TlsError> { ) -> Result<ServerCertVerified, rustls::Error> {
Ok(ServerCertVerified::assertion()) Ok(ServerCertVerified::assertion())
} }
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &rustls::DigitallySignedStruct,
) -> Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {
Ok(HandshakeSignatureValid::assertion())
}
fn verify_tls13_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &rustls::DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, TlsError> {
Ok(HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
vec![
SignatureScheme::RSA_PKCS1_SHA1,
SignatureScheme::ECDSA_SHA1_Legacy,
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::ECDSA_NISTP521_SHA512,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
]
}
} }
#[derive(Debug)]
pub struct NoHostnameTlsVerifier { pub struct NoHostnameTlsVerifier {
verifier: WebPkiVerifier, verifier: Arc<WebPkiServerVerifier>,
} }
impl ServerCertVerifier for NoHostnameTlsVerifier { impl ServerCertVerifier for NoHostnameTlsVerifier {
fn verify_server_cert( fn verify_server_cert(
&self, &self,
end_entity: &rustls::Certificate, end_entity: &CertificateDer<'_>,
intermediates: &[rustls::Certificate], intermediates: &[CertificateDer<'_>],
server_name: &ServerName, server_name: &ServerName<'_>,
scts: &mut dyn Iterator<Item = &[u8]>,
ocsp_response: &[u8], ocsp_response: &[u8],
now: SystemTime, now: UnixTime,
) -> Result<ServerCertVerified, TlsError> { ) -> Result<ServerCertVerified, rustls::Error> {
match self.verifier.verify_server_cert( match self.verifier.verify_server_cert(
end_entity, end_entity,
intermediates, intermediates,
server_name, server_name,
scts,
ocsp_response, ocsp_response,
now, now,
) { ) {
Err(TlsError::InvalidCertificateData(reason)) Err(TlsError::InvalidCertificate(CertificateError::NotValidForName)) => {
if reason.contains("CertNotValidForName") =>
{
Ok(ServerCertVerified::assertion()) Ok(ServerCertVerified::assertion())
} }
res => res, res => res,
} }
} }
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, TlsError> {
self.verifier.verify_tls12_signature(message, cert, dss)
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, TlsError> {
self.verifier.verify_tls13_signature(message, cert, dss)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.verifier.supported_verify_schemes()
}
} }

View file

@ -1,4 +1,5 @@
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rustls::pki_types::CertificateDer;
use rustls::RootCertStore; use rustls::RootCertStore;
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
@ -8,7 +9,7 @@ pub static ROOT_CERT_STORE: Lazy<RootCertStore> = Lazy::new(|| {
rustls_native_certs::load_native_certs().expect("could not load root TLS certificates") rustls_native_certs::load_native_certs().expect("could not load root TLS certificates")
{ {
roots roots
.add(&rustls::Certificate(cert.0)) .add(CertificateDer::from(cert.0))
.expect("could not add root TLS certificate"); .expect("could not add root TLS certificate");
} }
roots roots

View file

@ -9,21 +9,21 @@ ansi_term = "0.12"
anyhow = { version = "1.0", features = ["std"] } anyhow = { version = "1.0", features = ["std"] }
async-trait = "0.1" async-trait = "0.1"
bimap = "0.6" bimap = "0.6"
bytes = "1.3" bytes = "1.4"
dialoguer = "0.10" dialoguer = "0.10"
curve25519-dalek = "4.0.0" # pin due to build fail on x86 curve25519-dalek = "4.0.0" # pin due to build fail on x86
ed25519-dalek = "2.0.0" # pin due to build fail on x86 in 2.1 ed25519-dalek = "2.0.0" # pin due to build fail on x86 in 2.1
futures = "0.3" futures = "0.3"
russh = { version = "0.44.1", features = ["legacy-ed25519-pkcs8-parser"] } russh = { version = "0.44.1", features = ["legacy-ed25519-pkcs8-parser"] }
# russh = { version = "0.35.0-beta.6", path = "../../russh/russh"} # russh = { version = "0.35.0-beta.6", path = "../../russh/russh"}
sea-orm = { version = "0.12.2", features = [ sea-orm = { version = "0.12", features = [
"runtime-tokio-rustls", "runtime-tokio-rustls",
], default-features = false } ], default-features = false }
thiserror = "1.0" thiserror = "1.0"
time = "0.3" time = "0.3"
tokio = { version = "1.20", features = ["tracing", "signal"] } tokio = { version = "1.20", features = ["tracing", "signal"] }
tracing = "0.1" tracing = "0.1"
uuid = { version = "1.2", features = ["v4"] } uuid = { version = "1.3", features = ["v4"] }
warpgate-common = { version = "*", path = "../warpgate-common" } warpgate-common = { version = "*", path = "../warpgate-common" }
warpgate-core = { version = "*", path = "../warpgate-core" } warpgate-core = { version = "*", path = "../warpgate-core" }
warpgate-db-entities = { version = "*", path = "../warpgate-db-entities" } warpgate-db-entities = { version = "*", path = "../warpgate-db-entities" }

View file

@ -5,7 +5,7 @@ name = "warpgate-sso"
version = "0.10.2" version = "0.10.2"
[dependencies] [dependencies]
bytes = "1.3" bytes = "1.4"
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1.20", features = ["tracing", "macros"] } tokio = { version = "1.20", features = ["tracing", "macros"] }
tracing = "0.1" tracing = "0.1"
@ -15,4 +15,4 @@ serde_json = "1.0"
once_cell = "1.17" once_cell = "1.17"
jsonwebtoken = "8" jsonwebtoken = "8"
data-encoding = "2.3" data-encoding = "2.3"
futures = "0.3.30" futures = "0.3"

View file

@ -6,8 +6,7 @@ mod sso;
pub use config::*; pub use config::*;
pub use error::*; pub use error::*;
pub use openidconnect::core::CoreIdToken;
pub use request::*; pub use request::*;
pub use response::*; pub use response::*;
pub use sso::*; pub use sso::*;
pub use openidconnect::core::CoreIdToken;

View file

@ -110,6 +110,6 @@ impl SsoClient {
req = req.set_id_token_hint(&token); req = req.set_id_token_hint(&token);
req = req.set_client_id(self.config.client_id().clone()); req = req.set_client_id(self.config.client_id().clone());
req = req.set_post_logout_redirect_uri(PostLogoutRedirectUrl::from_url(redirect_url)); req = req.set_post_logout_redirect_uri(PostLogoutRedirectUrl::from_url(redirect_url));
return Ok(req.http_get_url()); Ok(req.http_get_url())
} }
} }

View file

@ -1366,6 +1366,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"Password"
],
"example": "Password" "example": "Password"
} }
} }
@ -1385,6 +1388,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"PublicKey"
],
"example": "PublicKey" "example": "PublicKey"
} }
} }
@ -1572,6 +1578,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"Http"
],
"example": "Http" "example": "Http"
} }
} }
@ -1591,6 +1600,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"MySql"
],
"example": "MySql" "example": "MySql"
} }
} }
@ -1610,6 +1622,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"Ssh"
],
"example": "Ssh" "example": "Ssh"
} }
} }
@ -1629,6 +1644,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"WebAdmin"
],
"example": "WebAdmin" "example": "WebAdmin"
} }
} }
@ -1808,6 +1826,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"Password"
],
"example": "Password" "example": "Password"
} }
} }
@ -1827,6 +1848,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"PublicKey"
],
"example": "PublicKey" "example": "PublicKey"
} }
} }
@ -1846,6 +1870,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"Sso"
],
"example": "Sso" "example": "Sso"
} }
} }
@ -1865,6 +1892,9 @@
"properties": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
"enum": [
"Totp"
],
"example": "Totp" "example": "Totp"
} }
} }

View file

@ -9,18 +9,18 @@ ansi_term = "0.12"
anyhow = { version = "1.0", features = ["backtrace"] } anyhow = { version = "1.0", features = ["backtrace"] }
async-trait = "0.1" async-trait = "0.1"
atty = "0.2" atty = "0.2"
bytes = "1.3" bytes = "1.4"
clap = { version = "3.2", features = ["derive"] } clap = { version = "4.0", features = ["derive"] }
config = { version = "0.13", features = ["yaml"], default-features = false } config = { version = "0.13", features = ["yaml"], default-features = false }
console = { version = "0.15", default-features = false } console = { version = "0.15", default-features = false }
console-subscriber = { version = "0.1", optional = true } console-subscriber = { version = "0.1", optional = true }
data-encoding = "2.3" data-encoding = "2.3"
dialoguer = "0.10" dialoguer = "0.10"
futures = "0.3" futures = "0.3"
notify = "^5.0.0" notify = "5.1"
rcgen = { version = "0.10", features = ["zeroize"] } rcgen = { version = "0.10", features = ["zeroize"] }
serde_json = "1.0" serde_json = "1.0"
serde_yaml = "0.8.23" serde_yaml = "0.9"
sea-orm = { version = "0.12.2", default-features = false } sea-orm = { version = "0.12.2", default-features = false }
time = "0.3" time = "0.3"
tokio = { version = "1.20", features = ["tracing", "signal", "macros"] } tokio = { version = "1.20", features = ["tracing", "signal", "macros"] }
@ -29,7 +29,7 @@ tracing-subscriber = { version = "0.3", features = [
"env-filter", "env-filter",
"local-time", "local-time",
] } ] }
uuid = "1.2" uuid = "1.3"
warpgate-admin = { version = "*", path = "../warpgate-admin" } warpgate-admin = { version = "*", path = "../warpgate-admin" }
warpgate-common = { version = "*", path = "../warpgate-common" } warpgate-common = { version = "*", path = "../warpgate-common" }
warpgate-core = { version = "*", path = "../warpgate-core" } warpgate-core = { version = "*", path = "../warpgate-core" }

View file

@ -5,7 +5,7 @@ mod logging;
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use clap::{ArgAction, StructOpt}; use clap::{ArgAction, Parser};
use logging::init_logging; use logging::init_logging;
use tracing::*; use tracing::*;