itsi-server 0.2.2 → 0.2.3
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 +28 -29
- data/ext/itsi_scheduler/Cargo.toml +1 -1
- data/ext/itsi_server/Cargo.toml +1 -1
- data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +26 -3
- data/lib/itsi/http_request.rb +31 -34
- data/lib/itsi/http_response.rb +10 -8
- data/lib/itsi/passfile.rb +6 -6
- data/lib/itsi/server/config/config_helpers.rb +33 -33
- data/lib/itsi/server/config/dsl.rb +14 -19
- data/lib/itsi/server/config/known_paths.rb +11 -7
- data/lib/itsi/server/config/middleware/error_response.md +13 -0
- data/lib/itsi/server/config/middleware/static_assets.md +40 -0
- data/lib/itsi/server/config/option.rb +0 -1
- data/lib/itsi/server/config/options/nodelay.md +2 -2
- data/lib/itsi/server/config/options/reuse_address.md +1 -1
- data/lib/itsi/server/config/typed_struct.rb +32 -35
- data/lib/itsi/server/config.rb +107 -92
- data/lib/itsi/server/default_app/default_app.rb +1 -1
- data/lib/itsi/server/grpc/grpc_call.rb +4 -5
- data/lib/itsi/server/grpc/grpc_interface.rb +6 -7
- data/lib/itsi/server/rack/handler/itsi.rb +0 -1
- data/lib/itsi/server/rack_interface.rb +0 -1
- data/lib/itsi/server/route_tester.rb +25 -23
- data/lib/itsi/server/typed_handlers/source_parser.rb +9 -7
- data/lib/itsi/server/version.rb +1 -1
- data/lib/itsi/server.rb +21 -21
- data/lib/itsi/standard_headers.rb +80 -80
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28ba76ce129635022bb442e61f18dac9c6d29d7552b7b2e006ec16b8c5ef975a
|
4
|
+
data.tar.gz: 944d5bfee24014c8aab5bffede13f73d6316023dcda9df7cbaf7e6fb442f8d9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 658829fb38833abdd60bbb175f552faddfa26692598626a25a546845bcbe4f1b6478f268b2917c6ef08b5ebf86e93c3bace063ba0594e2a774dca3810d616ce4
|
7
|
+
data.tar.gz: 9089b2a6067e148a8893f8e12e07e9e7fa1e3625b6a8940d3bf4fbae3aa81d3b10ab538250c8a15bdca084d0a603480554bb1663b73deccfc68c6deaba560205
|
data/Cargo.lock
CHANGED
@@ -117,9 +117,9 @@ dependencies = [
|
|
117
117
|
|
118
118
|
[[package]]
|
119
119
|
name = "anyhow"
|
120
|
-
version = "1.0.
|
120
|
+
version = "1.0.98"
|
121
121
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
122
|
-
checksum = "
|
122
|
+
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
123
123
|
|
124
124
|
[[package]]
|
125
125
|
name = "arc-swap"
|
@@ -253,9 +253,9 @@ dependencies = [
|
|
253
253
|
|
254
254
|
[[package]]
|
255
255
|
name = "aws-lc-sys"
|
256
|
-
version = "0.28.
|
256
|
+
version = "0.28.2"
|
257
257
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
258
|
-
checksum = "
|
258
|
+
checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1"
|
259
259
|
dependencies = [
|
260
260
|
"bindgen",
|
261
261
|
"cc",
|
@@ -467,9 +467,9 @@ dependencies = [
|
|
467
467
|
|
468
468
|
[[package]]
|
469
469
|
name = "brotli-decompressor"
|
470
|
-
version = "4.0.
|
470
|
+
version = "4.0.3"
|
471
471
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
472
|
-
checksum = "
|
472
|
+
checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
|
473
473
|
dependencies = [
|
474
474
|
"alloc-no-stdlib",
|
475
475
|
"alloc-stdlib",
|
@@ -587,9 +587,9 @@ dependencies = [
|
|
587
587
|
|
588
588
|
[[package]]
|
589
589
|
name = "clap"
|
590
|
-
version = "4.5.
|
590
|
+
version = "4.5.37"
|
591
591
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
592
|
-
checksum = "
|
592
|
+
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
593
593
|
dependencies = [
|
594
594
|
"clap_builder",
|
595
595
|
"clap_derive",
|
@@ -597,9 +597,9 @@ dependencies = [
|
|
597
597
|
|
598
598
|
[[package]]
|
599
599
|
name = "clap_builder"
|
600
|
-
version = "4.5.
|
600
|
+
version = "4.5.37"
|
601
601
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
602
|
-
checksum = "
|
602
|
+
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
603
603
|
dependencies = [
|
604
604
|
"anstream",
|
605
605
|
"anstyle",
|
@@ -764,9 +764,9 @@ dependencies = [
|
|
764
764
|
|
765
765
|
[[package]]
|
766
766
|
name = "data-encoding"
|
767
|
-
version = "2.
|
767
|
+
version = "2.9.0"
|
768
768
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
769
|
-
checksum = "
|
769
|
+
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
|
770
770
|
|
771
771
|
[[package]]
|
772
772
|
name = "der-parser"
|
@@ -1176,9 +1176,9 @@ dependencies = [
|
|
1176
1176
|
|
1177
1177
|
[[package]]
|
1178
1178
|
name = "h2"
|
1179
|
-
version = "0.4.
|
1179
|
+
version = "0.4.9"
|
1180
1180
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1181
|
-
checksum = "
|
1181
|
+
checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
|
1182
1182
|
dependencies = [
|
1183
1183
|
"atomic-waker",
|
1184
1184
|
"bytes",
|
@@ -1363,7 +1363,7 @@ dependencies = [
|
|
1363
1363
|
"bytes",
|
1364
1364
|
"futures-channel",
|
1365
1365
|
"futures-util",
|
1366
|
-
"h2 0.4.
|
1366
|
+
"h2 0.4.9",
|
1367
1367
|
"http 1.3.1",
|
1368
1368
|
"http-body 1.0.1",
|
1369
1369
|
"httparse",
|
@@ -1644,7 +1644,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|
1644
1644
|
|
1645
1645
|
[[package]]
|
1646
1646
|
name = "itsi-server"
|
1647
|
-
version = "0.2.
|
1647
|
+
version = "0.2.3"
|
1648
1648
|
dependencies = [
|
1649
1649
|
"argon2",
|
1650
1650
|
"async-channel",
|
@@ -1681,7 +1681,7 @@ dependencies = [
|
|
1681
1681
|
"parking_lot",
|
1682
1682
|
"percent-encoding",
|
1683
1683
|
"pin-project",
|
1684
|
-
"rand 0.9.
|
1684
|
+
"rand 0.9.1",
|
1685
1685
|
"rcgen",
|
1686
1686
|
"redis",
|
1687
1687
|
"regex",
|
@@ -1713,7 +1713,7 @@ dependencies = [
|
|
1713
1713
|
"axum-server",
|
1714
1714
|
"base64 0.22.1",
|
1715
1715
|
"chrono",
|
1716
|
-
"clap 4.5.
|
1716
|
+
"clap 4.5.37",
|
1717
1717
|
"futures",
|
1718
1718
|
"log",
|
1719
1719
|
"num-bigint",
|
@@ -1841,9 +1841,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|
1841
1841
|
|
1842
1842
|
[[package]]
|
1843
1843
|
name = "libc"
|
1844
|
-
version = "0.2.
|
1844
|
+
version = "0.2.172"
|
1845
1845
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1846
|
-
checksum = "
|
1846
|
+
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
1847
1847
|
|
1848
1848
|
[[package]]
|
1849
1849
|
name = "libloading"
|
@@ -1852,7 +1852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1852
1852
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
1853
1853
|
dependencies = [
|
1854
1854
|
"cfg-if",
|
1855
|
-
"windows-targets 0.
|
1855
|
+
"windows-targets 0.48.5",
|
1856
1856
|
]
|
1857
1857
|
|
1858
1858
|
[[package]]
|
@@ -2366,9 +2366,9 @@ dependencies = [
|
|
2366
2366
|
|
2367
2367
|
[[package]]
|
2368
2368
|
name = "proc-macro2"
|
2369
|
-
version = "1.0.
|
2369
|
+
version = "1.0.95"
|
2370
2370
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
2371
|
-
checksum = "
|
2371
|
+
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
2372
2372
|
dependencies = [
|
2373
2373
|
"unicode-ident",
|
2374
2374
|
]
|
@@ -2401,7 +2401,7 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
|
|
2401
2401
|
dependencies = [
|
2402
2402
|
"bytes",
|
2403
2403
|
"getrandom 0.3.2",
|
2404
|
-
"rand 0.9.
|
2404
|
+
"rand 0.9.1",
|
2405
2405
|
"ring",
|
2406
2406
|
"rustc-hash 2.1.1",
|
2407
2407
|
"rustls",
|
@@ -2466,13 +2466,12 @@ dependencies = [
|
|
2466
2466
|
|
2467
2467
|
[[package]]
|
2468
2468
|
name = "rand"
|
2469
|
-
version = "0.9.
|
2469
|
+
version = "0.9.1"
|
2470
2470
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
2471
|
-
checksum = "
|
2471
|
+
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
2472
2472
|
dependencies = [
|
2473
2473
|
"rand_chacha 0.9.0",
|
2474
2474
|
"rand_core 0.9.3",
|
2475
|
-
"zerocopy",
|
2476
2475
|
]
|
2477
2476
|
|
2478
2477
|
[[package]]
|
@@ -3062,9 +3061,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
3062
3061
|
|
3063
3062
|
[[package]]
|
3064
3063
|
name = "signal-hook-registry"
|
3065
|
-
version = "1.4.
|
3064
|
+
version = "1.4.5"
|
3066
3065
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
3067
|
-
checksum = "
|
3066
|
+
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
3068
3067
|
dependencies = [
|
3069
3068
|
"libc",
|
3070
3069
|
]
|
data/ext/itsi_server/Cargo.toml
CHANGED
@@ -14,7 +14,7 @@ use magnus::{
|
|
14
14
|
block::Proc,
|
15
15
|
error::Result,
|
16
16
|
value::{LazyId, ReprValue},
|
17
|
-
RArray, RHash, Ruby, Symbol, Value,
|
17
|
+
RArray, RHash, Ruby, Symbol, TryConvert, Value,
|
18
18
|
};
|
19
19
|
use nix::{
|
20
20
|
fcntl::{fcntl, FcntlArg, FdFlag},
|
@@ -124,9 +124,17 @@ impl ServerParams {
|
|
124
124
|
debug!("Loading Itsi Scheduler");
|
125
125
|
ruby.require("itsi/scheduler")?;
|
126
126
|
}
|
127
|
-
let
|
127
|
+
let result_pair = self
|
128
128
|
.middleware_loader
|
129
|
-
.call::<
|
129
|
+
.call::<(), RArray>(())
|
130
|
+
.inspect_err(|e| {
|
131
|
+
eprintln!("Error loading middleware: {:?}", e);
|
132
|
+
if let Some(err_value) = e.value() {
|
133
|
+
print_rb_backtrace(err_value);
|
134
|
+
}
|
135
|
+
})?;
|
136
|
+
let routes_raw = result_pair
|
137
|
+
.entry::<Option<Value>>(0)
|
130
138
|
.inspect_err(|e| {
|
131
139
|
eprintln!("Error loading middleware: {:?}", e);
|
132
140
|
if let Some(err_value) = e.value() {
|
@@ -134,6 +142,21 @@ impl ServerParams {
|
|
134
142
|
}
|
135
143
|
})?
|
136
144
|
.map(|mw| mw.into());
|
145
|
+
let error_lines = result_pair.entry::<Option<RArray>>(1).inspect_err(|e| {
|
146
|
+
eprintln!("Error loading middleware: {:?}", e);
|
147
|
+
if let Some(err_value) = e.value() {
|
148
|
+
print_rb_backtrace(err_value);
|
149
|
+
}
|
150
|
+
})?;
|
151
|
+
if error_lines.is_some_and(|r| !r.is_empty()) {
|
152
|
+
let errors: Vec<String> =
|
153
|
+
Vec::<String>::try_convert(error_lines.unwrap().as_value())?;
|
154
|
+
ItsiServerConfig::print_config_errors(errors);
|
155
|
+
return Err(magnus::Error::new(
|
156
|
+
magnus::exception::runtime_error(),
|
157
|
+
"Failed to set middleware",
|
158
|
+
));
|
159
|
+
}
|
137
160
|
let middleware = MiddlewareSet::new(routes_raw)?;
|
138
161
|
self.middleware.set(middleware).map_err(|_| {
|
139
162
|
magnus::Error::new(
|
data/lib/itsi/http_request.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require "stringio"
|
4
4
|
require "socket"
|
5
5
|
require "uri"
|
6
|
-
require_relative
|
6
|
+
require_relative "http_request/response_status_shortcodes"
|
7
7
|
|
8
8
|
module Itsi
|
9
9
|
class HttpRequest
|
@@ -22,7 +22,7 @@ module Itsi
|
|
22
22
|
end
|
23
23
|
[header, rack_form]
|
24
24
|
end.to_h.tap do |hm|
|
25
|
-
hm.default_proc = proc { |
|
25
|
+
hm.default_proc = proc { |_, key| "HTTP_#{key.upcase.gsub(/-/, "_")}" }
|
26
26
|
end
|
27
27
|
|
28
28
|
def to_rack_env
|
@@ -78,7 +78,7 @@ module Itsi
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def respond(
|
81
|
-
_body = nil, _status = 200, _headers = nil,
|
81
|
+
_body = nil, _status = 200, _headers = nil, # rubocop:disable Lint/UnderscorePrefixedVariableName
|
82
82
|
json: nil,
|
83
83
|
html: nil,
|
84
84
|
text: nil,
|
@@ -90,13 +90,12 @@ module Itsi
|
|
90
90
|
body: _body,
|
91
91
|
&blk
|
92
92
|
)
|
93
|
-
|
94
93
|
if json
|
95
94
|
if as
|
96
95
|
begin
|
97
96
|
validate!(json, as: as)
|
98
97
|
rescue ValidationError => e
|
99
|
-
json = {type:
|
98
|
+
json = { type: "error", message: "Validation Error: #{e.message}" }
|
100
99
|
status = 400
|
101
100
|
end
|
102
101
|
end
|
@@ -118,15 +117,13 @@ module Itsi
|
|
118
117
|
end
|
119
118
|
|
120
119
|
response.respond(status: status, headers: headers, body: body, hijack: hijack, &blk)
|
121
|
-
|
122
|
-
|
123
120
|
end
|
124
121
|
|
125
122
|
def hijack
|
126
123
|
self.hijacked = true
|
127
124
|
UNIXSocket.pair.yield_self do |(server_sock, app_sock)|
|
128
125
|
server_sock.autoclose = false
|
129
|
-
|
126
|
+
response.hijack(server_sock.fileno)
|
130
127
|
server_sock.sync = true
|
131
128
|
app_sock.sync = true
|
132
129
|
app_sock
|
@@ -150,37 +147,37 @@ module Itsi
|
|
150
147
|
as ? apply_schema!(params, as) : params
|
151
148
|
end
|
152
149
|
|
153
|
-
def params(schema=nil)
|
154
|
-
params =
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
150
|
+
def params(schema = nil)
|
151
|
+
params = if url_encoded?
|
152
|
+
URI.decode_www_form(build_input_io.read).to_h
|
153
|
+
elsif json?
|
154
|
+
JSON.parse(build_input_io.read)
|
155
|
+
elsif multipart?
|
156
|
+
Rack::Multipart::Parser.parse(
|
157
|
+
build_input_io,
|
158
|
+
content_length,
|
159
|
+
content_type,
|
160
|
+
Rack::Multipart::Parser::TEMPFILE_FACTORY,
|
161
|
+
Rack::Multipart::Parser::BUFSIZE,
|
162
|
+
Rack::Utils.default_query_parser
|
163
|
+
).params
|
164
|
+
else
|
165
|
+
{}
|
166
|
+
end
|
169
167
|
|
170
168
|
params.merge!(query_params).merge!(url_params)
|
171
169
|
validated = schema ? apply_schema!(params, schema) : params
|
172
|
-
|
173
|
-
if multipart?
|
174
|
-
raise "#params must take a block for multipart requests"
|
175
|
-
else
|
176
|
-
return validated
|
177
|
-
end
|
178
|
-
else
|
170
|
+
if block_given?
|
179
171
|
yield validated
|
172
|
+
else
|
173
|
+
raise "#params must take a block for multipart requests" if multipart?
|
174
|
+
|
175
|
+
validated
|
176
|
+
|
180
177
|
end
|
181
178
|
rescue ValidationError => e
|
182
179
|
if response.json?
|
183
|
-
respond(json: {error: e.message}, status: 400)
|
180
|
+
respond(json: { error: e.message }, status: 400)
|
184
181
|
else
|
185
182
|
respond(e.message, 400)
|
186
183
|
end
|
@@ -191,7 +188,7 @@ module Itsi
|
|
191
188
|
# Unexpected error.
|
192
189
|
# Don't reveal potential sensitive information to client.
|
193
190
|
if response.json?
|
194
|
-
respond(json: {error: "Internal Server Error"}, status: 500)
|
191
|
+
respond(json: { error: "Internal Server Error" }, status: 500)
|
195
192
|
else
|
196
193
|
respond("Internal Server Error", 500)
|
197
194
|
end
|
@@ -205,7 +202,7 @@ module Itsi
|
|
205
202
|
if params.key?(:tempfile)
|
206
203
|
params[:tempfile].unlink
|
207
204
|
else
|
208
|
-
|
205
|
+
params.each_value { |v| clean_temp_files(v) }
|
209
206
|
end
|
210
207
|
when Array then params.each { |v| clean_temp_files(v) }
|
211
208
|
end
|
data/lib/itsi/http_response.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "forwardable"
|
3
4
|
require "stringio"
|
4
5
|
require "socket"
|
5
6
|
|
6
7
|
module Itsi
|
7
|
-
|
8
8
|
class HttpResponse
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def respond(
|
10
|
+
_body = nil, _status = 200, _header = nil, # rubocop:disable Lint/UnderscorePrefixedVariableName
|
11
|
+
status: _status, headers: _header, body: _body,
|
12
|
+
hijack: false
|
13
|
+
)
|
14
|
+
self.status = status.is_a?(Symbol) ? HTTP_STATUS_NAME_TO_CODE_MAP.fetch(status) : status.to_i
|
13
15
|
|
14
16
|
body = body.to_s unless body.is_a?(String)
|
15
17
|
|
@@ -33,9 +35,9 @@ module Itsi
|
|
33
35
|
|
34
36
|
# If you hijack the connection, you are responsible for closing it.
|
35
37
|
# Otherwise, the response will be closed automatically.
|
36
|
-
|
38
|
+
close unless hijack
|
37
39
|
else
|
38
|
-
|
40
|
+
close
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
data/lib/itsi/passfile.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
module Itsi
|
2
2
|
class Server
|
3
|
-
|
4
3
|
module Passfile
|
5
|
-
require
|
4
|
+
require "io/console"
|
6
5
|
|
7
6
|
module_function
|
8
7
|
|
@@ -18,7 +17,7 @@ module Itsi
|
|
18
17
|
line.chomp!
|
19
18
|
next if line.empty?
|
20
19
|
|
21
|
-
user, pass = line.split(
|
20
|
+
user, pass = line.split(":", 2)
|
22
21
|
creds[user] = pass
|
23
22
|
end
|
24
23
|
end
|
@@ -26,14 +25,14 @@ module Itsi
|
|
26
25
|
end
|
27
26
|
|
28
27
|
def save(creds, filename)
|
29
|
-
File.open(filename,
|
28
|
+
File.open(filename, "w", 0o600) do |f|
|
30
29
|
creds.each do |u, p|
|
31
30
|
f.puts "#{u}:#{p}"
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
36
|
-
def echo(
|
35
|
+
def echo(_, algorithm)
|
37
36
|
print "Enter username: "
|
38
37
|
username = $stdin.gets.chomp
|
39
38
|
|
@@ -56,6 +55,7 @@ module Itsi
|
|
56
55
|
|
57
56
|
def add(filename, algorithm)
|
58
57
|
return unless (creds = load(filename))
|
58
|
+
|
59
59
|
print "Enter username: "
|
60
60
|
username = $stdin.gets.chomp
|
61
61
|
|
@@ -98,11 +98,11 @@ module Itsi
|
|
98
98
|
def list(filename)
|
99
99
|
puts "Current credentials in '#{filename}':"
|
100
100
|
return unless (creds = load(filename))
|
101
|
+
|
101
102
|
creds.each do |u, p|
|
102
103
|
puts "#{u}:#{p}"
|
103
104
|
end
|
104
105
|
end
|
105
|
-
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
@@ -2,7 +2,6 @@ module Itsi
|
|
2
2
|
class Server
|
3
3
|
module Config
|
4
4
|
module ConfigHelpers
|
5
|
-
|
6
5
|
def self.load_and_register(klass)
|
7
6
|
config_type = klass.name.split("::").last.downcase.gsub(/([a-z]()[A-Z])/, '\1_\2')
|
8
7
|
|
@@ -17,35 +16,35 @@ module Itsi
|
|
17
16
|
following = klass.subclasses
|
18
17
|
new_class = (following - current).first
|
19
18
|
|
20
|
-
documentation_file = "#{file[/(.*)\.rb/,1]}.md"
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
.gsub(/^\{\{[^\}]+\}\}/, "") # Strip Hugo blocks
|
29
|
-
end
|
19
|
+
documentation_file = "#{file[/(.*)\.rb/, 1]}.md"
|
20
|
+
documentation_file = "#{file[%r{(.*)/[^/]+\.rb}, 1]}/_index.md" unless File.exist?(documentation_file)
|
21
|
+
next unless File.exist?(documentation_file) && new_class
|
22
|
+
|
23
|
+
new_class.documentation IO.read(documentation_file)
|
24
|
+
.gsub(/^---.*?\n.*?-+/m, "") # Strip frontmatter
|
25
|
+
.gsub(/^(```.*?)\{.*?\}.*$/, "\\1") # Strip filename from code blocks
|
26
|
+
.gsub(/^\{\{[^}]+\}\}/, "") # Strip Hugo blocks
|
30
27
|
end
|
31
28
|
end
|
32
29
|
|
33
|
-
def normalize_keys!(hash, expected=[])
|
30
|
+
def normalize_keys!(hash, expected = [])
|
34
31
|
hash.keys.each do |key|
|
35
32
|
value = hash.delete(key)
|
36
33
|
key = key.to_s.downcase.to_sym
|
37
34
|
hash[key] = value
|
38
35
|
raise "Unexpected key: #{key}" unless expected.include?(key)
|
36
|
+
|
39
37
|
expected -= [key]
|
40
38
|
end
|
41
|
-
raise "Missing required keys: #{expected.join(
|
39
|
+
raise "Missing required keys: #{expected.join(", ")}" unless expected.empty?
|
40
|
+
|
42
41
|
hash
|
43
42
|
end
|
44
43
|
|
45
|
-
def self.included(cls)
|
46
|
-
def cls.inherited(base)
|
44
|
+
def self.included(cls) # rubocop:disable Metrics/PerceivedComplexity,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
45
|
+
def cls.inherited(base) # rubocop:disable Metrics/MethodLength,Lint/MissingSuper,Metrics/PerceivedComplexity
|
47
46
|
%i[detail documentation insert_text schema].each do |attr|
|
48
|
-
base.define_singleton_method(attr) do |value=nil|
|
47
|
+
base.define_singleton_method(attr) do |value = nil|
|
49
48
|
@middleware_class_attrs ||= {}
|
50
49
|
if value
|
51
50
|
@middleware_class_attrs[attr] = value
|
@@ -54,12 +53,12 @@ module Itsi
|
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
57
|
-
base.define_method(attr) do |
|
56
|
+
base.define_method(attr) do |_value = nil|
|
58
57
|
self.class.send(attr)
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
62
|
-
def base.schema(value=nil, &blk)
|
61
|
+
def base.schema(value = nil, &blk)
|
63
62
|
@middleware_class_attrs ||= {}
|
64
63
|
if blk
|
65
64
|
@middleware_class_attrs[:schema] = TypedStruct.new(&blk)
|
@@ -75,29 +74,30 @@ module Itsi
|
|
75
74
|
|
76
75
|
config_type = cls.name.split("::").last.downcase
|
77
76
|
|
78
|
-
cls.define_singleton_method("#{config_type}_name") do |name=self.name|
|
77
|
+
cls.define_singleton_method("#{config_type}_name") do |name = self.name|
|
79
78
|
@config_name ||= name.split("::").last.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
|
80
79
|
end
|
81
|
-
cls.define_method(:opt_name){ self.class.send("#{config_type}_name") }
|
82
|
-
cls.define_method(:location){ @location }
|
80
|
+
cls.define_method(:opt_name) { self.class.send("#{config_type}_name") }
|
81
|
+
cls.define_method(:location) { @location }
|
83
82
|
end
|
84
83
|
|
85
|
-
def initialize(location, params={})
|
84
|
+
def initialize(location, params = {})
|
86
85
|
if !self.class.ancestors.include?(Middleware) && !location.parent.nil?
|
87
86
|
raise "#{opt_name} must be set at the top level"
|
88
87
|
end
|
88
|
+
|
89
89
|
@location = location
|
90
|
-
@params = case
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
90
|
+
@params = case schema
|
91
|
+
when TypedStruct::Validation
|
92
|
+
schema.validate!(params)
|
93
|
+
when Array
|
94
|
+
default, validation = schema
|
95
|
+
params ? validation.validate!(params) : default
|
96
|
+
when nil
|
97
|
+
nil
|
98
|
+
else
|
99
|
+
schema.new(params).to_h
|
100
|
+
end
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|