itsi-server 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9738897c1d51717595b2ab829af9a7ed03f14b818f451121abb9fe2dd90ae9a
4
- data.tar.gz: 5b0cbc6234c01a11f509541b4ca963ff6743f3d3190c1c55f26eecedb5a49351
3
+ metadata.gz: be27a619d6a8c35a088332bb467aaf1c15f1e146eefcb9eea4e2bfa30400a1a3
4
+ data.tar.gz: ac488266fb7e70c0e5a75ad8a14c0788d73a8e2c06df32c4e8968172477950c2
5
5
  SHA512:
6
- metadata.gz: ec4156d473dcbcc34bc9ae98bfb7161afd62b050fa8652630a26d7ca2dc3b226523b268cc21e86179cecd07a0699ce8766edb861a7dc9c729df1580c98ccff0e
7
- data.tar.gz: cb19f0a410357782a691ba8aba8b27d24b3484d284ec363c46c16e3ead74eb8d4fb29e9f32aed59fe8442b8df8a35768fca39fc687a53bb98d15e589b1147d1b
6
+ metadata.gz: 1b5e765780844d7ab418246aa44481bad579de73fcdb1b19001327456f4d643c5f7dbce310965dae975895ca98388dfeeaa74ab67542000c3d48cfb41e5a473e
7
+ data.tar.gz: 8cdc7c721573ec281918d80d33870636326c53e7a59b3c4752215a2c5c1da67df8461aff3dd933d56400a813811668b4ab92a6bcae3ca9ffa8e50fcededda8fd
@@ -41,3 +41,6 @@ tempfile = "3.18.0"
41
41
  sysinfo = "0.33.1"
42
42
  tokio-rustls-acme = "0.6.0"
43
43
  rustls = "0.23.23"
44
+ fs2 = "0.4.3"
45
+ ring = "0.17.14"
46
+ async-trait = "0.1.87"
@@ -78,8 +78,9 @@ impl TokioListener {
78
78
  {
79
79
  let mut state = state.lock().await;
80
80
  loop {
81
- if let Some(event) = StreamExt::next(&mut *state).await {
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.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
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::{caches::DirCache, AcmeAcceptor, AcmeConfig, AcmeState};
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(DirCache::new("./rustls_acme_cache"))
54
+ .cache(LockedDirCache::new("./rustls_acme_cache"))
54
55
  .directory(directory_url)
55
56
  .state();
56
57
  let rustls_config = ServerConfig::builder()
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Server
5
- VERSION = "0.1.4"
5
+ VERSION = "0.1.5"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itsi-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
@@ -96,6 +96,7 @@ files:
96
96
  - ext/itsi_server/src/server/signal.rs
97
97
  - ext/itsi_server/src/server/thread_worker.rs
98
98
  - ext/itsi_server/src/server/tls.rs
99
+ - ext/itsi_server/src/server/tls/locked_dir_cache.rs
99
100
  - ext/itsi_tracing/Cargo.lock
100
101
  - ext/itsi_tracing/Cargo.toml
101
102
  - ext/itsi_tracing/src/lib.rs