itsi-scheduler 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/itsi_error/src/from.rs +1 -0
- data/ext/itsi_error/src/lib.rs +2 -0
- data/ext/itsi_scheduler/extconf.rb +1 -1
- data/ext/itsi_server/Cargo.toml +3 -1
- data/ext/itsi_server/extconf.rb +1 -1
- data/ext/itsi_server/src/lib.rs +3 -0
- data/ext/itsi_server/src/server/bind.rs +5 -4
- data/ext/itsi_server/src/server/itsi_server.rs +20 -6
- data/ext/itsi_server/src/server/lifecycle_event.rs +1 -0
- data/ext/itsi_server/src/server/listener.rs +83 -16
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +1 -0
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +9 -0
- data/ext/itsi_server/src/server/signal.rs +14 -1
- data/ext/itsi_server/src/server/tls.rs +76 -40
- data/lib/itsi/scheduler/version.rb +1 -1
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4759d488a010ea708b6f149ce902cb3777e554e7bb6aec147855325ae10a2dd
|
4
|
+
data.tar.gz: 6853013f6e0b8926cfcb7bf5b13ab58966611ab69a3274f201f76359ae472f5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6c780f95e94661c1a39035f8705a943c4274e27a8075f70c92d67daed6a6a70623f421731eb3ffa7bbae2488148d87b9f9772d9b34124f29b43e734000702ee
|
7
|
+
data.tar.gz: c11af0d97c617d984b4b2b005451abb1738ceb8ca9a3010c312cca35671d4c32434065eb2b1850de429a6321efa824dec5ffa1374f2a6b6f7c39685493cb9615
|
data/ext/itsi_error/src/from.rs
CHANGED
@@ -65,6 +65,7 @@ impl From<ItsiError> for magnus::Error {
|
|
65
65
|
ItsiError::ClientConnectionClosed => {
|
66
66
|
magnus::Error::new(magnus::exception::eof_error(), CLIENT_CONNECTION_CLOSED)
|
67
67
|
}
|
68
|
+
ItsiError::Pass() => magnus::Error::new(magnus::exception::interrupt(), "Pass"),
|
68
69
|
}
|
69
70
|
}
|
70
71
|
}
|
data/ext/itsi_error/src/lib.rs
CHANGED
data/ext/itsi_server/Cargo.toml
CHANGED
@@ -17,7 +17,7 @@ itsi_error = { path = "../itsi_error" }
|
|
17
17
|
socket2 = "0.5.8"
|
18
18
|
parking_lot = "0.12.3"
|
19
19
|
rustls-pemfile = "2.2.0"
|
20
|
-
tokio-rustls = "0.
|
20
|
+
tokio-rustls = "0.26.2"
|
21
21
|
bytes = "1.3"
|
22
22
|
rcgen = { version = "0.13.2", features = ["x509-parser", "pem"] }
|
23
23
|
base64 = "0.22.1"
|
@@ -39,3 +39,5 @@ httparse = "1.10.1"
|
|
39
39
|
async-channel = "2.3.1"
|
40
40
|
tempfile = "3.18.0"
|
41
41
|
sysinfo = "0.33.1"
|
42
|
+
tokio-rustls-acme = "0.6.0"
|
43
|
+
rustls = "0.23.23"
|
data/ext/itsi_server/extconf.rb
CHANGED
data/ext/itsi_server/src/lib.rs
CHANGED
@@ -56,6 +56,9 @@ pub fn log_error(msg: String) {
|
|
56
56
|
#[magnus::init]
|
57
57
|
fn init(ruby: &Ruby) -> Result<()> {
|
58
58
|
itsi_tracing::init();
|
59
|
+
rustls::crypto::aws_lc_rs::default_provider()
|
60
|
+
.install_default()
|
61
|
+
.ok();
|
59
62
|
|
60
63
|
let itsi = ruby.get_inner(&ITSI_MODULE);
|
61
64
|
itsi.define_singleton_method("log_debug", function!(log_debug, 1))?;
|
@@ -1,4 +1,7 @@
|
|
1
|
-
use super::{
|
1
|
+
use super::{
|
2
|
+
bind_protocol::BindProtocol,
|
3
|
+
tls::{configure_tls, ItsiTlsAcceptor},
|
4
|
+
};
|
2
5
|
use itsi_error::ItsiError;
|
3
6
|
use std::{
|
4
7
|
collections::HashMap,
|
@@ -6,8 +9,6 @@ use std::{
|
|
6
9
|
path::PathBuf,
|
7
10
|
str::FromStr,
|
8
11
|
};
|
9
|
-
use tokio_rustls::rustls::ServerConfig;
|
10
|
-
|
11
12
|
#[derive(Debug, Clone)]
|
12
13
|
pub enum BindAddress {
|
13
14
|
Ip(IpAddr),
|
@@ -26,7 +27,7 @@ pub struct Bind {
|
|
26
27
|
pub address: BindAddress,
|
27
28
|
pub port: Option<u16>, // None for Unix Sockets
|
28
29
|
pub protocol: BindProtocol,
|
29
|
-
pub tls_config: Option<
|
30
|
+
pub tls_config: Option<ItsiTlsAcceptor>,
|
30
31
|
}
|
31
32
|
|
32
33
|
impl std::fmt::Debug for Bind {
|
@@ -2,7 +2,7 @@ use super::{
|
|
2
2
|
bind::Bind,
|
3
3
|
listener::Listener,
|
4
4
|
serve_strategy::{cluster_mode::ClusterMode, single_mode::SingleMode},
|
5
|
-
signal::{reset_signal_handlers, SIGNAL_HANDLER_CHANNEL},
|
5
|
+
signal::{clear_signal_handlers, reset_signal_handlers, SIGNAL_HANDLER_CHANNEL},
|
6
6
|
};
|
7
7
|
use crate::{request::itsi_request::ItsiRequest, server::serve_strategy::ServeStrategy};
|
8
8
|
use derive_more::Debug;
|
@@ -195,9 +195,11 @@ impl Server {
|
|
195
195
|
Ok(Arc::new(listeners))
|
196
196
|
}
|
197
197
|
|
198
|
-
pub(crate) fn build_strategy(
|
198
|
+
pub(crate) fn build_strategy(
|
199
|
+
self,
|
200
|
+
listeners: Arc<Vec<Arc<Listener>>>,
|
201
|
+
) -> Result<ServeStrategy> {
|
199
202
|
let server = Arc::new(self);
|
200
|
-
let listeners = server.listeners()?;
|
201
203
|
|
202
204
|
let strategy = if server.config.workers == 1 {
|
203
205
|
ServeStrategy::Single(Arc::new(SingleMode::new(
|
@@ -218,13 +220,25 @@ impl Server {
|
|
218
220
|
pub fn start(&self) -> Result<()> {
|
219
221
|
reset_signal_handlers();
|
220
222
|
let rself = self.clone();
|
221
|
-
|
222
|
-
|
223
|
+
let listeners = self.listeners()?;
|
224
|
+
let listeners_clone = listeners.clone();
|
225
|
+
call_without_gvl(move || -> Result<()> {
|
226
|
+
let strategy = rself.build_strategy(listeners_clone)?;
|
223
227
|
if let Err(e) = strategy.run() {
|
224
228
|
error!("Error running server: {}", e);
|
225
229
|
strategy.stop()?;
|
226
230
|
}
|
231
|
+
drop(strategy);
|
227
232
|
Ok(())
|
228
|
-
})
|
233
|
+
})?;
|
234
|
+
if let Ok(listeners) = Arc::try_unwrap(listeners) {
|
235
|
+
listeners.into_iter().for_each(|listener| {
|
236
|
+
if let Ok(listener) = Arc::try_unwrap(listener) {
|
237
|
+
listener.unbind()
|
238
|
+
};
|
239
|
+
});
|
240
|
+
}
|
241
|
+
clear_signal_handlers();
|
242
|
+
Ok(())
|
229
243
|
}
|
230
244
|
}
|
@@ -1,7 +1,8 @@
|
|
1
1
|
use super::bind::{Bind, BindAddress};
|
2
2
|
use super::bind_protocol::BindProtocol;
|
3
3
|
use super::io_stream::IoStream;
|
4
|
-
use
|
4
|
+
use super::tls::ItsiTlsAcceptor;
|
5
|
+
use itsi_error::{ItsiError, Result};
|
5
6
|
use itsi_tracing::info;
|
6
7
|
use socket2::{Domain, Protocol, Socket, Type};
|
7
8
|
use std::net::{IpAddr, SocketAddr, TcpListener};
|
@@ -11,12 +12,14 @@ use tokio::net::TcpListener as TokioTcpListener;
|
|
11
12
|
use tokio::net::UnixListener as TokioUnixListener;
|
12
13
|
use tokio::net::{unix, TcpStream, UnixStream};
|
13
14
|
use tokio_rustls::TlsAcceptor;
|
15
|
+
use tokio_stream::StreamExt;
|
16
|
+
use tracing::error;
|
14
17
|
|
15
18
|
pub(crate) enum Listener {
|
16
19
|
Tcp(TcpListener),
|
17
|
-
TcpTls((TcpListener,
|
20
|
+
TcpTls((TcpListener, ItsiTlsAcceptor)),
|
18
21
|
Unix(UnixListener),
|
19
|
-
UnixTls((UnixListener,
|
22
|
+
UnixTls((UnixListener, ItsiTlsAcceptor)),
|
20
23
|
}
|
21
24
|
|
22
25
|
pub(crate) enum TokioListener {
|
@@ -27,7 +30,7 @@ pub(crate) enum TokioListener {
|
|
27
30
|
},
|
28
31
|
TcpTls {
|
29
32
|
listener: TokioTcpListener,
|
30
|
-
acceptor:
|
33
|
+
acceptor: ItsiTlsAcceptor,
|
31
34
|
host: String,
|
32
35
|
port: u16,
|
33
36
|
},
|
@@ -36,11 +39,19 @@ pub(crate) enum TokioListener {
|
|
36
39
|
},
|
37
40
|
UnixTls {
|
38
41
|
listener: TokioUnixListener,
|
39
|
-
acceptor:
|
42
|
+
acceptor: ItsiTlsAcceptor,
|
40
43
|
},
|
41
44
|
}
|
42
45
|
|
43
46
|
impl TokioListener {
|
47
|
+
pub fn unbind(self) {
|
48
|
+
match self {
|
49
|
+
TokioListener::Tcp { listener, .. } => drop(listener.into_std().unwrap()),
|
50
|
+
TokioListener::TcpTls { listener, .. } => drop(listener.into_std().unwrap()),
|
51
|
+
TokioListener::Unix { listener } => drop(listener.into_std().unwrap()),
|
52
|
+
TokioListener::UnixTls { listener, .. } => drop(listener.into_std().unwrap()),
|
53
|
+
};
|
54
|
+
}
|
44
55
|
pub(crate) async fn accept(&self) -> Result<IoStream> {
|
45
56
|
match self {
|
46
57
|
TokioListener::Tcp { listener, .. } => TokioListener::accept_tcp(listener).await,
|
@@ -59,9 +70,48 @@ impl TokioListener {
|
|
59
70
|
Self::to_tokio_io(Stream::TcpStream(tcp_stream), None).await
|
60
71
|
}
|
61
72
|
|
62
|
-
async fn
|
73
|
+
pub async fn spawn_state_task(&self) {
|
74
|
+
if let TokioListener::TcpTls {
|
75
|
+
acceptor: ItsiTlsAcceptor::Automatic(_acme_acceptor, state, _server_config),
|
76
|
+
..
|
77
|
+
} = self
|
78
|
+
{
|
79
|
+
let mut state = state.lock().await;
|
80
|
+
loop {
|
81
|
+
if let Some(event) = StreamExt::next(&mut *state).await {
|
82
|
+
info!("Received acme event: {:?}", event)
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
async fn accept_tls(
|
89
|
+
listener: &TokioTcpListener,
|
90
|
+
acceptor: &ItsiTlsAcceptor,
|
91
|
+
) -> Result<IoStream> {
|
63
92
|
let tcp_stream = listener.accept().await?;
|
64
|
-
|
93
|
+
match acceptor {
|
94
|
+
ItsiTlsAcceptor::Manual(tls_acceptor) => {
|
95
|
+
Self::to_tokio_io(Stream::TcpStream(tcp_stream), Some(tls_acceptor)).await
|
96
|
+
}
|
97
|
+
ItsiTlsAcceptor::Automatic(acme_acceptor, _, rustls_config) => {
|
98
|
+
let accept_future = acme_acceptor.accept(tcp_stream.0);
|
99
|
+
match accept_future.await.unwrap() {
|
100
|
+
None => Err(ItsiError::Pass()),
|
101
|
+
Some(start_handshake) => {
|
102
|
+
let tls_stream = start_handshake
|
103
|
+
.into_stream(rustls_config.clone())
|
104
|
+
.await
|
105
|
+
.unwrap();
|
106
|
+
// Wrap in your IoStream::TcpTls variant
|
107
|
+
Ok(IoStream::TcpTls {
|
108
|
+
stream: tls_stream,
|
109
|
+
addr: SockAddr::Tcp(Arc::new(tcp_stream.1)),
|
110
|
+
})
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
65
115
|
}
|
66
116
|
|
67
117
|
async fn accept_unix(listener: &TokioUnixListener) -> Result<IoStream> {
|
@@ -71,10 +121,20 @@ impl TokioListener {
|
|
71
121
|
|
72
122
|
async fn accept_unix_tls(
|
73
123
|
listener: &TokioUnixListener,
|
74
|
-
acceptor: &
|
124
|
+
acceptor: &ItsiTlsAcceptor,
|
75
125
|
) -> Result<IoStream> {
|
76
126
|
let unix_stream = listener.accept().await?;
|
77
|
-
|
127
|
+
match acceptor {
|
128
|
+
ItsiTlsAcceptor::Manual(tls_acceptor) => {
|
129
|
+
Self::to_tokio_io(Stream::UnixStream(unix_stream), Some(tls_acceptor)).await
|
130
|
+
}
|
131
|
+
ItsiTlsAcceptor::Automatic(_, _, _) => {
|
132
|
+
error!("Automatic TLS not supported on Unix sockets");
|
133
|
+
Err(ItsiError::UnsupportedProtocol(
|
134
|
+
"Automatic TLS on Unix Sockets".to_owned(),
|
135
|
+
))
|
136
|
+
}
|
137
|
+
}
|
78
138
|
}
|
79
139
|
|
80
140
|
async fn to_tokio_io(
|
@@ -166,6 +226,14 @@ impl std::fmt::Display for SockAddr {
|
|
166
226
|
}
|
167
227
|
|
168
228
|
impl Listener {
|
229
|
+
pub fn unbind(self) {
|
230
|
+
match self {
|
231
|
+
Listener::Tcp(listener) => drop(listener),
|
232
|
+
Listener::TcpTls((listener, _)) => drop(listener),
|
233
|
+
Listener::Unix(listener) => drop(listener),
|
234
|
+
Listener::UnixTls((listener, _)) => drop(listener),
|
235
|
+
};
|
236
|
+
}
|
169
237
|
pub fn to_tokio_listener(&self) -> TokioListener {
|
170
238
|
match self {
|
171
239
|
Listener::Tcp(listener) => TokioListener::Tcp {
|
@@ -213,16 +281,12 @@ impl TryFrom<Bind> for Listener {
|
|
213
281
|
BindProtocol::Http => Listener::Tcp(connect_tcp_socket(addr, bind.port.unwrap())?),
|
214
282
|
BindProtocol::Https => {
|
215
283
|
let tcp_listener = connect_tcp_socket(addr, bind.port.unwrap())?;
|
216
|
-
|
217
|
-
Listener::TcpTls((tcp_listener, tls_acceptor))
|
284
|
+
Listener::TcpTls((tcp_listener, bind.tls_config.unwrap()))
|
218
285
|
}
|
219
286
|
_ => unreachable!(),
|
220
287
|
},
|
221
288
|
BindAddress::UnixSocket(path) => match bind.tls_config {
|
222
|
-
Some(tls_config) =>
|
223
|
-
let tls_acceptor = TlsAcceptor::from(Arc::new(tls_config));
|
224
|
-
Listener::UnixTls((connect_unix_socket(&path)?, tls_acceptor))
|
225
|
-
}
|
289
|
+
Some(tls_config) => Listener::UnixTls((connect_unix_socket(&path)?, tls_config)),
|
226
290
|
None => Listener::Unix(connect_unix_socket(&path)?),
|
227
291
|
},
|
228
292
|
};
|
@@ -237,9 +301,11 @@ fn connect_tcp_socket(addr: IpAddr, port: u16) -> Result<TcpListener> {
|
|
237
301
|
};
|
238
302
|
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
|
239
303
|
let socket_address: SocketAddr = SocketAddr::new(addr, port);
|
304
|
+
socket.set_reuse_port(true).ok();
|
305
|
+
socket.set_reuse_address(true).ok();
|
240
306
|
socket.set_nonblocking(true).ok();
|
241
307
|
socket.set_nodelay(true).ok();
|
242
|
-
socket.set_recv_buffer_size(
|
308
|
+
socket.set_recv_buffer_size(262_144).ok();
|
243
309
|
socket.bind(&socket_address.into())?;
|
244
310
|
socket.listen(1024)?;
|
245
311
|
Ok(socket.into())
|
@@ -249,6 +315,7 @@ fn connect_unix_socket(path: &PathBuf) -> Result<UnixListener> {
|
|
249
315
|
let _ = std::fs::remove_file(path);
|
250
316
|
let socket = Socket::new(Domain::UNIX, Type::STREAM, None)?;
|
251
317
|
socket.set_nonblocking(true).ok();
|
318
|
+
|
252
319
|
let socket_address = socket2::SockAddr::unix(path)?;
|
253
320
|
|
254
321
|
info!("Binding to {:?}", path);
|
@@ -95,6 +95,12 @@ impl SingleMode {
|
|
95
95
|
let self_ref = self_ref.clone();
|
96
96
|
let listener = listener.clone();
|
97
97
|
let (shutdown_sender, mut shutdown_receiver) = tokio::sync::watch::channel::<RunningPhase>(RunningPhase::Running);
|
98
|
+
let listener_clone = listener.clone();
|
99
|
+
|
100
|
+
tokio::spawn(async move {
|
101
|
+
listener_clone.spawn_state_task().await;
|
102
|
+
});
|
103
|
+
|
98
104
|
listener_task_set.spawn(async move {
|
99
105
|
let strategy = self_ref.clone();
|
100
106
|
loop {
|
@@ -124,6 +130,9 @@ impl SingleMode {
|
|
124
130
|
}
|
125
131
|
}
|
126
132
|
}
|
133
|
+
if let Ok(listener) = Arc::try_unwrap(listener){
|
134
|
+
listener.unbind();
|
135
|
+
}
|
127
136
|
});
|
128
137
|
|
129
138
|
}
|
@@ -45,7 +45,8 @@ fn receive_signal(signum: i32, _: sighandler_t) {
|
|
45
45
|
}
|
46
46
|
}
|
47
47
|
|
48
|
-
pub fn reset_signal_handlers() {
|
48
|
+
pub fn reset_signal_handlers() -> bool {
|
49
|
+
SIGINT_COUNT.store(0, std::sync::atomic::Ordering::SeqCst);
|
49
50
|
unsafe {
|
50
51
|
libc::signal(libc::SIGTERM, receive_signal as usize);
|
51
52
|
libc::signal(libc::SIGINT, receive_signal as usize);
|
@@ -54,4 +55,16 @@ pub fn reset_signal_handlers() {
|
|
54
55
|
libc::signal(libc::SIGTTIN, receive_signal as usize);
|
55
56
|
libc::signal(libc::SIGTTOU, receive_signal as usize);
|
56
57
|
}
|
58
|
+
true
|
59
|
+
}
|
60
|
+
|
61
|
+
pub fn clear_signal_handlers() {
|
62
|
+
unsafe {
|
63
|
+
libc::signal(libc::SIGTERM, libc::SIG_DFL);
|
64
|
+
libc::signal(libc::SIGINT, libc::SIG_DFL);
|
65
|
+
libc::signal(libc::SIGUSR1, libc::SIG_DFL);
|
66
|
+
libc::signal(libc::SIGUSR2, libc::SIG_DFL);
|
67
|
+
libc::signal(libc::SIGTTIN, libc::SIG_DFL);
|
68
|
+
libc::signal(libc::SIGTTOU, libc::SIG_DFL);
|
69
|
+
}
|
57
70
|
}
|
@@ -1,21 +1,69 @@
|
|
1
1
|
use base64::{engine::general_purpose, Engine as _};
|
2
2
|
use itsi_error::Result;
|
3
|
-
use itsi_tracing::
|
3
|
+
use itsi_tracing::info;
|
4
4
|
use rcgen::{CertificateParams, DnType, KeyPair, SanType};
|
5
|
+
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
|
5
6
|
use rustls_pemfile::{certs, pkcs8_private_keys};
|
6
|
-
use std::{
|
7
|
-
|
7
|
+
use std::{
|
8
|
+
collections::HashMap,
|
9
|
+
env, fs,
|
10
|
+
io::{BufReader, Error},
|
11
|
+
sync::Arc,
|
12
|
+
};
|
13
|
+
use tokio::sync::Mutex;
|
14
|
+
use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
|
15
|
+
use tokio_rustls_acme::{caches::DirCache, AcmeAcceptor, AcmeConfig, AcmeState};
|
8
16
|
|
9
17
|
const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
|
10
18
|
const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
|
11
19
|
|
20
|
+
#[derive(Clone)]
|
21
|
+
pub enum ItsiTlsAcceptor {
|
22
|
+
Manual(TlsAcceptor),
|
23
|
+
Automatic(
|
24
|
+
AcmeAcceptor,
|
25
|
+
Arc<Mutex<AcmeState<Error>>>,
|
26
|
+
Arc<ServerConfig>,
|
27
|
+
),
|
28
|
+
}
|
29
|
+
|
12
30
|
// Generates a TLS configuration based on either :
|
13
31
|
// * Input "cert" and "key" options (either paths or Base64-encoded strings) or
|
14
32
|
// * Performs automatic certificate generation/retrieval. Generated certs use an internal self-signed Isti CA.
|
15
33
|
// If a non-local host or optional domain parameter is provided,
|
16
34
|
// an automated certificate will attempt to be fetched using let's encrypt.
|
17
|
-
pub fn configure_tls(
|
18
|
-
|
35
|
+
pub fn configure_tls(
|
36
|
+
host: &str,
|
37
|
+
query_params: &HashMap<String, String>,
|
38
|
+
) -> Result<ItsiTlsAcceptor> {
|
39
|
+
let domains = query_params
|
40
|
+
.get("domains")
|
41
|
+
.map(|v| v.split(',').map(String::from).collect::<Vec<_>>());
|
42
|
+
|
43
|
+
if query_params.get("cert").is_none() || query_params.get("key").is_none() {
|
44
|
+
if let Some(domains) = domains {
|
45
|
+
let directory_url = env::var("ACME_DIRECTORY_URL")
|
46
|
+
.unwrap_or_else(|_| "https://acme-v02.api.letsencrypt.org/directory".to_string());
|
47
|
+
info!(
|
48
|
+
domains = format!("{:?}", domains),
|
49
|
+
directory_url, "Requesting acme cert"
|
50
|
+
);
|
51
|
+
let acme_state = AcmeConfig::new(domains)
|
52
|
+
.contact(["mailto:wc@pico.net.nz"])
|
53
|
+
.cache(DirCache::new("./rustls_acme_cache"))
|
54
|
+
.directory(directory_url)
|
55
|
+
.state();
|
56
|
+
let rustls_config = ServerConfig::builder()
|
57
|
+
.with_no_client_auth()
|
58
|
+
.with_cert_resolver(acme_state.resolver());
|
59
|
+
let acceptor = acme_state.acceptor();
|
60
|
+
return Ok(ItsiTlsAcceptor::Automatic(
|
61
|
+
acceptor,
|
62
|
+
Arc::new(Mutex::new(acme_state)),
|
63
|
+
Arc::new(rustls_config),
|
64
|
+
));
|
65
|
+
}
|
66
|
+
}
|
19
67
|
let (certs, key) = if let (Some(cert_path), Some(key_path)) =
|
20
68
|
(query_params.get("cert"), query_params.get("key"))
|
21
69
|
{
|
@@ -24,36 +72,19 @@ pub fn configure_tls(host: &str, query_params: &HashMap<String, String>) -> Resu
|
|
24
72
|
let key = load_private_key(key_path);
|
25
73
|
(certs, key)
|
26
74
|
} else {
|
27
|
-
|
28
|
-
.get("domains")
|
29
|
-
.map(|v| v.split(',').map(String::from).collect());
|
30
|
-
let host_string = host.to_string();
|
31
|
-
let domains = domains_param.or_else(|| {
|
32
|
-
if host_string != "localhost" {
|
33
|
-
Some(vec![host_string])
|
34
|
-
} else {
|
35
|
-
None
|
36
|
-
}
|
37
|
-
});
|
38
|
-
|
39
|
-
if let Some(domains) = domains {
|
40
|
-
retrieve_acme_cert(domains)?
|
41
|
-
} else {
|
42
|
-
generate_ca_signed_cert(vec![host.to_owned()])?
|
43
|
-
}
|
75
|
+
generate_ca_signed_cert(vec![host.to_owned()])?
|
44
76
|
};
|
45
77
|
|
46
78
|
let mut config = ServerConfig::builder()
|
47
|
-
.with_safe_defaults()
|
48
79
|
.with_no_client_auth()
|
49
80
|
.with_single_cert(certs, key)
|
50
81
|
.expect("Failed to build TLS config");
|
51
82
|
|
52
83
|
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
53
|
-
Ok(config)
|
84
|
+
Ok(ItsiTlsAcceptor::Manual(TlsAcceptor::from(Arc::new(config))))
|
54
85
|
}
|
55
86
|
|
56
|
-
pub fn load_certs(path: &str) -> Vec<
|
87
|
+
pub fn load_certs(path: &str) -> Vec<CertificateDer<'static>> {
|
57
88
|
let data = if let Some(stripped) = path.strip_prefix("base64:") {
|
58
89
|
general_purpose::STANDARD
|
59
90
|
.decode(stripped)
|
@@ -71,14 +102,20 @@ pub fn load_certs(path: &str) -> Vec<Certificate> {
|
|
71
102
|
})
|
72
103
|
.collect::<Result<_>>()
|
73
104
|
.expect("Failed to parse certificate file");
|
74
|
-
certs_der
|
105
|
+
certs_der
|
106
|
+
.into_iter()
|
107
|
+
.map(|vec| {
|
108
|
+
// Convert the owned Vec<u8> into a CertificateDer and force 'static.
|
109
|
+
unsafe { std::mem::transmute(CertificateDer::from(vec)) }
|
110
|
+
})
|
111
|
+
.collect()
|
75
112
|
} else {
|
76
|
-
vec![
|
113
|
+
vec![CertificateDer::from(data)]
|
77
114
|
}
|
78
115
|
}
|
79
116
|
|
80
117
|
/// Loads a private key from a file or Base64.
|
81
|
-
pub fn load_private_key(path: &str) ->
|
118
|
+
pub fn load_private_key(path: &str) -> PrivateKeyDer<'static> {
|
82
119
|
let key_data = if let Some(stripped) = path.strip_prefix("base64:") {
|
83
120
|
general_purpose::STANDARD
|
84
121
|
.decode(stripped)
|
@@ -97,13 +134,15 @@ pub fn load_private_key(path: &str) -> PrivateKey {
|
|
97
134
|
.collect::<Result<_>>()
|
98
135
|
.expect("Failed to parse private key");
|
99
136
|
if !keys.is_empty() {
|
100
|
-
return
|
137
|
+
return PrivateKeyDer::try_from(keys[0].clone()).unwrap();
|
101
138
|
}
|
102
139
|
}
|
103
|
-
|
140
|
+
PrivateKeyDer::try_from(key_data).unwrap()
|
104
141
|
}
|
105
142
|
|
106
|
-
pub fn generate_ca_signed_cert(
|
143
|
+
pub fn generate_ca_signed_cert(
|
144
|
+
domains: Vec<String>,
|
145
|
+
) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)> {
|
107
146
|
info!("Generating New Itsi CA - Self signed Certificate. Use `itsi ca export` to export the CA certificate for import into your local trust store.");
|
108
147
|
|
109
148
|
let ca_kp = KeyPair::from_pem(ITS_CA_KEY).expect("Failed to load embedded CA key");
|
@@ -140,13 +179,10 @@ pub fn generate_ca_signed_cert(domains: Vec<String>) -> Result<(Vec<Certificate>
|
|
140
179
|
|
141
180
|
let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ca_kp).unwrap();
|
142
181
|
let ee_cert_der = ee_cert.der().to_vec();
|
143
|
-
let ee_cert =
|
144
|
-
let ca_cert =
|
145
|
-
Ok((
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
pub fn retrieve_acme_cert(domains: Vec<String>) -> Result<(Vec<Certificate>, PrivateKey)> {
|
150
|
-
warn!("Retrieving ACME cert for {}", domains.join(", "));
|
151
|
-
generate_ca_signed_cert(domains)
|
182
|
+
let ee_cert = CertificateDer::from(ee_cert_der);
|
183
|
+
let ca_cert = CertificateDer::from(ca_cert.der().to_vec());
|
184
|
+
Ok((
|
185
|
+
vec![ee_cert, ca_cert],
|
186
|
+
PrivateKeyDer::try_from(ee_key.serialize_der()).unwrap(),
|
187
|
+
))
|
152
188
|
}
|
metadata
CHANGED
@@ -1,28 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itsi-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wouter Coppieters
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-14 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
|
-
- !ruby/object:Gem::Dependency
|
13
|
-
name: libclang
|
14
|
-
requirement: !ruby/object:Gem::Requirement
|
15
|
-
requirements:
|
16
|
-
- - "~>"
|
17
|
-
- !ruby/object:Gem::Version
|
18
|
-
version: '14.0'
|
19
|
-
type: :runtime
|
20
|
-
prerelease: false
|
21
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
-
requirements:
|
23
|
-
- - "~>"
|
24
|
-
- !ruby/object:Gem::Version
|
25
|
-
version: '14.0'
|
26
12
|
- !ruby/object:Gem::Dependency
|
27
13
|
name: rb_sys
|
28
14
|
requirement: !ruby/object:Gem::Requirement
|