echspec 0.0.3 → 0.0.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/.ruby-version +1 -1
- data/README.md +42 -12
- data/Rakefile +0 -41
- data/docs/echspec-demo.png +0 -0
- data/exe/echspec +1 -1
- data/lib/echspec/cli/gen_configs.rb +69 -0
- data/lib/echspec/cli/run.rb +111 -0
- data/lib/echspec/cli.rb +21 -84
- data/lib/echspec/utils.rb +4 -0
- data/lib/echspec/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bce9c266ff5ece6660c7adab52de934378be099778a00520e5f758acf3052aae
|
|
4
|
+
data.tar.gz: 5675044be1620e08f228fbb3b8067ababb0764522b462456d7c3534cf974c2a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 91cb45ce9eb4672aa3c8352f21969d1cc442cce7cf4ef924e9fd9c038a9b1e29e43880428a7b6539c16eb4a6eda4527ac1b3052b85e69466f710a24e0df1517b
|
|
7
|
+
data.tar.gz: 5fed5c9dc669ad9ea2766097e1f473cbb8bc834d0f8ce5be81cd81428f6b914d5b25b55b10744e77824f03b96c5fc4b0d0dd734148dcdb8fe03b732fa95c97bc
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.0.
|
|
1
|
+
4.0.2
|
data/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
|
-
The gem is available at [rubygems.org](https://rubygems.org/gems/echspec). You can install it the following:
|
|
16
|
+
The gem is available at [rubygems.org](https://rubygems.org/gems/echspec). You can install it with the following:
|
|
17
17
|
|
|
18
18
|
```sh-session
|
|
19
19
|
$ gem install echspec
|
|
@@ -24,7 +24,22 @@ $ gem install echspec
|
|
|
24
24
|
|
|
25
25
|
```sh-session
|
|
26
26
|
$ echspec --help
|
|
27
|
-
Usage: echspec
|
|
27
|
+
Usage: echspec {SUBCOMMAND}
|
|
28
|
+
|
|
29
|
+
Available subcommands: run, gen_configs, version, help.
|
|
30
|
+
```
|
|
31
|
+
```sh-session
|
|
32
|
+
$ echspec run --help
|
|
33
|
+
Usage: echspec run [OPTIONS...] {HOSTNAME}
|
|
34
|
+
|
|
35
|
+
Run ECH conformance tests for a server.
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
|
|
39
|
+
$ echspec run localhost
|
|
40
|
+
$ echspec run -f echconfigs.pem -p 4433 localhost
|
|
41
|
+
|
|
42
|
+
Options:
|
|
28
43
|
-f, --file FILE path to ECHConfigs PEM file (default resolve ECHConfigs via DNS)
|
|
29
44
|
-p, --port VALUE server port number (default 443)
|
|
30
45
|
-n, --not-force-compliant-hpke not force compliant ECHConfig HPKE cipher suite
|
|
@@ -32,10 +47,10 @@ Usage: echspec [OPTIONS] <HOSTNAME>
|
|
|
32
47
|
-s, --sections SECTIONS sections to test; by the default, test all sections
|
|
33
48
|
```
|
|
34
49
|
|
|
35
|
-
|
|
50
|
+
Example output:
|
|
36
51
|
|
|
37
52
|
```sh-session
|
|
38
|
-
$ echspec research.cloudflare.com
|
|
53
|
+
$ echspec run research.cloudflare.com
|
|
39
54
|
TLS Encrypted Client Hello Server
|
|
40
55
|
✔ MUST implement the following HPKE cipher suite: KEM: DHKEM(X25519, HKDF-SHA256), KDF: HKDF-SHA256 and AEAD: AES-128-GCM. [9]
|
|
41
56
|
✔ MUST abort with an "illegal_parameter" alert, if EncodedClientHelloInner is padded with non-zero values. [5.1-9]
|
|
@@ -60,13 +75,13 @@ Failures:
|
|
|
60
75
|
1 failure
|
|
61
76
|
```
|
|
62
77
|
|
|
63
|
-
By default, `echspec` retrieves ECHConfigs via HTTPS records.
|
|
78
|
+
By default, `echspec` retrieves ECHConfigs via DNS HTTPS records. You can specify a local PEM file using the `-f, --file FILE` option. To test a server on localhost:
|
|
64
79
|
|
|
65
80
|
```sh-session
|
|
66
|
-
$ echspec -f fixtures/echconfigs.pem -p 4433 localhost
|
|
81
|
+
$ echspec run -f fixtures/echconfigs.pem -p 4433 localhost
|
|
67
82
|
```
|
|
68
83
|
|
|
69
|
-
By default, `echspec`
|
|
84
|
+
By default, `echspec` enforces the following mandatory HPKE cipher suite:
|
|
70
85
|
|
|
71
86
|
- KEM
|
|
72
87
|
- DHKEM(X25519, HKDF-SHA256)
|
|
@@ -75,16 +90,16 @@ By default, `echspec` uses the following HPKE cipher suite
|
|
|
75
90
|
- AEAD
|
|
76
91
|
- AES-128-GCM
|
|
77
92
|
|
|
78
|
-
|
|
93
|
+
Use the `-n` or `--not-force-compliant-hpke` option to disable this enforcement and use the cipher suite provided in the ECHConfig.
|
|
79
94
|
|
|
80
95
|
```sh-session
|
|
81
|
-
$ echspec -f fixtures/echconfigs.pem -p 4433 -n localhost
|
|
96
|
+
$ echspec run -f fixtures/echconfigs.pem -p 4433 -n localhost
|
|
82
97
|
```
|
|
83
98
|
|
|
84
|
-
|
|
99
|
+
To run only specific test SECTIONS, use the `-s` option:
|
|
85
100
|
|
|
86
101
|
```sh-session
|
|
87
|
-
$ echspec -f fixtures/echconfigs.pem -p 4433 -n -s 7.1.1-2,7.1.1-5 localhost
|
|
102
|
+
$ echspec run -f fixtures/echconfigs.pem -p 4433 -n -s 7.1.1-2,7.1.1-5 localhost
|
|
88
103
|
TLS Encrypted Client Hello Server
|
|
89
104
|
✔ MUST abort with a "missing_extension" alert, if 2nd ClientHelloOuter does not contains the "encrypted_client_hello" extension. [7.1.1-2]
|
|
90
105
|
✔ MUST abort with an "illegal_parameter" alert, if 2nd ClientHelloOuter "encrypted_client_hello" enc is empty. [7.1.1-2]
|
|
@@ -94,7 +109,7 @@ TLS Encrypted Client Hello Server
|
|
|
94
109
|
Using the `-v` or `--verbose` option provides a message stack if an error occurs. The message stack is formatted as JSON.
|
|
95
110
|
|
|
96
111
|
```sh-session
|
|
97
|
-
$ echspec -s 7-5 -v research.cloudflare.com 2>&1 > /dev/null | jq .
|
|
112
|
+
$ echspec run -s 7-5 -v research.cloudflare.com 2>&1 > /dev/null | jq .
|
|
98
113
|
````
|
|
99
114
|
|
|
100
115
|
<details>
|
|
@@ -267,6 +282,21 @@ $ echspec -s 7-5 -v research.cloudflare.com 2>&1 > /dev/null | jq .
|
|
|
267
282
|
|
|
268
283
|
</details>
|
|
269
284
|
|
|
285
|
+
You can generate an ECHConfig PEM file the following:
|
|
286
|
+
|
|
287
|
+
```sh-session
|
|
288
|
+
$ echspec gen_configs echconfigs.pem
|
|
289
|
+
```
|
|
290
|
+
```
|
|
291
|
+
-----BEGIN PRIVATE KEY-----
|
|
292
|
+
MC4CAQAwBQYDK2VuBCIEICjd4yGRdsoP9gU7YT7My8DHx1Tjme8GYDXrOMCi8v1V
|
|
293
|
+
-----END PRIVATE KEY-----
|
|
294
|
+
-----BEGIN ECHCONFIG-----
|
|
295
|
+
AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEA
|
|
296
|
+
AQALZXhhbXBsZS5jb20AAA==
|
|
297
|
+
-----END ECHCONFIG-----
|
|
298
|
+
```
|
|
299
|
+
|
|
270
300
|
|
|
271
301
|
## Note
|
|
272
302
|
|
data/Rakefile
CHANGED
|
@@ -1,49 +1,8 @@
|
|
|
1
1
|
require 'bundler/gem_tasks'
|
|
2
|
-
require 'ech_config'
|
|
3
|
-
require 'hpke'
|
|
4
|
-
require 'openssl'
|
|
5
2
|
require 'rspec/core/rake_task'
|
|
6
3
|
require 'rubocop/rake_task'
|
|
7
4
|
|
|
8
5
|
RuboCop::RakeTask.new
|
|
9
6
|
RSpec::Core::RakeTask.new(:spec)
|
|
10
7
|
|
|
11
|
-
TMP_DIR = "#{__dir__}/tmp".freeze
|
|
12
|
-
ECHCONFIGS = "#{TMP_DIR}/echconfigs.pem".freeze
|
|
13
|
-
|
|
14
|
-
directory TMP_DIR
|
|
15
|
-
|
|
16
|
-
file ECHCONFIGS => TMP_DIR do
|
|
17
|
-
puts "generate #{ECHCONFIGS}..."
|
|
18
|
-
|
|
19
|
-
key = OpenSSL::PKey.generate_key('X25519')
|
|
20
|
-
echconfigs = ECHConfigList.new(
|
|
21
|
-
[
|
|
22
|
-
ECHConfig.new(
|
|
23
|
-
"\xfe\x0d".b,
|
|
24
|
-
ECHConfig::ECHConfigContents.new(
|
|
25
|
-
ECHConfig::ECHConfigContents::HpkeKeyConfig.new(
|
|
26
|
-
123,
|
|
27
|
-
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeKemId.new(HPKE::DHKEM_X25519_HKDF_SHA256),
|
|
28
|
-
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkePublicKey.new(key.raw_public_key),
|
|
29
|
-
[
|
|
30
|
-
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite.new(
|
|
31
|
-
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeKdfId.new(HPKE::HKDF_SHA256),
|
|
32
|
-
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeAeadId.new(HPKE::AES_128_GCM)
|
|
33
|
-
)
|
|
34
|
-
]
|
|
35
|
-
),
|
|
36
|
-
32,
|
|
37
|
-
'localhost'.b,
|
|
38
|
-
ECHConfig::ECHConfigContents::Extensions.new('')
|
|
39
|
-
)
|
|
40
|
-
)
|
|
41
|
-
]
|
|
42
|
-
)
|
|
43
|
-
File.write(ECHCONFIGS, key.private_to_pem + echconfigs.to_pem)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
desc 'generate echconfigs file'
|
|
47
|
-
task gen_echconfigs: ECHCONFIGS
|
|
48
|
-
|
|
49
8
|
task default: %i[rubocop spec]
|
data/docs/echspec-demo.png
CHANGED
|
Binary file
|
data/exe/echspec
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module EchSpec
|
|
2
|
+
class CLI
|
|
3
|
+
class GenConfigs
|
|
4
|
+
def execute(argv)
|
|
5
|
+
fpath = parse_options(argv)
|
|
6
|
+
write(fpath)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def parse_options(argv)
|
|
10
|
+
op = OptionParser.new
|
|
11
|
+
|
|
12
|
+
op.banner = <<~USAGE
|
|
13
|
+
Usage: echspec gen_configs {FILE}
|
|
14
|
+
|
|
15
|
+
Generate an ECHConfig PEM file.
|
|
16
|
+
|
|
17
|
+
Examples:
|
|
18
|
+
|
|
19
|
+
$ echspec gen_configs echconfigs.pem
|
|
20
|
+
USAGE
|
|
21
|
+
|
|
22
|
+
begin
|
|
23
|
+
args = op.parse(argv)
|
|
24
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
|
25
|
+
warn op
|
|
26
|
+
warn "** #{e.message}"
|
|
27
|
+
exit 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if args.length != 1
|
|
31
|
+
warn op
|
|
32
|
+
warn '** {FILE} argument is not specified'
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
args[0]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def write(fpath)
|
|
39
|
+
hostname = 'localhost'
|
|
40
|
+
|
|
41
|
+
key = OpenSSL::PKey.generate_key('X25519')
|
|
42
|
+
echconfigs = ECHConfigList.new(
|
|
43
|
+
[
|
|
44
|
+
ECHConfig.new(
|
|
45
|
+
"\xfe\x0d".b,
|
|
46
|
+
ECHConfig::ECHConfigContents.new(
|
|
47
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig.new(
|
|
48
|
+
123,
|
|
49
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeKemId.new(HPKE::DHKEM_X25519_HKDF_SHA256),
|
|
50
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkePublicKey.new(key.raw_public_key),
|
|
51
|
+
[
|
|
52
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite.new(
|
|
53
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeKdfId.new(HPKE::HKDF_SHA256),
|
|
54
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeAeadId.new(HPKE::AES_128_GCM)
|
|
55
|
+
)
|
|
56
|
+
]
|
|
57
|
+
),
|
|
58
|
+
32,
|
|
59
|
+
hostname.b,
|
|
60
|
+
ECHConfig::ECHConfigContents::Extensions.new('')
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
]
|
|
64
|
+
)
|
|
65
|
+
File.write(fpath, key.private_to_pem + echconfigs.to_pem)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module EchSpec
|
|
2
|
+
class CLI
|
|
3
|
+
class Run
|
|
4
|
+
def execute(argv)
|
|
5
|
+
fpath, port, force_compliant, verbose, hostname, sections = parse_options(argv)
|
|
6
|
+
|
|
7
|
+
if sections.nil?
|
|
8
|
+
Spec.run(fpath, port, hostname, force_compliant, verbose)
|
|
9
|
+
else
|
|
10
|
+
Spec.run_only(fpath, port, hostname, sections, verbose)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# rubocop: disable Metrics/AbcSize
|
|
15
|
+
# rubocop: disable Metrics/MethodLength
|
|
16
|
+
def parse_options(argv)
|
|
17
|
+
op = OptionParser.new
|
|
18
|
+
|
|
19
|
+
# default value
|
|
20
|
+
fpath = nil
|
|
21
|
+
port = 443
|
|
22
|
+
force_compliant = true
|
|
23
|
+
verbose = false
|
|
24
|
+
sections = nil
|
|
25
|
+
|
|
26
|
+
op.on(
|
|
27
|
+
'-f',
|
|
28
|
+
'--file FILE',
|
|
29
|
+
'path to ECHConfigs PEM file (default resolve ECHConfigs via DNS)'
|
|
30
|
+
) do |v|
|
|
31
|
+
fpath = v
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
op.on(
|
|
35
|
+
'-p',
|
|
36
|
+
'--port VALUE',
|
|
37
|
+
"server port number (default #{port})"
|
|
38
|
+
) do |v|
|
|
39
|
+
port = v
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
op.on(
|
|
43
|
+
'-n',
|
|
44
|
+
'--not-force-compliant-hpke',
|
|
45
|
+
'not force compliant ECHConfig HPKE cipher suite'
|
|
46
|
+
) do
|
|
47
|
+
force_compliant = false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
op.on(
|
|
51
|
+
'-v',
|
|
52
|
+
'--verbose',
|
|
53
|
+
'verbose mode; prints message stack if raised an error'
|
|
54
|
+
) do
|
|
55
|
+
verbose = true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
op.on(
|
|
59
|
+
'-s',
|
|
60
|
+
'--sections SECTIONS',
|
|
61
|
+
'sections to test; by the default, test all sections'
|
|
62
|
+
) do |v|
|
|
63
|
+
sections = v.split(',')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
op.banner = <<~USAGE
|
|
67
|
+
Usage: echspec run [OPTIONS...] {HOSTNAME}
|
|
68
|
+
|
|
69
|
+
Run ECH conformance tests for a server.
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
|
|
73
|
+
$ echspec run localhost
|
|
74
|
+
$ echspec run -f echconfigs.pem -p 4433 localhost
|
|
75
|
+
|
|
76
|
+
Options:
|
|
77
|
+
USAGE
|
|
78
|
+
|
|
79
|
+
begin
|
|
80
|
+
args = op.parse(argv)
|
|
81
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
|
82
|
+
warn op
|
|
83
|
+
warn "** #{e.message}"
|
|
84
|
+
exit 1
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if !fpath.nil? && !File.exist?(fpath)
|
|
88
|
+
warn '** {FILE} is not found'
|
|
89
|
+
exit 1
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
unknowns = sections.nil? ? [] : sections - Spec.sections
|
|
93
|
+
unless unknowns.empty?
|
|
94
|
+
warn "** #{unknowns} are unknown sections"
|
|
95
|
+
exit 1
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if args.length != 1
|
|
99
|
+
warn op
|
|
100
|
+
warn '** {HOSTNAME} argument is not specified'
|
|
101
|
+
exit 1
|
|
102
|
+
end
|
|
103
|
+
hostname = args[0]
|
|
104
|
+
|
|
105
|
+
[fpath, port, force_compliant, verbose, hostname, sections]
|
|
106
|
+
end
|
|
107
|
+
# rubocop: enable Metrics/AbcSize
|
|
108
|
+
# rubocop: enable Metrics/MethodLength
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
data/lib/echspec/cli.rb
CHANGED
|
@@ -1,96 +1,33 @@
|
|
|
1
|
+
require_relative 'cli/gen_configs'
|
|
2
|
+
require_relative 'cli/run'
|
|
3
|
+
|
|
1
4
|
module EchSpec
|
|
2
5
|
class CLI
|
|
3
|
-
|
|
4
|
-
# rubocop: disable Metrics/MethodLength
|
|
5
|
-
def parse_options(argv = ARGV)
|
|
6
|
-
op = OptionParser.new
|
|
7
|
-
|
|
8
|
-
# default value
|
|
9
|
-
fpath = nil
|
|
10
|
-
port = 443
|
|
11
|
-
force_compliant = true
|
|
12
|
-
verbose = false
|
|
13
|
-
sections = nil
|
|
14
|
-
|
|
15
|
-
op.on(
|
|
16
|
-
'-f',
|
|
17
|
-
'--file FILE',
|
|
18
|
-
'path to ECHConfigs PEM file (default resolve ECHConfigs via DNS)'
|
|
19
|
-
) do |v|
|
|
20
|
-
fpath = v
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
op.on(
|
|
24
|
-
'-p',
|
|
25
|
-
'--port VALUE',
|
|
26
|
-
"server port number (default #{port})"
|
|
27
|
-
) do |v|
|
|
28
|
-
port = v
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
op.on(
|
|
32
|
-
'-n',
|
|
33
|
-
'--not-force-compliant-hpke',
|
|
34
|
-
'not force compliant ECHConfig HPKE cipher suite'
|
|
35
|
-
) do
|
|
36
|
-
force_compliant = false
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
op.on(
|
|
40
|
-
'-v',
|
|
41
|
-
'--verbose',
|
|
42
|
-
'verbose mode; prints message stack if raised an error'
|
|
43
|
-
) do
|
|
44
|
-
verbose = true
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
op.on(
|
|
48
|
-
'-s',
|
|
49
|
-
'--sections SECTIONS',
|
|
50
|
-
'sections to test; by the default, test all sections'
|
|
51
|
-
) do |v|
|
|
52
|
-
sections = v.split(',')
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
op.banner = 'Usage: echspec [OPTIONS] <HOSTNAME>'
|
|
56
|
-
begin
|
|
57
|
-
args = op.parse(argv)
|
|
58
|
-
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
|
59
|
-
warn op
|
|
60
|
-
warn "** #{e.message}"
|
|
61
|
-
exit 1
|
|
62
|
-
end
|
|
6
|
+
using Refinements
|
|
63
7
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
exit 1
|
|
67
|
-
end
|
|
8
|
+
def execute(argv = ARGV)
|
|
9
|
+
subcommands = %i[run gen_configs]
|
|
68
10
|
|
|
69
|
-
|
|
70
|
-
unless unknowns.empty?
|
|
71
|
-
warn "** #{unknowns} are unknown sections"
|
|
72
|
-
exit 1
|
|
73
|
-
end
|
|
11
|
+
op = OptionParser.new
|
|
74
12
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
warn '** <HOSTNAME> argument is not specified'
|
|
78
|
-
exit 1
|
|
79
|
-
end
|
|
80
|
-
hostname = args[0]
|
|
13
|
+
op.banner = <<~USAGE
|
|
14
|
+
Usage: echspec {SUBCOMMAND}
|
|
81
15
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# rubocop: enable Metrics/AbcSize
|
|
85
|
-
# rubocop: enable Metrics/MethodLength
|
|
16
|
+
Available subcommands: #{subcommands.join(', ')}, version, help.
|
|
17
|
+
USAGE
|
|
86
18
|
|
|
87
|
-
|
|
88
|
-
|
|
19
|
+
op.version = EchSpec::VERSION
|
|
20
|
+
op.order!(argv)
|
|
89
21
|
|
|
90
|
-
|
|
91
|
-
|
|
22
|
+
subcommand = argv.shift
|
|
23
|
+
case subcommand&.to_sym
|
|
24
|
+
when :version
|
|
25
|
+
puts EchSpec::VERSION
|
|
26
|
+
when *subcommands
|
|
27
|
+
klass = self.class.const_get(subcommand.to_camel)
|
|
28
|
+
klass.new.__send__(:execute, argv)
|
|
92
29
|
else
|
|
93
|
-
|
|
30
|
+
puts op
|
|
94
31
|
end
|
|
95
32
|
end
|
|
96
33
|
end
|
data/lib/echspec/utils.rb
CHANGED
data/lib/echspec/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: echspec
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- thekuwayama
|
|
@@ -101,6 +101,8 @@ files:
|
|
|
101
101
|
- fixtures/server.key
|
|
102
102
|
- lib/echspec.rb
|
|
103
103
|
- lib/echspec/cli.rb
|
|
104
|
+
- lib/echspec/cli/gen_configs.rb
|
|
105
|
+
- lib/echspec/cli/run.rb
|
|
104
106
|
- lib/echspec/error.rb
|
|
105
107
|
- lib/echspec/log.rb
|
|
106
108
|
- lib/echspec/result.rb
|
|
@@ -136,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
136
138
|
- !ruby/object:Gem::Version
|
|
137
139
|
version: '0'
|
|
138
140
|
requirements: []
|
|
139
|
-
rubygems_version: 4.0.
|
|
141
|
+
rubygems_version: 4.0.8
|
|
140
142
|
specification_version: 4
|
|
141
143
|
summary: A conformance testing tool for ECH implementation
|
|
142
144
|
test_files: []
|