itsi 0.1.6 → 0.1.8

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.
Files changed (239) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +49 -0
  3. data/Rakefile +20 -0
  4. data/crates/itsi_error/src/from.rs +26 -29
  5. data/crates/itsi_error/src/lib.rs +1 -1
  6. data/crates/itsi_server/Cargo.lock +2956 -0
  7. data/crates/itsi_server/Cargo.toml +2 -1
  8. data/crates/itsi_server/src/env.rs +43 -0
  9. data/crates/itsi_server/src/lib.rs +1 -0
  10. data/crates/itsi_server/src/request/itsi_request.rs +7 -7
  11. data/crates/itsi_server/src/server/bind.rs +4 -3
  12. data/crates/itsi_server/src/server/itsi_server.rs +1 -8
  13. data/crates/itsi_server/src/server/listener.rs +98 -107
  14. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +22 -12
  15. data/crates/itsi_server/src/server/tls/locked_dir_cache.rs +3 -3
  16. data/crates/itsi_server/src/server/tls.rs +83 -44
  17. data/gems/scheduler/ext/itsi_error/src/from.rs +26 -29
  18. data/gems/scheduler/ext/itsi_error/src/lib.rs +1 -1
  19. data/gems/scheduler/ext/itsi_server/Cargo.lock +2956 -0
  20. data/gems/scheduler/ext/itsi_server/Cargo.toml +2 -1
  21. data/gems/scheduler/ext/itsi_server/src/env.rs +43 -0
  22. data/gems/scheduler/ext/itsi_server/src/lib.rs +1 -0
  23. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +7 -7
  24. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +4 -3
  25. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +1 -8
  26. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +98 -107
  27. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +22 -12
  28. data/gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs +3 -3
  29. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +83 -44
  30. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  31. data/gems/server/Cargo.lock +2917 -0
  32. data/gems/server/Cargo.toml +7 -0
  33. data/gems/server/ext/itsi_error/src/from.rs +26 -29
  34. data/gems/server/ext/itsi_error/src/lib.rs +1 -1
  35. data/gems/server/ext/itsi_server/Cargo.lock +2956 -0
  36. data/gems/server/ext/itsi_server/Cargo.toml +2 -1
  37. data/gems/server/ext/itsi_server/src/env.rs +43 -0
  38. data/gems/server/ext/itsi_server/src/lib.rs +1 -0
  39. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +7 -7
  40. data/gems/server/ext/itsi_server/src/server/bind.rs +4 -3
  41. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +1 -8
  42. data/gems/server/ext/itsi_server/src/server/listener.rs +98 -107
  43. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +22 -12
  44. data/gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs +3 -3
  45. data/gems/server/ext/itsi_server/src/server/tls.rs +83 -44
  46. data/gems/server/lib/itsi/index.html.erb +91 -0
  47. data/gems/server/lib/itsi/server/scheduler_mode.rb +1 -1
  48. data/gems/server/lib/itsi/server/version.rb +1 -1
  49. data/gems/server/lib/itsi/server.rb +22 -2
  50. data/lib/itsi/version.rb +1 -1
  51. data/sandbox/deploy/main.tf +237 -0
  52. data/sandbox/deploy/outputs.tf +4 -0
  53. data/sandbox/deploy/vars.tf +11 -0
  54. data/sandbox/falcon_benchmark/Gemfile +10 -0
  55. data/sandbox/falcon_benchmark/Gemfile.lock +140 -0
  56. data/sandbox/falcon_benchmark/config.ru +54 -0
  57. data/sandbox/itsi_sandbox_async/Gemfile +10 -0
  58. data/sandbox/itsi_sandbox_async/Gemfile.lock +69 -0
  59. data/sandbox/itsi_sandbox_async/config.ru +10 -0
  60. data/sandbox/itsi_sandbox_hanami/.env +2 -0
  61. data/sandbox/itsi_sandbox_hanami/.gitignore +6 -0
  62. data/sandbox/itsi_sandbox_hanami/.rspec +1 -0
  63. data/sandbox/itsi_sandbox_hanami/Gemfile +49 -0
  64. data/sandbox/itsi_sandbox_hanami/Gemfile.lock +440 -0
  65. data/sandbox/itsi_sandbox_hanami/Guardfile +9 -0
  66. data/sandbox/itsi_sandbox_hanami/Procfile.dev +2 -0
  67. data/sandbox/itsi_sandbox_hanami/README.md +1 -0
  68. data/sandbox/itsi_sandbox_hanami/Rakefile +3 -0
  69. data/sandbox/itsi_sandbox_hanami/app/action.rb +12 -0
  70. data/sandbox/itsi_sandbox_hanami/app/actions/.keep +0 -0
  71. data/sandbox/itsi_sandbox_hanami/app/assets/css/app.css +5 -0
  72. data/sandbox/itsi_sandbox_hanami/app/assets/images/favicon.ico +0 -0
  73. data/sandbox/itsi_sandbox_hanami/app/assets/js/app.js +1 -0
  74. data/sandbox/itsi_sandbox_hanami/app/db/relation.rb +10 -0
  75. data/sandbox/itsi_sandbox_hanami/app/db/repo.rb +10 -0
  76. data/sandbox/itsi_sandbox_hanami/app/db/struct.rb +10 -0
  77. data/sandbox/itsi_sandbox_hanami/app/operation.rb +9 -0
  78. data/sandbox/itsi_sandbox_hanami/app/relations/.keep +0 -0
  79. data/sandbox/itsi_sandbox_hanami/app/repos/.keep +0 -0
  80. data/sandbox/itsi_sandbox_hanami/app/structs/.keep +0 -0
  81. data/sandbox/itsi_sandbox_hanami/app/templates/layouts/app.html.erb +14 -0
  82. data/sandbox/itsi_sandbox_hanami/app/view.rb +9 -0
  83. data/sandbox/itsi_sandbox_hanami/app/views/helpers.rb +10 -0
  84. data/sandbox/itsi_sandbox_hanami/bin/dev +8 -0
  85. data/sandbox/itsi_sandbox_hanami/config/app.rb +8 -0
  86. data/sandbox/itsi_sandbox_hanami/config/assets.js +16 -0
  87. data/sandbox/itsi_sandbox_hanami/config/db/migrate/.keep +0 -0
  88. data/sandbox/itsi_sandbox_hanami/config/db/seeds.rb +15 -0
  89. data/sandbox/itsi_sandbox_hanami/config/puma.rb +47 -0
  90. data/sandbox/itsi_sandbox_hanami/config/routes.rb +7 -0
  91. data/sandbox/itsi_sandbox_hanami/config/settings.rb +9 -0
  92. data/sandbox/itsi_sandbox_hanami/config.ru +5 -0
  93. data/sandbox/itsi_sandbox_hanami/db/.keep +0 -0
  94. data/sandbox/itsi_sandbox_hanami/lib/itsi_hanami/types.rb +11 -0
  95. data/sandbox/itsi_sandbox_hanami/lib/tasks/.keep +0 -0
  96. data/sandbox/itsi_sandbox_hanami/package-lock.json +946 -0
  97. data/sandbox/itsi_sandbox_hanami/package.json +8 -0
  98. data/sandbox/itsi_sandbox_hanami/spec/requests/root_spec.rb +11 -0
  99. data/sandbox/itsi_sandbox_hanami/spec/spec_helper.rb +9 -0
  100. data/sandbox/itsi_sandbox_hanami/spec/support/db/cleaning.rb +42 -0
  101. data/sandbox/itsi_sandbox_hanami/spec/support/db.rb +10 -0
  102. data/sandbox/itsi_sandbox_hanami/spec/support/features.rb +5 -0
  103. data/sandbox/itsi_sandbox_hanami/spec/support/operations.rb +8 -0
  104. data/sandbox/itsi_sandbox_hanami/spec/support/requests.rb +13 -0
  105. data/sandbox/itsi_sandbox_hanami/spec/support/rspec.rb +61 -0
  106. data/sandbox/itsi_sandbox_rack/Gemfile +17 -0
  107. data/sandbox/itsi_sandbox_rack/Gemfile.lock +153 -0
  108. data/sandbox/itsi_sandbox_rack/config.ru +18 -0
  109. data/sandbox/itsi_sandbox_rack_lint/Gemfile +7 -0
  110. data/sandbox/itsi_sandbox_rack_lint/Gemfile.lock +27 -0
  111. data/sandbox/itsi_sandbox_rack_lint/config.ru +3 -0
  112. data/sandbox/itsi_sandbox_rails/.dockerignore +51 -0
  113. data/sandbox/itsi_sandbox_rails/.gitattributes +9 -0
  114. data/sandbox/itsi_sandbox_rails/.github/dependabot.yml +12 -0
  115. data/sandbox/itsi_sandbox_rails/.github/workflows/ci.yml +90 -0
  116. data/sandbox/itsi_sandbox_rails/.gitignore +34 -0
  117. data/sandbox/itsi_sandbox_rails/.kamal/hooks/docker-setup.sample +3 -0
  118. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-app-boot.sample +3 -0
  119. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-deploy.sample +14 -0
  120. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-proxy-reboot.sample +3 -0
  121. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-app-boot.sample +3 -0
  122. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-build.sample +51 -0
  123. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-connect.sample +47 -0
  124. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-deploy.sample +109 -0
  125. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  126. data/sandbox/itsi_sandbox_rails/.kamal/secrets +17 -0
  127. data/sandbox/itsi_sandbox_rails/.rubocop.yml +8 -0
  128. data/sandbox/itsi_sandbox_rails/.ruby-version +1 -0
  129. data/sandbox/itsi_sandbox_rails/Dockerfile +72 -0
  130. data/sandbox/itsi_sandbox_rails/Gemfile +72 -0
  131. data/sandbox/itsi_sandbox_rails/Gemfile.lock +480 -0
  132. data/sandbox/itsi_sandbox_rails/README.md +24 -0
  133. data/sandbox/itsi_sandbox_rails/Rakefile +6 -0
  134. data/sandbox/itsi_sandbox_rails/app/assets/images/.keep +0 -0
  135. data/sandbox/itsi_sandbox_rails/app/assets/stylesheets/application.css +10 -0
  136. data/sandbox/itsi_sandbox_rails/app/controllers/application_controller.rb +4 -0
  137. data/sandbox/itsi_sandbox_rails/app/controllers/concerns/.keep +0 -0
  138. data/sandbox/itsi_sandbox_rails/app/controllers/home_controller.rb +51 -0
  139. data/sandbox/itsi_sandbox_rails/app/controllers/live_controller.rb +41 -0
  140. data/sandbox/itsi_sandbox_rails/app/controllers/uploads_controller.rb +32 -0
  141. data/sandbox/itsi_sandbox_rails/app/helpers/application_helper.rb +2 -0
  142. data/sandbox/itsi_sandbox_rails/app/javascript/application.js +3 -0
  143. data/sandbox/itsi_sandbox_rails/app/javascript/controllers/application.js +9 -0
  144. data/sandbox/itsi_sandbox_rails/app/javascript/controllers/hello_controller.js +7 -0
  145. data/sandbox/itsi_sandbox_rails/app/javascript/controllers/index.js +4 -0
  146. data/sandbox/itsi_sandbox_rails/app/jobs/application_job.rb +7 -0
  147. data/sandbox/itsi_sandbox_rails/app/mailers/application_mailer.rb +4 -0
  148. data/sandbox/itsi_sandbox_rails/app/models/application_record.rb +3 -0
  149. data/sandbox/itsi_sandbox_rails/app/models/concerns/.keep +0 -0
  150. data/sandbox/itsi_sandbox_rails/app/models/post.rb +2 -0
  151. data/sandbox/itsi_sandbox_rails/app/views/layouts/application.html.erb +28 -0
  152. data/sandbox/itsi_sandbox_rails/app/views/layouts/mailer.html.erb +13 -0
  153. data/sandbox/itsi_sandbox_rails/app/views/layouts/mailer.text.erb +1 -0
  154. data/sandbox/itsi_sandbox_rails/app/views/pwa/manifest.json.erb +22 -0
  155. data/sandbox/itsi_sandbox_rails/app/views/pwa/service-worker.js +26 -0
  156. data/sandbox/itsi_sandbox_rails/bin/brakeman +7 -0
  157. data/sandbox/itsi_sandbox_rails/bin/bundle +109 -0
  158. data/sandbox/itsi_sandbox_rails/bin/dev +2 -0
  159. data/sandbox/itsi_sandbox_rails/bin/docker-entrypoint +14 -0
  160. data/sandbox/itsi_sandbox_rails/bin/importmap +4 -0
  161. data/sandbox/itsi_sandbox_rails/bin/jobs +6 -0
  162. data/sandbox/itsi_sandbox_rails/bin/kamal +27 -0
  163. data/sandbox/itsi_sandbox_rails/bin/rails +4 -0
  164. data/sandbox/itsi_sandbox_rails/bin/rake +4 -0
  165. data/sandbox/itsi_sandbox_rails/bin/rubocop +8 -0
  166. data/sandbox/itsi_sandbox_rails/bin/setup +34 -0
  167. data/sandbox/itsi_sandbox_rails/bin/thrust +5 -0
  168. data/sandbox/itsi_sandbox_rails/config/application.rb +61 -0
  169. data/sandbox/itsi_sandbox_rails/config/boot.rb +4 -0
  170. data/sandbox/itsi_sandbox_rails/config/cable.yml +17 -0
  171. data/sandbox/itsi_sandbox_rails/config/cache.yml +16 -0
  172. data/sandbox/itsi_sandbox_rails/config/credentials.yml.enc +1 -0
  173. data/sandbox/itsi_sandbox_rails/config/database.yml +40 -0
  174. data/sandbox/itsi_sandbox_rails/config/deploy.yml +116 -0
  175. data/sandbox/itsi_sandbox_rails/config/environment.rb +5 -0
  176. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +72 -0
  177. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +90 -0
  178. data/sandbox/itsi_sandbox_rails/config/environments/test.rb +53 -0
  179. data/sandbox/itsi_sandbox_rails/config/importmap.rb +7 -0
  180. data/sandbox/itsi_sandbox_rails/config/initializers/assets.rb +7 -0
  181. data/sandbox/itsi_sandbox_rails/config/initializers/content_security_policy.rb +25 -0
  182. data/sandbox/itsi_sandbox_rails/config/initializers/filter_parameter_logging.rb +8 -0
  183. data/sandbox/itsi_sandbox_rails/config/initializers/inflections.rb +16 -0
  184. data/sandbox/itsi_sandbox_rails/config/locales/en.yml +31 -0
  185. data/sandbox/itsi_sandbox_rails/config/puma.rb +41 -0
  186. data/sandbox/itsi_sandbox_rails/config/queue.yml +18 -0
  187. data/sandbox/itsi_sandbox_rails/config/recurring.yml +10 -0
  188. data/sandbox/itsi_sandbox_rails/config/routes.rb +21 -0
  189. data/sandbox/itsi_sandbox_rails/config/storage.yml +34 -0
  190. data/sandbox/itsi_sandbox_rails/config.ru +7 -0
  191. data/sandbox/itsi_sandbox_rails/db/cable_schema.rb +11 -0
  192. data/sandbox/itsi_sandbox_rails/db/cache_schema.rb +14 -0
  193. data/sandbox/itsi_sandbox_rails/db/migrate/20250301041554_create_posts.rb +10 -0
  194. data/sandbox/itsi_sandbox_rails/db/queue_schema.rb +129 -0
  195. data/sandbox/itsi_sandbox_rails/db/schema.rb +23 -0
  196. data/sandbox/itsi_sandbox_rails/db/seeds.rb +9 -0
  197. data/sandbox/itsi_sandbox_rails/lib/tasks/.keep +0 -0
  198. data/sandbox/itsi_sandbox_rails/log/.keep +0 -0
  199. data/sandbox/itsi_sandbox_rails/public/400.html +114 -0
  200. data/sandbox/itsi_sandbox_rails/public/404.html +114 -0
  201. data/sandbox/itsi_sandbox_rails/public/406-unsupported-browser.html +114 -0
  202. data/sandbox/itsi_sandbox_rails/public/422.html +114 -0
  203. data/sandbox/itsi_sandbox_rails/public/500.html +114 -0
  204. data/sandbox/itsi_sandbox_rails/public/icon.png +0 -0
  205. data/sandbox/itsi_sandbox_rails/public/icon.svg +3 -0
  206. data/sandbox/itsi_sandbox_rails/public/robots.txt +1 -0
  207. data/sandbox/itsi_sandbox_rails/script/.keep +0 -0
  208. data/sandbox/itsi_sandbox_rails/storage/.keep +0 -0
  209. data/sandbox/itsi_sandbox_rails/test/application_system_test_case.rb +5 -0
  210. data/sandbox/itsi_sandbox_rails/test/controllers/.keep +0 -0
  211. data/sandbox/itsi_sandbox_rails/test/fixtures/files/.keep +0 -0
  212. data/sandbox/itsi_sandbox_rails/test/fixtures/posts.yml +9 -0
  213. data/sandbox/itsi_sandbox_rails/test/helpers/.keep +0 -0
  214. data/sandbox/itsi_sandbox_rails/test/integration/.keep +0 -0
  215. data/sandbox/itsi_sandbox_rails/test/mailers/.keep +0 -0
  216. data/sandbox/itsi_sandbox_rails/test/models/.keep +0 -0
  217. data/sandbox/itsi_sandbox_rails/test/models/post_test.rb +7 -0
  218. data/sandbox/itsi_sandbox_rails/test/system/.keep +0 -0
  219. data/sandbox/itsi_sandbox_rails/test/test_helper.rb +15 -0
  220. data/sandbox/itsi_sandbox_rails/tmp/.keep +0 -0
  221. data/sandbox/itsi_sandbox_rails/tmp/pids/.keep +0 -0
  222. data/sandbox/itsi_sandbox_rails/tmp/storage/.keep +0 -0
  223. data/sandbox/itsi_sandbox_rails/vendor/.keep +0 -0
  224. data/sandbox/itsi_sandbox_rails/vendor/javascript/.keep +0 -0
  225. data/sandbox/itsi_sandbox_roda/Gemfile +5 -0
  226. data/sandbox/itsi_sandbox_roda/Gemfile.lock +44 -0
  227. data/sandbox/itsi_sandbox_roda/config.ru +39 -0
  228. data/sandbox/itsi_sinatra/Gemfile +9 -0
  229. data/sandbox/itsi_sinatra/Gemfile.lock +81 -0
  230. data/sandbox/itsi_sinatra/app.rb +9 -0
  231. data/sandbox/pebble/docker-compose.yml +11 -0
  232. data/tasks.txt +10 -4
  233. metadata +196 -12
  234. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -13
  235. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
  236. data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -13
  237. data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
  238. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -13
  239. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
@@ -2,7 +2,9 @@ use base64::{engine::general_purpose, Engine as _};
2
2
  use itsi_error::Result;
3
3
  use itsi_tracing::info;
4
4
  use locked_dir_cache::LockedDirCache;
5
- use rcgen::{CertificateParams, DnType, KeyPair, SanType};
5
+ use rcgen::{
6
+ generate_simple_self_signed, CertificateParams, CertifiedKey, DnType, KeyPair, SanType,
7
+ };
6
8
  use rustls::{
7
9
  pki_types::{CertificateDer, PrivateKeyDer},
8
10
  ClientConfig, RootCertStore,
@@ -10,16 +12,19 @@ use rustls::{
10
12
  use rustls_pemfile::{certs, pkcs8_private_keys};
11
13
  use std::{
12
14
  collections::HashMap,
13
- env, fs,
15
+ fs,
14
16
  io::{BufReader, Error},
15
17
  sync::Arc,
16
18
  };
17
19
  use tokio::sync::Mutex;
18
20
  use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
19
21
  use tokio_rustls_acme::{AcmeAcceptor, AcmeConfig, AcmeState};
22
+
23
+ use crate::env::{
24
+ ITSI_ACME_CACHE_DIR, ITSI_ACME_CA_PEM_PATH, ITSI_ACME_CONTACT_EMAIL, ITSI_ACME_DIRECTORY_URL,
25
+ ITSI_LOCAL_CA_DIR,
26
+ };
20
27
  mod locked_dir_cache;
21
- const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
22
- const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
23
28
 
24
29
  #[derive(Clone)]
25
30
  pub enum ItsiTlsAcceptor {
@@ -31,11 +36,12 @@ pub enum ItsiTlsAcceptor {
31
36
  ),
32
37
  }
33
38
 
34
- // Generates a TLS configuration based on either :
35
- // * Input "cert" and "key" options (either paths or Base64-encoded strings) or
36
- // * Performs automatic certificate generation/retrieval. Generated certs use an internal self-signed Isti CA.
37
- // If a non-local host or optional domain parameter is provided,
38
- // an automated certificate will attempt to be fetched using let's encrypt.
39
+ /// Generates a TLS configuration based on either :
40
+ /// * Input "cert" and "key" options (either paths or Base64-encoded strings) or
41
+ /// * Performs automatic certificate generation/retrieval. Generated certs use an internal self-signed Isti CA.
42
+ ///
43
+ /// If a non-local host or optional domain parameter is provided,
44
+ /// an automated certificate will attempt to be fetched using let's encrypt.
39
45
  pub fn configure_tls(
40
46
  host: &str,
41
47
  query_params: &HashMap<String, String>,
@@ -44,17 +50,27 @@ pub fn configure_tls(
44
50
  .get("domains")
45
51
  .map(|v| v.split(',').map(String::from).collect::<Vec<_>>());
46
52
 
47
- if query_params.get("cert").is_none() || query_params.get("key").is_none() {
53
+ if query_params.get("cert").is_some_and(|c| c == "auto") {
48
54
  if let Some(domains) = domains {
49
- let directory_url = env::var("ACME_DIRECTORY_URL")
50
- .unwrap_or_else(|_| "https://acme-v02.api.letsencrypt.org/directory".to_string());
55
+ let directory_url = &*ITSI_ACME_DIRECTORY_URL;
51
56
  info!(
52
57
  domains = format!("{:?}", domains),
53
58
  directory_url, "Requesting acme cert"
54
59
  );
55
60
 
56
- let mut root_cert_store = RootCertStore::empty();
57
- if let Ok(ca_pem_path) = env::var("ITSI_ACME_CA_PEM_PATH") {
61
+ let acme_config = AcmeConfig::new(domains)
62
+ .contact([format!("mailto:{}", (*ITSI_ACME_CONTACT_EMAIL).as_ref().map_err(|_| {
63
+ itsi_error::ItsiError::ArgumentError(
64
+ "ITSI_ACME_CONTACT_EMAIL must be set before you can auto-generate production certificates"
65
+ .to_string(),
66
+ )
67
+ })?)])
68
+ .cache(LockedDirCache::new(&*ITSI_ACME_CACHE_DIR))
69
+ .directory(directory_url);
70
+
71
+ let acme_state = if let Ok(ca_pem_path) = &*ITSI_ACME_CA_PEM_PATH {
72
+ let mut root_cert_store = RootCertStore::empty();
73
+
58
74
  let ca_pem = fs::read(ca_pem_path).expect("failed to read CA pem file");
59
75
  let mut ca_reader = BufReader::new(&ca_pem[..]);
60
76
  let der_certs: Vec<CertificateDer> = certs(&mut ca_reader)
@@ -66,31 +82,23 @@ pub fn configure_tls(
66
82
  ))
67
83
  })?;
68
84
  root_cert_store.add_parsable_certificates(der_certs);
69
- }
70
85
 
71
- let client_config = ClientConfig::builder()
72
- .with_root_certificates(root_cert_store)
73
- .with_no_client_auth();
74
-
75
- let contact_email = env::var("ITSI_ACME_CONTACT_EMAIL").map_err(|_| {
76
- itsi_error::ItsiError::ArgumentError(
77
- "ITSI_ACME_CONTACT_EMAIL must be set before you can auto-generate production certificates"
78
- .to_string(),
79
- )
80
- })?;
81
-
82
- let cache_dir = env::var("ITSI_ACME_CACHE_DIR")
83
- .unwrap_or_else(|_| "./.rustls_acme_cache".to_string());
84
-
85
- let acme_state = AcmeConfig::new(domains)
86
- .contact([format!("mailto:{}", contact_email)])
87
- .cache(LockedDirCache::new(cache_dir))
88
- .directory(directory_url)
89
- .client_tls_config(Arc::new(client_config))
90
- .state();
91
- let rustls_config = ServerConfig::builder()
86
+ let client_config = ClientConfig::builder()
87
+ .with_root_certificates(root_cert_store)
88
+ .with_no_client_auth();
89
+ acme_config
90
+ .client_tls_config(Arc::new(client_config))
91
+ .state()
92
+ } else {
93
+ acme_config.state()
94
+ };
95
+
96
+ let mut rustls_config = ServerConfig::builder()
92
97
  .with_no_client_auth()
93
98
  .with_cert_resolver(acme_state.resolver());
99
+
100
+ rustls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
101
+
94
102
  let acceptor = acme_state.acceptor();
95
103
  return Ok(ItsiTlsAcceptor::Automatic(
96
104
  acceptor,
@@ -107,7 +115,7 @@ pub fn configure_tls(
107
115
  let key = load_private_key(key_path);
108
116
  (certs, key)
109
117
  } else {
110
- generate_ca_signed_cert(vec![host.to_owned()])?
118
+ generate_ca_signed_cert(domains.unwrap_or(vec![host.to_owned()]))?
111
119
  };
112
120
 
113
121
  let mut config = ServerConfig::builder()
@@ -178,10 +186,19 @@ pub fn load_private_key(path: &str) -> PrivateKeyDer<'static> {
178
186
  pub fn generate_ca_signed_cert(
179
187
  domains: Vec<String>,
180
188
  ) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)> {
181
- info!("Generating New Itsi CA - Self signed Certificate. Use `itsi ca export` to export the CA certificate for import into your local trust store.");
189
+ info!(
190
+ domains = format!("{}", domains.join(", ")),
191
+ "Self signed cert",
192
+ );
193
+ info!(
194
+ "Add {} to your system's trusted cert store to resolve certificate errors.",
195
+ format!("{}/itsi_dev_ca.crt", ITSI_LOCAL_CA_DIR.to_str().unwrap())
196
+ );
197
+ info!("Dev CA path can be overridden by setting env var: `ITSI_LOCAL_CA_DIR`.");
198
+ let (ca_key_pem, ca_cert_pem) = get_or_create_local_dev_ca()?;
182
199
 
183
- let ca_kp = KeyPair::from_pem(ITS_CA_KEY).expect("Failed to load embedded CA key");
184
- let ca_cert = CertificateParams::from_ca_cert_pem(ITS_CA_CERT)
200
+ let ca_kp = KeyPair::from_pem(&ca_key_pem).expect("Failed to load CA key");
201
+ let ca_cert = CertificateParams::from_ca_cert_pem(&ca_cert_pem)
185
202
  .expect("Failed to parse embedded CA certificate")
186
203
  .self_signed(&ca_kp)
187
204
  .expect("Failed to self-sign embedded CA cert");
@@ -189,10 +206,6 @@ pub fn generate_ca_signed_cert(
189
206
  let ee_key = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap();
190
207
  let mut ee_params = CertificateParams::default();
191
208
 
192
- info!(
193
- "Generated certificate will be valid for domains {:?}",
194
- domains
195
- );
196
209
  use std::net::IpAddr;
197
210
 
198
211
  ee_params.subject_alt_names = domains
@@ -221,3 +234,29 @@ pub fn generate_ca_signed_cert(
221
234
  PrivateKeyDer::try_from(ee_key.serialize_der()).unwrap(),
222
235
  ))
223
236
  }
237
+
238
+ fn get_or_create_local_dev_ca() -> Result<(String, String)> {
239
+ let ca_dir = &*ITSI_LOCAL_CA_DIR;
240
+ fs::create_dir_all(ca_dir)?;
241
+
242
+ let key_path = ca_dir.join("itsi_dev_ca.key");
243
+ let cert_path = ca_dir.join("itsi_dev_ca.crt");
244
+
245
+ if key_path.exists() && cert_path.exists() {
246
+ // Already have a local CA
247
+ let key_pem = fs::read_to_string(&key_path)?;
248
+ let cert_pem = fs::read_to_string(&cert_path)?;
249
+
250
+ Ok((key_pem, cert_pem))
251
+ } else {
252
+ let subject_alt_names = vec!["dev.itsi.fyi".to_string(), "localhost".to_string()];
253
+
254
+ let CertifiedKey { cert, key_pair } =
255
+ generate_simple_self_signed(subject_alt_names).unwrap();
256
+
257
+ fs::write(&key_path, key_pair.serialize_pem())?;
258
+ fs::write(&cert_path, cert.pem())?;
259
+
260
+ Ok((key_pair.serialize_pem(), cert.pem()))
261
+ }
262
+ }
@@ -0,0 +1,91 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Itsi - Default</title>
6
+ <style>
7
+ * {
8
+ box-sizing: border-box;
9
+ margin: 0;
10
+ padding: 0;
11
+ }
12
+ body {
13
+ font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
14
+ background-color: #f4f4f4;
15
+ color: #333;
16
+ line-height: 1.6;
17
+ }
18
+ .container {
19
+ max-width: 700px;
20
+ margin: 3rem auto;
21
+ background: #fff;
22
+ border-radius: 8px;
23
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
24
+ padding: 2rem;
25
+ }
26
+ h1 {
27
+ font-size: 1.8rem;
28
+ margin-bottom: 1rem;
29
+ text-align: center;
30
+ color: #444;
31
+ }
32
+ p {
33
+ margin-bottom: 1rem;
34
+ text-align: center;
35
+ color: #666;
36
+ }
37
+ ul.fields {
38
+ list-style: none;
39
+ margin-top: 1.5rem;
40
+ padding: 0;
41
+ }
42
+ ul.fields li {
43
+ background: #fafafa;
44
+ border: 1px solid #eee;
45
+ border-radius: 5px;
46
+ padding: 0.75rem;
47
+ margin-bottom: 0.75rem;
48
+ display: flex;
49
+ justify-content: space-between;
50
+ align-items: center;
51
+ }
52
+ .label {
53
+ font-weight: bold;
54
+ margin-right: 1rem;
55
+ }
56
+ </style>
57
+ </head>
58
+ <body>
59
+ <div class="container">
60
+ <h1>You're running on Itsi!</h1>
61
+ <p>RACK environment:</p>
62
+
63
+ <ul class="fields">
64
+ <li>
65
+ <span class="label">REQUEST_METHOD:</span>
66
+ <span>%{REQUEST_METHOD}</span>
67
+ </li>
68
+ <li>
69
+ <span class="label">PATH_INFO:</span>
70
+ <span>%{PATH_INFO}</span>
71
+ </li>
72
+ <li>
73
+ <span class="label">SERVER_NAME:</span>
74
+ <span>%{SERVER_NAME}</span>
75
+ </li>
76
+ <li>
77
+ <span class="label">SERVER_PORT:</span>
78
+ <span>%{SERVER_PORT}</span>
79
+ </li>
80
+ <li>
81
+ <span class="label">REMOTE_ADDR:</span>
82
+ <span>%{REMOTE_ADDR}</span>
83
+ </li>
84
+ <li>
85
+ <span class="label">HTTP_USER_AGENT:</span>
86
+ <span>%{HTTP_USER_AGENT}</span>
87
+ </li>
88
+ </ul>
89
+ </div>
90
+ </body>
91
+ </html>
@@ -1,6 +1,6 @@
1
1
  if defined?(ActiveSupport::IsolatedExecutionState) && !ENV["ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL"]
2
2
  Itsi.log_info \
3
3
  "ActiveSupport Isolated Execution state detected. Automatically switching to :fiber mode. "\
4
- "Use ENV['ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL'] to disable this behavior"
4
+ "Set ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL to disable this behavior"
5
5
  ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
6
6
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Server
5
- VERSION = "0.1.6"
5
+ VERSION = "0.1.8"
6
6
  end
7
7
  end
@@ -6,6 +6,9 @@ require_relative "signals"
6
6
  require_relative "request"
7
7
  require_relative "stream_io"
8
8
  require_relative "server/rack/handler/itsi"
9
+ require 'erb'
10
+
11
+ DEFAULT_INDEX = IO.read(__dir__ + '/index.html.erb')
9
12
 
10
13
  module Itsi
11
14
  class Server
@@ -14,8 +17,25 @@ module Itsi
14
17
  @running ||= false
15
18
  end
16
19
 
17
- def self.start(app:, **opts)
18
- server = new(app: ->{app}, **opts)
20
+ def self.start(
21
+ app: ->(env){
22
+ [env['CONTENT_TYPE'], env['HTTP_ACCEPT']].include?('application/json') ?
23
+ [200, {"Content-Type" => "application/json"}, ["{\"message\": \"You're running on Itsi!\"}"]] :
24
+ [200, {"Content-Type" => "text/html"}, [
25
+ DEFAULT_INDEX % {
26
+ REQUEST_METHOD: env['REQUEST_METHOD'],
27
+ PATH_INFO: env['PATH_INFO'],
28
+ SERVER_NAME: env['SERVER_NAME'],
29
+ SERVER_PORT: env['SERVER_PORT'],
30
+ REMOTE_ADDR: env['REMOTE_ADDR'],
31
+ HTTP_USER_AGENT: env['HTTP_USER_AGENT']
32
+ }
33
+ ]]
34
+ },
35
+ binds: ['http://0.0.0.0:3000'],
36
+ **opts
37
+ )
38
+ server = new(app: ->{app}, binds: binds, **opts)
19
39
  @running = true
20
40
  Signal.trap('INT', 'DEFAULT')
21
41
  server.start
data/lib/itsi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Itsi
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.8"
3
3
  end
@@ -0,0 +1,237 @@
1
+ terraform {
2
+ required_providers {
3
+ aws = {
4
+ source = "hashicorp/aws"
5
+ version = "~> 5.0"
6
+ }
7
+ cloudflare = {
8
+ source = "cloudflare/cloudflare"
9
+ version = "~> 5.0.0"
10
+ }
11
+ }
12
+
13
+ required_version = ">= 0.14.9"
14
+ }
15
+
16
+ provider "aws" {
17
+ region = var.aws_region
18
+ }
19
+
20
+
21
+ data "aws_region" "current" {
22
+ name = var.aws_region
23
+ }
24
+
25
+ data "aws_ami" "ubuntu" {
26
+ most_recent = true
27
+
28
+ filter {
29
+ name = "name"
30
+ values = ["ubuntu/images/hvm-ssd-gp3/*ubuntu-noble-24.04-arm64-server-*"]
31
+ }
32
+
33
+ filter {
34
+ name = "virtualization-type"
35
+ values = ["hvm"]
36
+ }
37
+
38
+ owners = ["099720109477"] # Canonical
39
+ }
40
+
41
+ # Create VPC
42
+ # terraform aws create vpc
43
+ resource "aws_vpc" "vpc" {
44
+ cidr_block = "10.0.0.0/16"
45
+ instance_tenancy = "default"
46
+ enable_dns_hostnames = true
47
+ tags = {
48
+ Name = "${var.environment}-vpc"
49
+ }
50
+ }
51
+ resource "aws_subnet" "public_subnet_a" {
52
+ vpc_id = aws_vpc.vpc.id
53
+ cidr_block = "10.0.1.0/24"
54
+ availability_zone = var.subnet_az
55
+ map_public_ip_on_launch = true
56
+
57
+ tags = {
58
+ Name = "${var.environment} Public Subnet A"
59
+ }
60
+ }
61
+
62
+ resource "aws_subnet" "private_subnet_a" {
63
+ vpc_id = aws_vpc.vpc.id
64
+ cidr_block = "10.0.2.0/24"
65
+ availability_zone = var.subnet_az
66
+
67
+ tags = {
68
+ Name = "${var.environment} Private Subnet A"
69
+ }
70
+ }
71
+
72
+ resource "aws_internet_gateway" "ig_a" {
73
+ vpc_id = aws_vpc.vpc.id
74
+
75
+ tags = {
76
+ Name = "${var.environment} Internet Gateway A"
77
+ }
78
+ }
79
+
80
+ resource "aws_route_table" "public_rt" {
81
+ vpc_id = aws_vpc.vpc.id
82
+
83
+ route {
84
+ cidr_block = "0.0.0.0/0"
85
+ gateway_id = aws_internet_gateway.ig_a.id
86
+ }
87
+
88
+ route {
89
+ ipv6_cidr_block = "::/0"
90
+ gateway_id = aws_internet_gateway.ig_a.id
91
+ }
92
+
93
+ tags = {
94
+ Name = "${var.environment} Public Route Table"
95
+ }
96
+ }
97
+
98
+ resource "aws_route_table_association" "public_1_rt_a" {
99
+ subnet_id = aws_subnet.public_subnet_a.id
100
+ route_table_id = aws_route_table.public_rt.id
101
+ }
102
+
103
+ resource "aws_security_group" "web_sg" {
104
+ name = "HTTP and SSH"
105
+ vpc_id = aws_vpc.vpc.id
106
+
107
+ ingress {
108
+ from_port = 443
109
+ to_port = 443
110
+ protocol = "tcp"
111
+ cidr_blocks = ["0.0.0.0/0"]
112
+ }
113
+
114
+
115
+ ingress {
116
+ from_port = 80
117
+ to_port = 80
118
+ protocol = "tcp"
119
+ cidr_blocks = ["0.0.0.0/0"]
120
+ }
121
+
122
+ ingress {
123
+ from_port = 22
124
+ to_port = 22
125
+ protocol = "tcp"
126
+ cidr_blocks = ["0.0.0.0/0"]
127
+ }
128
+
129
+ egress {
130
+ from_port = 0
131
+ to_port = 0
132
+ protocol = -1
133
+ cidr_blocks = ["0.0.0.0/0"]
134
+ }
135
+
136
+ tags = {
137
+ Name = "${var.environment} Web Security Group"
138
+ }
139
+ }
140
+
141
+
142
+ resource "aws_instance" "web" {
143
+ ami = data.aws_ami.ubuntu.id
144
+ instance_type = "t4g.micro"
145
+ key_name = "key-pair-aws-admin"
146
+ iam_instance_profile = aws_iam_instance_profile.web.name
147
+
148
+ tags = {
149
+ Name = "web-${var.environment}"
150
+ }
151
+
152
+ subnet_id = aws_subnet.public_subnet_a.id
153
+ security_groups = [aws_security_group.web_sg.id]
154
+ associate_public_ip_address = true
155
+
156
+ user_data = <<EOF
157
+ #!/bin/bash
158
+ apt-get update
159
+ apt-get install zlib1g-dev libyaml-dev libssl-dev libffi-dev libgmp3-dev libclang-dev build-essential -y && \
160
+ apt-get clean && rm -rf /var/lib/apt/lists/* && apt-get autoremove -y
161
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
162
+ curl https://mise.run | sh
163
+ echo "eval \"\$(/root/.local/bin/mise activate bash)\"" >> ~/.bashrc
164
+ eval "$(/root/.local/bin/mise activate bash)"
165
+ mise use ruby@3.4.2
166
+ gem install itsi
167
+ EOF
168
+
169
+ root_block_device {
170
+ encrypted = true
171
+ volume_type = "gp3"
172
+ volume_size = 12
173
+ tags = {
174
+ Name = "web-root-block-device-${var.environment}"
175
+ }
176
+ }
177
+
178
+ depends_on = [aws_route_table_association.public_1_rt_a]
179
+ }
180
+
181
+ locals {
182
+ role_policy_arns = [
183
+ "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM",
184
+ "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
185
+ ]
186
+ }
187
+
188
+ resource "aws_iam_instance_profile" "web" {
189
+ name = "EC2-Profile-${var.environment}"
190
+ role = aws_iam_role.web.name
191
+ }
192
+
193
+ resource "aws_iam_role_policy_attachment" "web" {
194
+ count = length(local.role_policy_arns)
195
+
196
+ role = aws_iam_role.web.name
197
+ policy_arn = element(local.role_policy_arns, count.index)
198
+ }
199
+
200
+ resource "aws_iam_role_policy" "web" {
201
+ name = "EC2-Inline-Policy-${var.environment}"
202
+ role = aws_iam_role.web.id
203
+ policy = jsonencode(
204
+ {
205
+ "Version" : "2012-10-17",
206
+ "Statement" : [
207
+ {
208
+ "Effect" : "Allow",
209
+ "Action" : [
210
+ "ssm:GetParameter"
211
+ ],
212
+ "Resource" : "*"
213
+ }
214
+ ]
215
+ }
216
+ )
217
+ }
218
+
219
+ resource "aws_iam_role" "web" {
220
+ name = "EC2-Role-${var.environment}"
221
+ path = "/"
222
+
223
+ assume_role_policy = jsonencode(
224
+ {
225
+ "Version" : "2012-10-17",
226
+ "Statement" : [
227
+ {
228
+ "Action" : "sts:AssumeRole",
229
+ "Principal" : {
230
+ "Service" : "ec2.amazonaws.com"
231
+ },
232
+ "Effect" : "Allow"
233
+ }
234
+ ]
235
+ }
236
+ )
237
+ }
@@ -0,0 +1,4 @@
1
+ output "ec2_public_ip" {
2
+ description = "Public IP of the EC2 instance"
3
+ value = aws_instance.web.public_ip
4
+ }
@@ -0,0 +1,11 @@
1
+ variable "aws_region" {
2
+ default = "ap-southeast-2"
3
+ }
4
+
5
+ variable "environment" {
6
+ default = "itsi-production"
7
+ }
8
+
9
+ variable "subnet_az" {
10
+ default = "ap-southeast-2a"
11
+ }
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'iodine'
4
+ gem 'unicorn'
5
+ gem 'puma'
6
+ gem 'passenger'
7
+ gem 'agoo'
8
+ gem 'falcon'
9
+ gem "itsi-server", path: "../../gems/server"
10
+ gem "itsi-scheduler", path: "../../gems/scheduler"