itsi 0.1.4 → 0.1.5
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/Cargo.lock +20 -7
- data/crates/itsi_server/Cargo.toml +3 -0
- data/crates/itsi_server/src/server/listener.rs +11 -10
- data/crates/itsi_server/src/server/tls/locked_dir_cache.rs +94 -0
- data/crates/itsi_server/src/server/tls.rs +4 -3
- data/gems/scheduler/ext/itsi_server/Cargo.toml +3 -0
- data/gems/scheduler/ext/itsi_server/src/server/listener.rs +11 -10
- data/gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs +94 -0
- data/gems/scheduler/ext/itsi_server/src/server/tls.rs +4 -3
- data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
- data/gems/server/ext/itsi_server/Cargo.toml +3 -0
- data/gems/server/ext/itsi_server/src/server/listener.rs +11 -10
- data/gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs +94 -0
- data/gems/server/ext/itsi_server/src/server/tls.rs +4 -3
- data/gems/server/lib/itsi/server/version.rb +1 -1
- data/lib/itsi/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c3da3f1e894f11eff41ba4294705e11b323b0c67ced5056ded2ba3bf3fe214e
|
4
|
+
data.tar.gz: 7f47c950da4d638c639a9a5045bc21c6b9a1fa33180700bce2a1605816067ce2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97a77b338eb51a461bc93d8f822111cd7582105252174fd4b29665eb6be508acb1ad314afa4286bba915d57da38d78922a81cc7a32c61a9c95495aee6f348aff
|
7
|
+
data.tar.gz: 0c1484b3474f3a1acf5df54eeb0657a1dc4e5fb8d63a388576f39a9883e6bb19acb9630fedb19852d55c78bf4d81553ab0337201a573516c9a52da66988959a9
|
data/Cargo.lock
CHANGED
@@ -434,7 +434,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
434
434
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
435
435
|
dependencies = [
|
436
436
|
"libc",
|
437
|
-
"windows-sys 0.
|
437
|
+
"windows-sys 0.59.0",
|
438
438
|
]
|
439
439
|
|
440
440
|
[[package]]
|
@@ -479,6 +479,16 @@ dependencies = [
|
|
479
479
|
"percent-encoding",
|
480
480
|
]
|
481
481
|
|
482
|
+
[[package]]
|
483
|
+
name = "fs2"
|
484
|
+
version = "0.4.3"
|
485
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
486
|
+
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
487
|
+
dependencies = [
|
488
|
+
"libc",
|
489
|
+
"winapi",
|
490
|
+
]
|
491
|
+
|
482
492
|
[[package]]
|
483
493
|
name = "fs_extra"
|
484
494
|
version = "1.3.0"
|
@@ -974,10 +984,12 @@ name = "itsi-server"
|
|
974
984
|
version = "0.1.0"
|
975
985
|
dependencies = [
|
976
986
|
"async-channel",
|
987
|
+
"async-trait",
|
977
988
|
"base64",
|
978
989
|
"bytes",
|
979
990
|
"crossbeam",
|
980
991
|
"derive_more",
|
992
|
+
"fs2",
|
981
993
|
"futures",
|
982
994
|
"http",
|
983
995
|
"http-body-util",
|
@@ -993,6 +1005,7 @@ dependencies = [
|
|
993
1005
|
"pin-project",
|
994
1006
|
"rb-sys",
|
995
1007
|
"rcgen",
|
1008
|
+
"ring",
|
996
1009
|
"rustls",
|
997
1010
|
"rustls-pemfile",
|
998
1011
|
"socket2",
|
@@ -1480,7 +1493,7 @@ dependencies = [
|
|
1480
1493
|
"once_cell",
|
1481
1494
|
"socket2",
|
1482
1495
|
"tracing",
|
1483
|
-
"windows-sys 0.
|
1496
|
+
"windows-sys 0.59.0",
|
1484
1497
|
]
|
1485
1498
|
|
1486
1499
|
[[package]]
|
@@ -1684,9 +1697,9 @@ dependencies = [
|
|
1684
1697
|
|
1685
1698
|
[[package]]
|
1686
1699
|
name = "ring"
|
1687
|
-
version = "0.17.
|
1700
|
+
version = "0.17.14"
|
1688
1701
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1689
|
-
checksum = "
|
1702
|
+
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
1690
1703
|
dependencies = [
|
1691
1704
|
"cc",
|
1692
1705
|
"cfg-if",
|
@@ -1733,7 +1746,7 @@ dependencies = [
|
|
1733
1746
|
"errno",
|
1734
1747
|
"libc",
|
1735
1748
|
"linux-raw-sys 0.4.15",
|
1736
|
-
"windows-sys 0.
|
1749
|
+
"windows-sys 0.59.0",
|
1737
1750
|
]
|
1738
1751
|
|
1739
1752
|
[[package]]
|
@@ -1746,7 +1759,7 @@ dependencies = [
|
|
1746
1759
|
"errno",
|
1747
1760
|
"libc",
|
1748
1761
|
"linux-raw-sys 0.9.2",
|
1749
|
-
"windows-sys 0.
|
1762
|
+
"windows-sys 0.59.0",
|
1750
1763
|
]
|
1751
1764
|
|
1752
1765
|
[[package]]
|
@@ -1997,7 +2010,7 @@ dependencies = [
|
|
1997
2010
|
"getrandom 0.3.1",
|
1998
2011
|
"once_cell",
|
1999
2012
|
"rustix 1.0.1",
|
2000
|
-
"windows-sys 0.
|
2013
|
+
"windows-sys 0.59.0",
|
2001
2014
|
]
|
2002
2015
|
|
2003
2016
|
[[package]]
|
@@ -78,8 +78,9 @@ impl TokioListener {
|
|
78
78
|
{
|
79
79
|
let mut state = state.lock().await;
|
80
80
|
loop {
|
81
|
-
|
82
|
-
info!("Received acme event: {:?}", event)
|
81
|
+
match StreamExt::next(&mut *state).await {
|
82
|
+
Some(event) => info!("Received acme event: {:?}", event),
|
83
|
+
None => error!("Received no acme event"),
|
83
84
|
}
|
84
85
|
}
|
85
86
|
}
|
@@ -96,19 +97,19 @@ impl TokioListener {
|
|
96
97
|
}
|
97
98
|
ItsiTlsAcceptor::Automatic(acme_acceptor, _, rustls_config) => {
|
98
99
|
let accept_future = acme_acceptor.accept(tcp_stream.0);
|
99
|
-
match accept_future.await
|
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
|
100
|
+
match accept_future.await {
|
101
|
+
Ok(None) => Err(ItsiError::Pass()),
|
102
|
+
Ok(Some(start_handshake)) => {
|
103
|
+
let tls_stream = start_handshake.into_stream(rustls_config.clone()).await?;
|
107
104
|
Ok(IoStream::TcpTls {
|
108
105
|
stream: tls_stream,
|
109
106
|
addr: SockAddr::Tcp(Arc::new(tcp_stream.1)),
|
110
107
|
})
|
111
108
|
}
|
109
|
+
Err(error) => {
|
110
|
+
error!(error = format!("{:?}", error));
|
111
|
+
Err(ItsiError::Pass())
|
112
|
+
}
|
112
113
|
}
|
113
114
|
}
|
114
115
|
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
use async_trait::async_trait;
|
2
|
+
use fs2::FileExt; // for lock_exclusive, unlock
|
3
|
+
use std::fs::OpenOptions;
|
4
|
+
use std::io::Error as IoError;
|
5
|
+
use std::path::{Path, PathBuf};
|
6
|
+
use tokio_rustls_acme::caches::DirCache;
|
7
|
+
use tokio_rustls_acme::{AccountCache, CertCache};
|
8
|
+
|
9
|
+
/// A wrapper around DirCache that locks a file before writing cert/account data.
|
10
|
+
pub struct LockedDirCache<P: AsRef<Path> + Send + Sync> {
|
11
|
+
inner: DirCache<P>,
|
12
|
+
lock_path: PathBuf,
|
13
|
+
}
|
14
|
+
|
15
|
+
impl<P: AsRef<Path> + Send + Sync> LockedDirCache<P> {
|
16
|
+
pub fn new(dir: P) -> Self {
|
17
|
+
let dir_path = dir.as_ref().to_path_buf();
|
18
|
+
let lock_path = dir_path.join(".acme.lock");
|
19
|
+
Self {
|
20
|
+
inner: DirCache::new(dir),
|
21
|
+
lock_path,
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
fn lock_exclusive(&self) -> Result<std::fs::File, IoError> {
|
26
|
+
let lockfile = OpenOptions::new()
|
27
|
+
.write(true)
|
28
|
+
.truncate(true)
|
29
|
+
.open(&self.lock_path)?;
|
30
|
+
lockfile.lock_exclusive()?;
|
31
|
+
Ok(lockfile)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
#[async_trait]
|
36
|
+
impl<P: AsRef<Path> + Send + Sync> CertCache for LockedDirCache<P> {
|
37
|
+
type EC = IoError;
|
38
|
+
|
39
|
+
async fn load_cert(
|
40
|
+
&self,
|
41
|
+
domains: &[String],
|
42
|
+
directory_url: &str,
|
43
|
+
) -> Result<Option<Vec<u8>>, Self::EC> {
|
44
|
+
// Just delegate to the inner DirCache
|
45
|
+
self.inner.load_cert(domains, directory_url).await
|
46
|
+
}
|
47
|
+
|
48
|
+
async fn store_cert(
|
49
|
+
&self,
|
50
|
+
domains: &[String],
|
51
|
+
directory_url: &str,
|
52
|
+
cert: &[u8],
|
53
|
+
) -> Result<(), Self::EC> {
|
54
|
+
// Acquire the lock before storing
|
55
|
+
let lockfile = self.lock_exclusive()?;
|
56
|
+
|
57
|
+
// Perform the store operation
|
58
|
+
let result = self.inner.store_cert(domains, directory_url, cert).await;
|
59
|
+
|
60
|
+
// Unlock and return
|
61
|
+
let _ = fs2::FileExt::unlock(&lockfile);
|
62
|
+
result
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
#[async_trait]
|
67
|
+
impl<P: AsRef<Path> + Send + Sync> AccountCache for LockedDirCache<P> {
|
68
|
+
type EA = IoError;
|
69
|
+
|
70
|
+
async fn load_account(
|
71
|
+
&self,
|
72
|
+
contact: &[String],
|
73
|
+
directory_url: &str,
|
74
|
+
) -> Result<Option<Vec<u8>>, Self::EA> {
|
75
|
+
self.inner.load_account(contact, directory_url).await
|
76
|
+
}
|
77
|
+
|
78
|
+
async fn store_account(
|
79
|
+
&self,
|
80
|
+
contact: &[String],
|
81
|
+
directory_url: &str,
|
82
|
+
account: &[u8],
|
83
|
+
) -> Result<(), Self::EA> {
|
84
|
+
let lockfile = self.lock_exclusive()?;
|
85
|
+
|
86
|
+
let result = self
|
87
|
+
.inner
|
88
|
+
.store_account(contact, directory_url, account)
|
89
|
+
.await;
|
90
|
+
|
91
|
+
let _ = fs2::FileExt::unlock(&lockfile);
|
92
|
+
result
|
93
|
+
}
|
94
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
use base64::{engine::general_purpose, Engine as _};
|
2
2
|
use itsi_error::Result;
|
3
3
|
use itsi_tracing::info;
|
4
|
+
use locked_dir_cache::LockedDirCache;
|
4
5
|
use rcgen::{CertificateParams, DnType, KeyPair, SanType};
|
5
6
|
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
|
6
7
|
use rustls_pemfile::{certs, pkcs8_private_keys};
|
@@ -12,8 +13,8 @@ use std::{
|
|
12
13
|
};
|
13
14
|
use tokio::sync::Mutex;
|
14
15
|
use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
|
15
|
-
use tokio_rustls_acme::{
|
16
|
-
|
16
|
+
use tokio_rustls_acme::{AcmeAcceptor, AcmeConfig, AcmeState};
|
17
|
+
mod locked_dir_cache;
|
17
18
|
const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
|
18
19
|
const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
|
19
20
|
|
@@ -50,7 +51,7 @@ pub fn configure_tls(
|
|
50
51
|
);
|
51
52
|
let acme_state = AcmeConfig::new(domains)
|
52
53
|
.contact(["mailto:wc@pico.net.nz"])
|
53
|
-
.cache(
|
54
|
+
.cache(LockedDirCache::new("./rustls_acme_cache"))
|
54
55
|
.directory(directory_url)
|
55
56
|
.state();
|
56
57
|
let rustls_config = ServerConfig::builder()
|
@@ -78,8 +78,9 @@ impl TokioListener {
|
|
78
78
|
{
|
79
79
|
let mut state = state.lock().await;
|
80
80
|
loop {
|
81
|
-
|
82
|
-
info!("Received acme event: {:?}", event)
|
81
|
+
match StreamExt::next(&mut *state).await {
|
82
|
+
Some(event) => info!("Received acme event: {:?}", event),
|
83
|
+
None => error!("Received no acme event"),
|
83
84
|
}
|
84
85
|
}
|
85
86
|
}
|
@@ -96,19 +97,19 @@ impl TokioListener {
|
|
96
97
|
}
|
97
98
|
ItsiTlsAcceptor::Automatic(acme_acceptor, _, rustls_config) => {
|
98
99
|
let accept_future = acme_acceptor.accept(tcp_stream.0);
|
99
|
-
match accept_future.await
|
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
|
100
|
+
match accept_future.await {
|
101
|
+
Ok(None) => Err(ItsiError::Pass()),
|
102
|
+
Ok(Some(start_handshake)) => {
|
103
|
+
let tls_stream = start_handshake.into_stream(rustls_config.clone()).await?;
|
107
104
|
Ok(IoStream::TcpTls {
|
108
105
|
stream: tls_stream,
|
109
106
|
addr: SockAddr::Tcp(Arc::new(tcp_stream.1)),
|
110
107
|
})
|
111
108
|
}
|
109
|
+
Err(error) => {
|
110
|
+
error!(error = format!("{:?}", error));
|
111
|
+
Err(ItsiError::Pass())
|
112
|
+
}
|
112
113
|
}
|
113
114
|
}
|
114
115
|
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
use async_trait::async_trait;
|
2
|
+
use fs2::FileExt; // for lock_exclusive, unlock
|
3
|
+
use std::fs::OpenOptions;
|
4
|
+
use std::io::Error as IoError;
|
5
|
+
use std::path::{Path, PathBuf};
|
6
|
+
use tokio_rustls_acme::caches::DirCache;
|
7
|
+
use tokio_rustls_acme::{AccountCache, CertCache};
|
8
|
+
|
9
|
+
/// A wrapper around DirCache that locks a file before writing cert/account data.
|
10
|
+
pub struct LockedDirCache<P: AsRef<Path> + Send + Sync> {
|
11
|
+
inner: DirCache<P>,
|
12
|
+
lock_path: PathBuf,
|
13
|
+
}
|
14
|
+
|
15
|
+
impl<P: AsRef<Path> + Send + Sync> LockedDirCache<P> {
|
16
|
+
pub fn new(dir: P) -> Self {
|
17
|
+
let dir_path = dir.as_ref().to_path_buf();
|
18
|
+
let lock_path = dir_path.join(".acme.lock");
|
19
|
+
Self {
|
20
|
+
inner: DirCache::new(dir),
|
21
|
+
lock_path,
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
fn lock_exclusive(&self) -> Result<std::fs::File, IoError> {
|
26
|
+
let lockfile = OpenOptions::new()
|
27
|
+
.write(true)
|
28
|
+
.truncate(true)
|
29
|
+
.open(&self.lock_path)?;
|
30
|
+
lockfile.lock_exclusive()?;
|
31
|
+
Ok(lockfile)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
#[async_trait]
|
36
|
+
impl<P: AsRef<Path> + Send + Sync> CertCache for LockedDirCache<P> {
|
37
|
+
type EC = IoError;
|
38
|
+
|
39
|
+
async fn load_cert(
|
40
|
+
&self,
|
41
|
+
domains: &[String],
|
42
|
+
directory_url: &str,
|
43
|
+
) -> Result<Option<Vec<u8>>, Self::EC> {
|
44
|
+
// Just delegate to the inner DirCache
|
45
|
+
self.inner.load_cert(domains, directory_url).await
|
46
|
+
}
|
47
|
+
|
48
|
+
async fn store_cert(
|
49
|
+
&self,
|
50
|
+
domains: &[String],
|
51
|
+
directory_url: &str,
|
52
|
+
cert: &[u8],
|
53
|
+
) -> Result<(), Self::EC> {
|
54
|
+
// Acquire the lock before storing
|
55
|
+
let lockfile = self.lock_exclusive()?;
|
56
|
+
|
57
|
+
// Perform the store operation
|
58
|
+
let result = self.inner.store_cert(domains, directory_url, cert).await;
|
59
|
+
|
60
|
+
// Unlock and return
|
61
|
+
let _ = fs2::FileExt::unlock(&lockfile);
|
62
|
+
result
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
#[async_trait]
|
67
|
+
impl<P: AsRef<Path> + Send + Sync> AccountCache for LockedDirCache<P> {
|
68
|
+
type EA = IoError;
|
69
|
+
|
70
|
+
async fn load_account(
|
71
|
+
&self,
|
72
|
+
contact: &[String],
|
73
|
+
directory_url: &str,
|
74
|
+
) -> Result<Option<Vec<u8>>, Self::EA> {
|
75
|
+
self.inner.load_account(contact, directory_url).await
|
76
|
+
}
|
77
|
+
|
78
|
+
async fn store_account(
|
79
|
+
&self,
|
80
|
+
contact: &[String],
|
81
|
+
directory_url: &str,
|
82
|
+
account: &[u8],
|
83
|
+
) -> Result<(), Self::EA> {
|
84
|
+
let lockfile = self.lock_exclusive()?;
|
85
|
+
|
86
|
+
let result = self
|
87
|
+
.inner
|
88
|
+
.store_account(contact, directory_url, account)
|
89
|
+
.await;
|
90
|
+
|
91
|
+
let _ = fs2::FileExt::unlock(&lockfile);
|
92
|
+
result
|
93
|
+
}
|
94
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
use base64::{engine::general_purpose, Engine as _};
|
2
2
|
use itsi_error::Result;
|
3
3
|
use itsi_tracing::info;
|
4
|
+
use locked_dir_cache::LockedDirCache;
|
4
5
|
use rcgen::{CertificateParams, DnType, KeyPair, SanType};
|
5
6
|
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
|
6
7
|
use rustls_pemfile::{certs, pkcs8_private_keys};
|
@@ -12,8 +13,8 @@ use std::{
|
|
12
13
|
};
|
13
14
|
use tokio::sync::Mutex;
|
14
15
|
use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
|
15
|
-
use tokio_rustls_acme::{
|
16
|
-
|
16
|
+
use tokio_rustls_acme::{AcmeAcceptor, AcmeConfig, AcmeState};
|
17
|
+
mod locked_dir_cache;
|
17
18
|
const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
|
18
19
|
const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
|
19
20
|
|
@@ -50,7 +51,7 @@ pub fn configure_tls(
|
|
50
51
|
);
|
51
52
|
let acme_state = AcmeConfig::new(domains)
|
52
53
|
.contact(["mailto:wc@pico.net.nz"])
|
53
|
-
.cache(
|
54
|
+
.cache(LockedDirCache::new("./rustls_acme_cache"))
|
54
55
|
.directory(directory_url)
|
55
56
|
.state();
|
56
57
|
let rustls_config = ServerConfig::builder()
|
@@ -78,8 +78,9 @@ impl TokioListener {
|
|
78
78
|
{
|
79
79
|
let mut state = state.lock().await;
|
80
80
|
loop {
|
81
|
-
|
82
|
-
info!("Received acme event: {:?}", event)
|
81
|
+
match StreamExt::next(&mut *state).await {
|
82
|
+
Some(event) => info!("Received acme event: {:?}", event),
|
83
|
+
None => error!("Received no acme event"),
|
83
84
|
}
|
84
85
|
}
|
85
86
|
}
|
@@ -96,19 +97,19 @@ impl TokioListener {
|
|
96
97
|
}
|
97
98
|
ItsiTlsAcceptor::Automatic(acme_acceptor, _, rustls_config) => {
|
98
99
|
let accept_future = acme_acceptor.accept(tcp_stream.0);
|
99
|
-
match accept_future.await
|
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
|
100
|
+
match accept_future.await {
|
101
|
+
Ok(None) => Err(ItsiError::Pass()),
|
102
|
+
Ok(Some(start_handshake)) => {
|
103
|
+
let tls_stream = start_handshake.into_stream(rustls_config.clone()).await?;
|
107
104
|
Ok(IoStream::TcpTls {
|
108
105
|
stream: tls_stream,
|
109
106
|
addr: SockAddr::Tcp(Arc::new(tcp_stream.1)),
|
110
107
|
})
|
111
108
|
}
|
109
|
+
Err(error) => {
|
110
|
+
error!(error = format!("{:?}", error));
|
111
|
+
Err(ItsiError::Pass())
|
112
|
+
}
|
112
113
|
}
|
113
114
|
}
|
114
115
|
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
use async_trait::async_trait;
|
2
|
+
use fs2::FileExt; // for lock_exclusive, unlock
|
3
|
+
use std::fs::OpenOptions;
|
4
|
+
use std::io::Error as IoError;
|
5
|
+
use std::path::{Path, PathBuf};
|
6
|
+
use tokio_rustls_acme::caches::DirCache;
|
7
|
+
use tokio_rustls_acme::{AccountCache, CertCache};
|
8
|
+
|
9
|
+
/// A wrapper around DirCache that locks a file before writing cert/account data.
|
10
|
+
pub struct LockedDirCache<P: AsRef<Path> + Send + Sync> {
|
11
|
+
inner: DirCache<P>,
|
12
|
+
lock_path: PathBuf,
|
13
|
+
}
|
14
|
+
|
15
|
+
impl<P: AsRef<Path> + Send + Sync> LockedDirCache<P> {
|
16
|
+
pub fn new(dir: P) -> Self {
|
17
|
+
let dir_path = dir.as_ref().to_path_buf();
|
18
|
+
let lock_path = dir_path.join(".acme.lock");
|
19
|
+
Self {
|
20
|
+
inner: DirCache::new(dir),
|
21
|
+
lock_path,
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
fn lock_exclusive(&self) -> Result<std::fs::File, IoError> {
|
26
|
+
let lockfile = OpenOptions::new()
|
27
|
+
.write(true)
|
28
|
+
.truncate(true)
|
29
|
+
.open(&self.lock_path)?;
|
30
|
+
lockfile.lock_exclusive()?;
|
31
|
+
Ok(lockfile)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
#[async_trait]
|
36
|
+
impl<P: AsRef<Path> + Send + Sync> CertCache for LockedDirCache<P> {
|
37
|
+
type EC = IoError;
|
38
|
+
|
39
|
+
async fn load_cert(
|
40
|
+
&self,
|
41
|
+
domains: &[String],
|
42
|
+
directory_url: &str,
|
43
|
+
) -> Result<Option<Vec<u8>>, Self::EC> {
|
44
|
+
// Just delegate to the inner DirCache
|
45
|
+
self.inner.load_cert(domains, directory_url).await
|
46
|
+
}
|
47
|
+
|
48
|
+
async fn store_cert(
|
49
|
+
&self,
|
50
|
+
domains: &[String],
|
51
|
+
directory_url: &str,
|
52
|
+
cert: &[u8],
|
53
|
+
) -> Result<(), Self::EC> {
|
54
|
+
// Acquire the lock before storing
|
55
|
+
let lockfile = self.lock_exclusive()?;
|
56
|
+
|
57
|
+
// Perform the store operation
|
58
|
+
let result = self.inner.store_cert(domains, directory_url, cert).await;
|
59
|
+
|
60
|
+
// Unlock and return
|
61
|
+
let _ = fs2::FileExt::unlock(&lockfile);
|
62
|
+
result
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
#[async_trait]
|
67
|
+
impl<P: AsRef<Path> + Send + Sync> AccountCache for LockedDirCache<P> {
|
68
|
+
type EA = IoError;
|
69
|
+
|
70
|
+
async fn load_account(
|
71
|
+
&self,
|
72
|
+
contact: &[String],
|
73
|
+
directory_url: &str,
|
74
|
+
) -> Result<Option<Vec<u8>>, Self::EA> {
|
75
|
+
self.inner.load_account(contact, directory_url).await
|
76
|
+
}
|
77
|
+
|
78
|
+
async fn store_account(
|
79
|
+
&self,
|
80
|
+
contact: &[String],
|
81
|
+
directory_url: &str,
|
82
|
+
account: &[u8],
|
83
|
+
) -> Result<(), Self::EA> {
|
84
|
+
let lockfile = self.lock_exclusive()?;
|
85
|
+
|
86
|
+
let result = self
|
87
|
+
.inner
|
88
|
+
.store_account(contact, directory_url, account)
|
89
|
+
.await;
|
90
|
+
|
91
|
+
let _ = fs2::FileExt::unlock(&lockfile);
|
92
|
+
result
|
93
|
+
}
|
94
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
use base64::{engine::general_purpose, Engine as _};
|
2
2
|
use itsi_error::Result;
|
3
3
|
use itsi_tracing::info;
|
4
|
+
use locked_dir_cache::LockedDirCache;
|
4
5
|
use rcgen::{CertificateParams, DnType, KeyPair, SanType};
|
5
6
|
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
|
6
7
|
use rustls_pemfile::{certs, pkcs8_private_keys};
|
@@ -12,8 +13,8 @@ use std::{
|
|
12
13
|
};
|
13
14
|
use tokio::sync::Mutex;
|
14
15
|
use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
|
15
|
-
use tokio_rustls_acme::{
|
16
|
-
|
16
|
+
use tokio_rustls_acme::{AcmeAcceptor, AcmeConfig, AcmeState};
|
17
|
+
mod locked_dir_cache;
|
17
18
|
const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
|
18
19
|
const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
|
19
20
|
|
@@ -50,7 +51,7 @@ pub fn configure_tls(
|
|
50
51
|
);
|
51
52
|
let acme_state = AcmeConfig::new(domains)
|
52
53
|
.contact(["mailto:wc@pico.net.nz"])
|
53
|
-
.cache(
|
54
|
+
.cache(LockedDirCache::new("./rustls_acme_cache"))
|
54
55
|
.directory(directory_url)
|
55
56
|
.state();
|
56
57
|
let rustls_config = ServerConfig::builder()
|
data/lib/itsi/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itsi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wouter Coppieters
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- crates/itsi_server/src/server/signal.rs
|
92
92
|
- crates/itsi_server/src/server/thread_worker.rs
|
93
93
|
- crates/itsi_server/src/server/tls.rs
|
94
|
+
- crates/itsi_server/src/server/tls/locked_dir_cache.rs
|
94
95
|
- crates/itsi_tracing/Cargo.lock
|
95
96
|
- crates/itsi_tracing/Cargo.toml
|
96
97
|
- crates/itsi_tracing/src/lib.rs
|
@@ -148,6 +149,7 @@ files:
|
|
148
149
|
- gems/scheduler/ext/itsi_server/src/server/signal.rs
|
149
150
|
- gems/scheduler/ext/itsi_server/src/server/thread_worker.rs
|
150
151
|
- gems/scheduler/ext/itsi_server/src/server/tls.rs
|
152
|
+
- gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs
|
151
153
|
- gems/scheduler/ext/itsi_tracing/Cargo.lock
|
152
154
|
- gems/scheduler/ext/itsi_tracing/Cargo.toml
|
153
155
|
- gems/scheduler/ext/itsi_tracing/src/lib.rs
|
@@ -218,6 +220,7 @@ files:
|
|
218
220
|
- gems/server/ext/itsi_server/src/server/signal.rs
|
219
221
|
- gems/server/ext/itsi_server/src/server/thread_worker.rs
|
220
222
|
- gems/server/ext/itsi_server/src/server/tls.rs
|
223
|
+
- gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs
|
221
224
|
- gems/server/ext/itsi_tracing/Cargo.lock
|
222
225
|
- gems/server/ext/itsi_tracing/Cargo.toml
|
223
226
|
- gems/server/ext/itsi_tracing/src/lib.rs
|