ruby-sslyze 1.1.0 → 1.2.0
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/ChangeLog.md +6 -1
- data/Rakefile +1 -1
- data/lib/sslyze/version.rb +1 -1
- data/lib/sslyze/xml.rb +1 -1
- data/lib/sslyze/xml/certinfo/certificate.rb +3 -3
- data/lib/sslyze/xml/certinfo/certificate/public_key.rb +84 -0
- data/lib/sslyze/xml/resum_rate.rb +1 -1
- data/spec/sslyze.xml +963 -10
- data/spec/xml/certinfo/certificate/public_key_spec.rb +71 -0
- data/spec/xml/certinfo/certificate_spec.rb +1 -1
- data/spec/xml/certinfo/ocsp_stapling/ocsp_response_spec.rb +1 -3
- data/spec/xml/certinfo/received_certificate_chain_spec.rb +3 -8
- data/spec/xml/http_headers/http_strict_transport_security_spec.rb +0 -8
- data/spec/xml/protocol/cipher_suite_spec.rb +18 -11
- data/spec/xml/target_spec.rb +1 -3
- data/spec/xml_examples.rb +4 -1
- metadata +5 -5
- data/lib/sslyze/x509/public_key.rb +0 -53
- data/spec/x509/public_key_spec.rb +0 -113
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'xml_examples'
|
3
|
+
require 'sslyze/xml/certinfo/certificate/public_key'
|
4
|
+
|
5
|
+
describe SSLyze::XML::Certinfo::Certificate::PublicKey do
|
6
|
+
include_examples "XML specs"
|
7
|
+
|
8
|
+
let(:xpath) { '/document/results/target/certinfo/receivedCertificateChain/certificate/publicKey' }
|
9
|
+
|
10
|
+
subject { described_class.new(xml.at(xpath)) }
|
11
|
+
|
12
|
+
describe "#algorithm" do
|
13
|
+
context "when the algorithm attribute is RSA" do
|
14
|
+
let(:xpath) { "#{super()}[@algorithm='RSA']" }
|
15
|
+
|
16
|
+
it { expect(subject.algorithm).to be :RSA }
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when the algorithm attribute is DSA" do
|
20
|
+
let(:xpath) { "#{super()}[@algorithm='DSA']" }
|
21
|
+
|
22
|
+
pending "need to find a target with a DSA public key" do
|
23
|
+
expect(subject.algorithm).to be :DSA
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the algorithm attribute is EllipticCurve" do
|
28
|
+
let(:xpath) { "#{super()}[@algorithm='EllipticCurve']" }
|
29
|
+
|
30
|
+
it { expect(subject.algorithm).to be :EC }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#size" do
|
35
|
+
let(:expected_size) { 2048 }
|
36
|
+
let(:xpath) { "#{super()}[@size=#{expected_size}]" }
|
37
|
+
|
38
|
+
it "should parse the size attribute" do
|
39
|
+
expect(subject.size).to be expected_size
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#curve" do
|
44
|
+
context "when the curve attribute is present" do
|
45
|
+
let(:expected_curve) { :secp256r1 }
|
46
|
+
let(:xpath) { "#{super()}[@curve='#{expected_curve}']" }
|
47
|
+
|
48
|
+
it { expect(subject.curve).to be(expected_curve) }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when the curve attribute is missing" do
|
52
|
+
let(:xpath) { "#{super()}[not(@curve)]" }
|
53
|
+
|
54
|
+
it { expect(subject.curve).to be nil }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#exponent" do
|
59
|
+
context "when the exponent attribute is present" do
|
60
|
+
let(:xpath) { "#{super()}[@exponent]" }
|
61
|
+
|
62
|
+
it { expect(subject.exponent).to be 65537 }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the exponent attribute is missing" do
|
66
|
+
let(:xpath) { "#{super()}[not(@exponent)]" }
|
67
|
+
|
68
|
+
it { expect(subject.exponent).to be nil }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -116,7 +116,7 @@ JqbaIVifYwqwNN+4lRxS3F5lNlA/il12IOgbRioLI62o8G0DaEUQgHNf8vSG
|
|
116
116
|
|
117
117
|
describe "#public_key" do
|
118
118
|
it do
|
119
|
-
expect(subject.public_key).to be_a(
|
119
|
+
expect(subject.public_key).to be_a(described_class::PublicKey)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -50,9 +50,7 @@ describe SSLyze::XML::Certinfo::OCSPStapling::OCSPResponse do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
describe "#produced_at" do
|
53
|
-
let(:expected_time) { '
|
54
|
-
|
55
|
-
let(:xpath) { "#{super()}[producedAt/text()='#{expected_time}']" }
|
53
|
+
let(:expected_time) { node.at_xpath('producedAt').inner_text }
|
56
54
|
|
57
55
|
it "should query producedAt and return a Time object" do
|
58
56
|
expect(subject.produced_at).to be == Time.parse(expected_time)
|
@@ -13,15 +13,14 @@ describe SSLyze::XML::Certinfo::ReceivedCertificateChain do
|
|
13
13
|
|
14
14
|
describe "#each_certificate" do
|
15
15
|
context "when 'certificate' XML children are present" do
|
16
|
-
let(:xpath)
|
17
|
-
let(:
|
16
|
+
let(:xpath) { "#{super()}[certificate]" }
|
17
|
+
let(:count) { node.xpath('./certificate').count }
|
18
18
|
|
19
19
|
it "should yield successive Certificate objects" do
|
20
20
|
expect { |b|
|
21
21
|
subject.each_certificate(&b)
|
22
22
|
}.to yield_successive_args(
|
23
|
-
SSLyze::XML::Certinfo::Certificate
|
24
|
-
SSLyze::XML::Certinfo::Certificate
|
23
|
+
*[SSLyze::XML::Certinfo::Certificate] * count
|
25
24
|
)
|
26
25
|
end
|
27
26
|
end
|
@@ -70,8 +69,6 @@ describe SSLyze::XML::Certinfo::ReceivedCertificateChain do
|
|
70
69
|
let(:xpath_count) { xml.at(xpath).xpath('certificate').count - 2 }
|
71
70
|
|
72
71
|
it "should yield the intermediate certificates" do
|
73
|
-
pending "<receivedCertificateChain/> always has at most two <certificate/> children"
|
74
|
-
|
75
72
|
expect { |b|
|
76
73
|
subject.each_intermediate(&b)
|
77
74
|
}.to yield_successive_args(
|
@@ -97,8 +94,6 @@ describe SSLyze::XML::Certinfo::ReceivedCertificateChain do
|
|
97
94
|
let(:xpath_count) { xml.at(xpath).xpath('certificate').count - 2 }
|
98
95
|
|
99
96
|
it "should yield the intermediate certificates" do
|
100
|
-
pending "<receivedCertificateChain/> always has at most two <certificate/> children"
|
101
|
-
|
102
97
|
expect(subject.intermediates).to be_a(Array).and(all(be_kind_of(SSLyze::XML::Certinfo::Certificate)))
|
103
98
|
end
|
104
99
|
end
|
@@ -28,8 +28,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it do
|
31
|
-
pending "need an example with no 'includeSubDomains' attribute"
|
32
|
-
|
33
31
|
expect(subject.include_sub_domains?).to be nil
|
34
32
|
end
|
35
33
|
end
|
@@ -50,8 +48,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
|
|
50
48
|
end
|
51
49
|
|
52
50
|
it do
|
53
|
-
pending "need an example where 'isSupported' is 'False'"
|
54
|
-
|
55
51
|
expect(subject.is_supported?).to be false
|
56
52
|
end
|
57
53
|
end
|
@@ -74,8 +70,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
|
|
74
70
|
end
|
75
71
|
|
76
72
|
it do
|
77
|
-
pending "need an example with no 'maxAge' attribute"
|
78
|
-
|
79
73
|
expect(subject.max_age).to be nil
|
80
74
|
end
|
81
75
|
end
|
@@ -98,8 +92,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
|
|
98
92
|
end
|
99
93
|
|
100
94
|
it do
|
101
|
-
pending "need an example with no 'preload' attribute"
|
102
|
-
|
103
95
|
expect(subject.preload?).to be nil
|
104
96
|
end
|
105
97
|
end
|
@@ -5,29 +5,38 @@ require 'sslyze/xml/protocol/cipher_suite'
|
|
5
5
|
describe SSLyze::XML::Protocol::CipherSuite do
|
6
6
|
include_examples "XML specs"
|
7
7
|
|
8
|
-
|
8
|
+
let(:expected_name) { 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' }
|
9
|
+
|
10
|
+
let(:xpath) { '/document/results/target/tlsv1_2/preferredCipherSuite/cipherSuite' }
|
9
11
|
|
10
12
|
describe "#name" do
|
13
|
+
let(:xpath) { "#{super()}[@name='#{expected_name}']" }
|
14
|
+
|
11
15
|
it "should parse the name attribute" do
|
12
|
-
expect(subject.name).to be ==
|
16
|
+
expect(subject.name).to be == expected_name
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
16
20
|
describe "#rfc_name" do
|
21
|
+
let(:xpath) { "#{super()}[@name='#{expected_name}']" }
|
22
|
+
|
17
23
|
it "should return the RFC cipher suite name" do
|
18
|
-
expect(subject.rfc_name).to be ==
|
24
|
+
expect(subject.rfc_name).to be == expected_name
|
19
25
|
end
|
20
26
|
end
|
21
27
|
|
22
28
|
describe "#openssl_name" do
|
29
|
+
let(:openssl_name) { 'ECDHE-RSA-AES128-GCM-SHA256' }
|
30
|
+
let(:xpath) { "#{super()}[@name='#{expected_name}']" }
|
31
|
+
|
23
32
|
it "should map the RFC name back to the OpenSSL name" do
|
24
|
-
expect(subject.openssl_name).to be ==
|
33
|
+
expect(subject.openssl_name).to be == openssl_name
|
25
34
|
end
|
26
35
|
end
|
27
36
|
|
28
37
|
describe "#connection_status" do
|
29
38
|
it "should parse the connectionStatus attribute" do
|
30
|
-
expect(subject.connection_status).to be == '
|
39
|
+
expect(subject.connection_status).to be == node['connectionStatus']
|
31
40
|
end
|
32
41
|
end
|
33
42
|
|
@@ -44,10 +53,10 @@ describe SSLyze::XML::Protocol::CipherSuite do
|
|
44
53
|
end
|
45
54
|
|
46
55
|
describe "#key_exchange" do
|
56
|
+
let(:xpath) { '/document/results/target/tlsv1_2/acceptedCipherSuites/cipherSuite' }
|
57
|
+
|
47
58
|
context "when the keyExchange child is present" do
|
48
|
-
|
49
|
-
described_class.new(xml.at('/document/results/target/tlsv1_2/acceptedCipherSuites/cipherSuite[keyExchange]'))
|
50
|
-
end
|
59
|
+
let(:xpath) { "#{super()}[keyExchange]" }
|
51
60
|
|
52
61
|
it do
|
53
62
|
expect(subject.key_exchange).to be_kind_of(described_class::KeyExchange)
|
@@ -55,9 +64,7 @@ describe SSLyze::XML::Protocol::CipherSuite do
|
|
55
64
|
end
|
56
65
|
|
57
66
|
context "when the keyExchange object is missing" do
|
58
|
-
|
59
|
-
described_class.new(xml.at('/document/results/target/tlsv1_2/acceptedCipherSuites/cipherSuite[not(./keyExchange)]'))
|
60
|
-
end
|
67
|
+
let(:xpath) { "#{super()}[not(./keyExchange)]" }
|
61
68
|
|
62
69
|
it { expect(subject.key_exchange).to be nil }
|
63
70
|
end
|
data/spec/xml/target_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe SSLyze::XML::Target do
|
|
6
6
|
include_examples "XML specs"
|
7
7
|
|
8
8
|
let(:xpath) { '/document/results/target' }
|
9
|
-
let(:expected_ip) { '
|
9
|
+
let(:expected_ip) { node['ip'] }
|
10
10
|
|
11
11
|
subject { described_class.new(xml.at(xpath)) }
|
12
12
|
|
@@ -29,8 +29,6 @@ describe SSLyze::XML::Target do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
describe "#ipaddr" do
|
32
|
-
let(:xpath) { "#{super()}[@ip='#{expected_ip}']" }
|
33
|
-
|
34
32
|
it "must parse the ip attribute" do
|
35
33
|
expect(subject.ipaddr).to be == IPAddr.new(expected_ip)
|
36
34
|
end
|
data/spec/xml_examples.rb
CHANGED
@@ -5,5 +5,8 @@ shared_examples_for "XML specs" do
|
|
5
5
|
let(:path) { File.expand_path('spec/sslyze.xml') }
|
6
6
|
let(:xml) { Nokogiri::XML(open(path)) }
|
7
7
|
|
8
|
-
|
8
|
+
let(:xpath) { '/' }
|
9
|
+
let(:node) { xml.at_xpath(xpath) }
|
10
|
+
|
11
|
+
subject { described_class.new(node) }
|
9
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-sslyze
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hal Brodigan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03
|
11
|
+
date: 2018-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rprogram
|
@@ -84,7 +84,6 @@ files:
|
|
84
84
|
- lib/sslyze/x509/extensions/key_usage.rb
|
85
85
|
- lib/sslyze/x509/extensions/subject_alt_name.rb
|
86
86
|
- lib/sslyze/x509/name.rb
|
87
|
-
- lib/sslyze/x509/public_key.rb
|
88
87
|
- lib/sslyze/xml.rb
|
89
88
|
- lib/sslyze/xml/attributes.rb
|
90
89
|
- lib/sslyze/xml/attributes/error.rb
|
@@ -94,6 +93,7 @@ files:
|
|
94
93
|
- lib/sslyze/xml/attributes/title.rb
|
95
94
|
- lib/sslyze/xml/certinfo.rb
|
96
95
|
- lib/sslyze/xml/certinfo/certificate.rb
|
96
|
+
- lib/sslyze/xml/certinfo/certificate/public_key.rb
|
97
97
|
- lib/sslyze/xml/certinfo/certificate_validation.rb
|
98
98
|
- lib/sslyze/xml/certinfo/certificate_validation/hostname_validation.rb
|
99
99
|
- lib/sslyze/xml/certinfo/certificate_validation/path_validation.rb
|
@@ -140,7 +140,7 @@ files:
|
|
140
140
|
- spec/x509/extensions/key_usage_spec.rb
|
141
141
|
- spec/x509/extensions/subject_alt_name_spec.rb
|
142
142
|
- spec/x509/name_spec.rb
|
143
|
-
- spec/
|
143
|
+
- spec/xml/certinfo/certificate/public_key_spec.rb
|
144
144
|
- spec/xml/certinfo/certificate_spec.rb
|
145
145
|
- spec/xml/certinfo/certificate_validation/hostname_validation_spec.rb
|
146
146
|
- spec/xml/certinfo/certificate_validation/path_validation_spec.rb
|
@@ -210,7 +210,7 @@ test_files:
|
|
210
210
|
- spec/x509/extensions/key_usage_spec.rb
|
211
211
|
- spec/x509/extensions/subject_alt_name_spec.rb
|
212
212
|
- spec/x509/name_spec.rb
|
213
|
-
- spec/
|
213
|
+
- spec/xml/certinfo/certificate/public_key_spec.rb
|
214
214
|
- spec/xml/certinfo/certificate_spec.rb
|
215
215
|
- spec/xml/certinfo/certificate_validation/hostname_validation_spec.rb
|
216
216
|
- spec/xml/certinfo/certificate_validation/path_validation_spec.rb
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'delegate'
|
2
|
-
|
3
|
-
module SSLyze
|
4
|
-
module X509
|
5
|
-
#
|
6
|
-
# Wrapper class around [OpenSSL::PKey] classes that provide {#algorithm} and
|
7
|
-
# {#size} methods.
|
8
|
-
#
|
9
|
-
# [OpenSSL::PKey]: http://www.rubydoc.info/stdlib/openssl/OpenSSL/PKey
|
10
|
-
#
|
11
|
-
# @since 1.0.0
|
12
|
-
#
|
13
|
-
class PublicKey < SimpleDelegator
|
14
|
-
|
15
|
-
#
|
16
|
-
# The algorithm that generated the public key.
|
17
|
-
#
|
18
|
-
# @return [:rsa, :dsa, :dh, :ec]
|
19
|
-
#
|
20
|
-
def algorithm
|
21
|
-
case __getobj__
|
22
|
-
when OpenSSL::PKey::RSA then :rsa
|
23
|
-
when OpenSSL::PKey::DSA then :dsa
|
24
|
-
when OpenSSL::PKey::DH then :dh
|
25
|
-
when OpenSSL::PKey::EC then :ec
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
#
|
30
|
-
# The size of the public key.
|
31
|
-
#
|
32
|
-
# @return [Integer]
|
33
|
-
# The number of bits in the public key.
|
34
|
-
#
|
35
|
-
# @raise [NotImplementedError]
|
36
|
-
# Determining key size for `OpenSSL::PKey::EC` public keys is currently
|
37
|
-
# not implemented.
|
38
|
-
#
|
39
|
-
def size
|
40
|
-
pkey = __getobj__
|
41
|
-
|
42
|
-
case pkey
|
43
|
-
when OpenSSL::PKey::RSA then pkey.n.num_bits
|
44
|
-
when OpenSSL::PKey::DSA then pkey.p.num_bits
|
45
|
-
when OpenSSL::PKey::DH then pkey.p.num_bits
|
46
|
-
when OpenSSL::PKey::EC
|
47
|
-
raise(NotImplementedError,"key size for #{pkey.inspect} not implemented")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,113 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'openssl'
|
3
|
-
|
4
|
-
require 'sslyze/x509/public_key'
|
5
|
-
|
6
|
-
describe SSLyze::X509::PublicKey do
|
7
|
-
let(:key_size) { 1024 }
|
8
|
-
|
9
|
-
let(:rsa_key) { OpenSSL::PKey::RSA.new(key_size) }
|
10
|
-
let(:dsa_key) { OpenSSL::PKey::DSA.new(key_size) }
|
11
|
-
let(:dh_key) { OpenSSL::PKey::DH.new(key_size) }
|
12
|
-
let(:ec_key) { OpenSSL::PKey::EC.new }
|
13
|
-
|
14
|
-
describe "#algorithm" do
|
15
|
-
context "when the pkey is an OpenSSL::PKey::RSA key" do
|
16
|
-
let(:pkey) { rsa_key }
|
17
|
-
|
18
|
-
subject { described_class.new(pkey) }
|
19
|
-
|
20
|
-
it { expect(subject.algorithm).to be :rsa }
|
21
|
-
end
|
22
|
-
|
23
|
-
context "when the pkey is an OpenSSL::PKey::DSA key" do
|
24
|
-
let(:pkey) { dsa_key }
|
25
|
-
|
26
|
-
subject { described_class.new(pkey) }
|
27
|
-
|
28
|
-
it { expect(subject.algorithm).to be :dsa }
|
29
|
-
end
|
30
|
-
|
31
|
-
context "when the pkey is an OpenSSL::PKey::DH key" do
|
32
|
-
let(:pkey) { dh_key }
|
33
|
-
|
34
|
-
subject { described_class.new(pkey) }
|
35
|
-
|
36
|
-
it { expect(subject.algorithm).to be :dh }
|
37
|
-
end
|
38
|
-
|
39
|
-
context "when the pkey is an OpenSSL::PKey::EC key" do
|
40
|
-
let(:pkey) { ec_key }
|
41
|
-
|
42
|
-
subject { described_class.new(pkey) }
|
43
|
-
|
44
|
-
it { expect(subject.algorithm).to be :ec }
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "#size" do
|
49
|
-
context "when the pkey is an OpenSSL::PKey::RSA key" do
|
50
|
-
let(:pkey) { rsa_key }
|
51
|
-
|
52
|
-
subject { described_class.new(pkey) }
|
53
|
-
|
54
|
-
it "to infer the key size from pkey.n.num_bits" do
|
55
|
-
expect(subject.size).to (be == pkey.n.num_bits).and(be == key_size)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context "when the pkey is an OpenSSL::PKey::DSA key" do
|
60
|
-
let(:pkey) { dsa_key }
|
61
|
-
|
62
|
-
subject { described_class.new(pkey) }
|
63
|
-
|
64
|
-
it "to infer the key size from pkey.p.num_bits" do
|
65
|
-
expect(subject.size).to (be == pkey.p.num_bits).and(be == key_size)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
context "when the pkey is an OpenSSL::PKey::DH key" do
|
70
|
-
let(:pkey) { dh_key }
|
71
|
-
|
72
|
-
subject { described_class.new(pkey) }
|
73
|
-
|
74
|
-
it "to infer the key size from pkey.p.num_bits" do
|
75
|
-
expect(subject.size).to (be == pkey.p.num_bits).and(be == key_size)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context "when the pkey is an OpenSSL::PKey::EC key" do
|
80
|
-
let(:pkey) { ec_key }
|
81
|
-
|
82
|
-
subject { described_class.new(pkey) }
|
83
|
-
|
84
|
-
it do
|
85
|
-
expect { subject.size }.to raise_error(NotImplementedError)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "#to_der" do
|
91
|
-
let(:pkey) { rsa_key }
|
92
|
-
|
93
|
-
subject { described_class.new(pkey) }
|
94
|
-
|
95
|
-
it "should call the public key's #to_der method" do
|
96
|
-
expect(pkey).to receive(:to_der)
|
97
|
-
|
98
|
-
subject.to_der
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
describe "#to_text" do
|
103
|
-
let(:pkey) { rsa_key }
|
104
|
-
|
105
|
-
subject { described_class.new(pkey) }
|
106
|
-
|
107
|
-
it "should call the public key's #to_text method" do
|
108
|
-
expect(pkey).to receive(:to_text)
|
109
|
-
|
110
|
-
subject.to_text
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|