11 changed files with 1060 additions and 816 deletions
@ -0,0 +1,61 @@ |
|||
module CryptCheck |
|||
module Grade |
|||
def grade |
|||
@grade ||= calculate_grade |
|||
end |
|||
|
|||
GRADES = %i(A+ A B+ B C+ C D E F G V T X) |
|||
GRADE_STATUS = { |
|||
:'A+' => :best, |
|||
A: :best, |
|||
:'B+' => :great, |
|||
B: :great, |
|||
:'C+' => :good, |
|||
C: :good, |
|||
D: nil, |
|||
E: :warning, |
|||
F: :error, |
|||
G: :critical, |
|||
|
|||
V: :critical, |
|||
T: :critical, |
|||
X: :critical |
|||
} |
|||
STATUS_GRADES = { |
|||
critical: :G, |
|||
error: :F, |
|||
warning: :E, |
|||
default: :D, |
|||
good: :C, |
|||
great: :B, |
|||
best: :A |
|||
} |
|||
|
|||
def grade_status |
|||
GRADE_STATUS.fetch self.grade, :unknown |
|||
end |
|||
|
|||
private |
|||
def calculate_grade |
|||
return :V unless self.valid? |
|||
return :T unless self.trusted? |
|||
|
|||
states = self.states |
|||
states = State.collect { |s| [s, State.state(states, s)] }.to_h |
|||
|
|||
State::BADS.each do |s| |
|||
return STATUS_GRADES[s] if states[s] |
|||
end |
|||
|
|||
grade = STATUS_GRADES[:default] |
|||
State::GOODS.each do |s| |
|||
state = states[s] |
|||
return grade if state == false |
|||
grade = STATUS_GRADES[s] |
|||
return grade if state == :some |
|||
grade = "#{grade}+".to_sym |
|||
end |
|||
grade |
|||
end |
|||
end |
|||
end |
@ -1,52 +0,0 @@ |
|||
module CryptCheck |
|||
module Tls |
|||
module Grade |
|||
def grade |
|||
@grade ||= calculate_grade |
|||
end |
|||
|
|||
GRADES = %i(A+ A B+ B C+ C D E F G V T X) |
|||
GRADE_STATUS = { |
|||
V: :critical, |
|||
T: :critical, |
|||
|
|||
G: :critical, |
|||
F: :error, |
|||
E: :warning, |
|||
D: nil, |
|||
C: :good, |
|||
:'C+' => :good, |
|||
B: :great, |
|||
:'B+' => :great, |
|||
A: :best, |
|||
:'A+' => :best |
|||
} |
|||
def grade_status |
|||
GRADE_STATUS.fetch self.grade, :unknown |
|||
end |
|||
|
|||
private |
|||
def calculate_grade |
|||
return :V unless self.valid? |
|||
return :T unless self.trusted? |
|||
|
|||
states = self.states |
|||
|
|||
{ critical: :G, error: :F, warning: :E }.each do |type, grade| |
|||
return grade if states[type].any? { |s| s == true } |
|||
end |
|||
|
|||
{good: %i(D C), great: %i(C B), best: %i(B A)}.each do |type, scores| |
|||
state = states[type] |
|||
return scores.first if state.all? { |s| s != false } |
|||
if state.any? { |s| s == false } |
|||
Logger.info { "Missing #{type} : #{states[type].select { |s| s == false }.collect &:key}" } |
|||
return scores.last |
|||
end |
|||
end |
|||
|
|||
:'A+' |
|||
end |
|||
end |
|||
end |
|||
end |
@ -0,0 +1,149 @@ |
|||
require 'awesome_print' |
|||
|
|||
module CryptCheck |
|||
describe Grade do |
|||
describe '#grade' do |
|||
def obj(trust: true, valid: true, **states) |
|||
Class.new do |
|||
def initialize(trust, valid, states) |
|||
@trust, @valid, @states = trust, valid, states |
|||
end |
|||
|
|||
include Grade |
|||
|
|||
def trusted? |
|||
@trust |
|||
end |
|||
|
|||
def valid? |
|||
@valid |
|||
end |
|||
|
|||
def states |
|||
State.empty.merge @states |
|||
end |
|||
end.new trust, valid, states |
|||
end |
|||
|
|||
it 'must return :V if not valid' do |
|||
obj = obj valid: false, critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :V |
|||
end |
|||
|
|||
it 'must return :T if not trusted' do |
|||
obj = obj trust: false, critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :T |
|||
end |
|||
|
|||
it 'must return :G if critical' do |
|||
obj = obj critical: { foo: false, bar: nil, baz: true }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :G |
|||
end |
|||
|
|||
it 'must return :F if error' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil, baz: true }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :F |
|||
end |
|||
|
|||
it 'must return :E if warning' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil, baz: true }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :E |
|||
end |
|||
|
|||
it 'must return :D if nor good nor bad' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: false, bar: nil }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :D |
|||
end |
|||
|
|||
it 'must return :C if some good' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: false, bar: nil, baz: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :C |
|||
end |
|||
|
|||
it 'must return :C+ if all good' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: false, bar: nil }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :'C+' |
|||
end |
|||
|
|||
it 'must return :B if some great' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: false, bar: nil, baz: true }, |
|||
best: { foo: true, bar: nil } |
|||
expect(obj.grade).to eq :B |
|||
end |
|||
|
|||
it 'must return :B+ if all great' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: false, bar: nil } |
|||
expect(obj.grade).to eq :'B+' |
|||
end |
|||
|
|||
it 'must return :A if some best' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: false, bar: nil, baz: true } |
|||
expect(obj.grade).to eq :A |
|||
end |
|||
|
|||
it 'must return :A+ if all best' do |
|||
obj = obj critical: { foo: false, bar: nil }, |
|||
error: { foo: false, bar: nil }, |
|||
warning: { foo: false, bar: nil }, |
|||
good: { foo: nil, bar: true }, |
|||
great: { foo: nil, bar: true }, |
|||
best: { foo: nil, bar: true } |
|||
expect(obj.grade).to eq :'A+' |
|||
end |
|||
end |
|||
end |
|||
end |
@ -0,0 +1,406 @@ |
|||
require 'ostruct' |
|||
|
|||
module CryptCheck |
|||
describe State do |
|||
describe '::status' do |
|||
it 'must handle empty list' do |
|||
expect(State.status []).to be_nil |
|||
end |
|||
|
|||
it 'must answer correctly' do |
|||
{ |
|||
[:critical, :critical] => :critical, |
|||
[:critical, :error] => :critical, |
|||
[:critical, :warning] => :critical, |
|||
[:critical, nil] => :critical, |
|||
[:critical, :good] => :critical, |
|||
[:critical, :great] => :critical, |
|||
[:critical, :best] => :critical, |
|||
|
|||
[:error, :critical] => :critical, |
|||
[:error, :error] => :error, |
|||
[:error, :warning] => :error, |
|||
[:error, nil] => :error, |
|||
[:error, :good] => :error, |
|||
[:error, :great] => :error, |
|||
[:error, :best] => :error, |
|||
|
|||
[:warning, :critical] => :critical, |
|||
[:warning, :error] => :error, |
|||
[:warning, :warning] => :warning, |
|||
[:warning, nil] => :warning, |
|||
[:warning, :good] => :warning, |
|||
[:warning, :great] => :warning, |
|||
[:warning, :best] => :warning, |
|||
|
|||
[:good, :critical] => :critical, |
|||
[:good, :error] => :error, |
|||
[:good, :warning] => :warning, |
|||
[:good, nil] => :good, |
|||
[:good, :good] => :good, |
|||
[:good, :great] => :good, |
|||
[:good, :best] => :good, |
|||
|
|||
[:great, :critical] => :critical, |
|||
[:great, :error] => :error, |
|||
[:great, :warning] => :warning, |
|||
[:great, nil] => :great, |
|||
[:great, :good] => :good, |
|||
[:great, :great] => :great, |
|||
[:great, :best] => :great, |
|||
|
|||
[:best, :critical] => :critical, |
|||
[:best, :error] => :error, |
|||
[:best, :warning] => :warning, |
|||
[:best, nil] => :best, |
|||
[:best, :good] => :good, |
|||
[:best, :great] => :great, |
|||
[:best, :best] => :best |
|||
}.each do |levels, result| |
|||
got = State.status levels |
|||
expect(got).to be(result), "#{levels} : expected #{result.inspect}, got #{got.inspect}" |
|||
end |
|||
end |
|||
|
|||
it 'must handle object list' do |
|||
critical = OpenStruct.new status: :critical |
|||
warning = OpenStruct.new status: :warning |
|||
expect(State.status [critical, warning]).to be :critical |
|||
end |
|||
end |
|||
|
|||
describe '::problem' do |
|||
it 'must answer correctly' do |
|||
{ |
|||
[:critical, :critical] => :critical, |
|||
[:critical, :error] => :critical, |
|||
[:critical, :warning] => :critical, |
|||
[:critical, nil] => :critical, |
|||
[:critical, :good] => :critical, |
|||
[:critical, :great] => :critical, |
|||
[:critical, :best] => :critical, |
|||
|
|||
[:error, :critical] => :critical, |
|||
[:error, :error] => :error, |
|||
[:error, :warning] => :error, |
|||
[:error, nil] => :error, |
|||
[:error, :good] => :error, |
|||
[:error, :great] => :error, |
|||
[:error, :best] => :error, |
|||
|
|||
[:warning, :critical] => :critical, |
|||
[:warning, :error] => :error, |
|||
[:warning, :warning] => :warning, |
|||
[:warning, nil] => :warning, |
|||
[:warning, :good] => :warning, |
|||
[:warning, :great] => :warning, |
|||
[:warning, :best] => :warning, |
|||
|
|||
[:good, :critical] => :critical, |
|||
[:good, :error] => :error, |
|||
[:good, :warning] => :warning, |
|||
[:good, nil] => nil, |
|||
[:good, :good] => nil, |
|||
[:good, :great] => nil, |
|||
[:good, :best] => nil, |
|||
|
|||
[:great, :critical] => :critical, |
|||
[:great, :error] => :error, |
|||
[:great, :warning] => :warning, |
|||
[:great, nil] => nil, |
|||
[:great, :good] => nil, |
|||
[:great, :great] => nil, |
|||
[:great, :best] => nil, |
|||
|
|||
[:best, :critical] => :critical, |
|||
[:best, :error] => :error, |
|||
[:best, :warning] => :warning, |
|||
[:best, nil] => nil, |
|||
[:best, :good] => nil, |
|||
[:best, :great] => nil, |
|||
[:best, :best] => nil |
|||
}.each do |levels, result| |
|||
got = State.problem levels |
|||
expect(got).to be(result), "#{levels} : expected #{result.inspect}, got #{got.inspect}" |
|||
end |
|||
end |
|||
|
|||
it 'must handle object list' do |
|||
critical = OpenStruct.new status: :critical |
|||
warning = OpenStruct.new status: :warning |
|||
expect(State.problem [critical, warning]).to be :critical |
|||
end |
|||
end |
|||
|
|||
describe '#states' do |
|||
def match_states(obj, **expected) |
|||
expected = State.empty.merge expected |
|||
expect(obj.states).to eq expected |
|||
end |
|||
|
|||
|
|||
let(:empty) do |
|||
Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[] |
|||
end |
|||
end.new |
|||
end |
|||
let(:childless) do |
|||
Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[ |
|||
[:foo, :critical, -> (_) { true }], |
|||
[:bar, :error, -> (_) { true }], |
|||
[:baz, :warning, -> (_) { false }] |
|||
] |
|||
end |
|||
end.new |
|||
end |
|||
let(:parent) do |
|||
child = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:bar, :error, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
Class.new do |
|||
include State |
|||
|
|||
def initialize(child) |
|||
@child = child |
|||
end |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
|
|||
def children |
|||
[@child] |
|||
end |
|||
end.new child |
|||
end |
|||
let(:duplicated) do |
|||
child = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, :error, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
Class.new do |
|||
include State |
|||
|
|||
def initialize(child) |
|||
@child = child |
|||
end |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
|
|||
def children |
|||
[@child] |
|||
end |
|||
end.new(child) |
|||
end |
|||
|
|||
it 'must return the level if single level specified' do |
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: true } |
|||
|
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { false }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false } |
|||
|
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { nil }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: nil } |
|||
end |
|||
|
|||
it 'must return all levels if multiple levels specified' do |
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :critical }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: true }, |
|||
error: { foo: true }, |
|||
good: { foo: false }, |
|||
great: { foo: false } |
|||
|
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :error }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false }, |
|||
error: { foo: true }, |
|||
good: { foo: false }, |
|||
great: { foo: false } |
|||
|
|||
|
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :great }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false }, |
|||
error: { foo: false }, |
|||
good: { foo: true }, |
|||
great: { foo: true } |
|||
|
|||
|
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :good }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false }, |
|||
error: { foo: false }, |
|||
good: { foo: true }, |
|||
great: { foo: false } |
|||
|
|||
obj = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { nil }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: nil }, |
|||
error: { foo: nil }, |
|||
good: { foo: nil }, |
|||
great: { foo: nil } |
|||
end |
|||
|
|||
it 'must return empty if no check nor child' do |
|||
match_states empty |
|||
end |
|||
|
|||
it 'must return personal status if no child' do |
|||
match_states childless, critical: { foo: true }, error: { bar: true }, warning: { baz: false } |
|||
end |
|||
|
|||
it 'must return personal and children statuses' do |
|||
match_states parent, critical: { foo: true }, error: { bar: true } |
|||
end |
|||
|
|||
it 'must return remove duplicated status' do |
|||
match_states duplicated, critical: { foo: true }, error: { foo: true } |
|||
end |
|||
end |
|||
|
|||
describe '#status' do |
|||
it 'must return nil if nothing special' do |
|||
empty = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[] |
|||
end |
|||
end.new |
|||
expect(empty.status).to be_nil |
|||
end |
|||
|
|||
it 'must return the status if only one' do |
|||
empty = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
expect(empty.status).to be :critical |
|||
end |
|||
|
|||
it 'must return the worst status if multiple' do |
|||
empty = Class.new do |
|||
include State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }], |
|||
[:bar, :error, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
expect(empty.status).to be :critical |
|||
end |
|||
end |
|||
|
|||
describe '::state' do |
|||
it 'must return false on bad case with only nil' do |
|||
states = { critical: { foo: nil } } |
|||
expect(State.state states, :critical).to be_falsey |
|||
end |
|||
|
|||
it 'must return false on bad case with all false or nil' do |
|||
states = { critical: { foo: false, bar: nil } } |
|||
expect(State.state states, :critical).to be_falsey |
|||
end |
|||
|
|||
it 'must return true on bad case with a single true' do |
|||
states = { critical: { foo: false, bar: nil, baz: true } } |
|||
expect(State.state states, :critical).to be_truthy |
|||
end |
|||
|
|||
it 'must return :all on good case with only nil' do |
|||
states = { best: { foo: nil } } |
|||
expect(State.state states, :best).to eq :all |
|||
end |
|||
|
|||
it 'must return false on good case with only false' do |
|||
states = { best: { foo: false } } |
|||
expect(State.state states, :best).to be_falsey |
|||
end |
|||
|
|||
it 'must return false on good case with only false or nil' do |
|||
states = { best: { foo: false, bar: nil } } |
|||
expect(State.state states, :best).to be_falsey |
|||
end |
|||
|
|||
it 'must return :some on good case with a single true' do |
|||
states = { best: { foo: false, bar: nil, baz: true } } |
|||
expect(State.state states, :best).to eq :some |
|||
end |
|||
|
|||
it 'must return :all on good case with only true' do |
|||
states = { best: { bar: true } } |
|||
expect(State.state states, :best).to eq :all |
|||
end |
|||
|
|||
it 'must return :all on good case with only true or nil' do |
|||
states = { best: { foo: nil, bar: true } } |
|||
expect(State.state states, :best).to eq :all |
|||
end |
|||
end |
|||
end |
|||
end |
@ -1,357 +0,0 @@ |
|||
require 'ostruct' |
|||
|
|||
describe CryptCheck::State do |
|||
describe '::status' do |
|||
it 'must handle empty list' do |
|||
expect(CryptCheck::State.status []).to be_nil |
|||
end |
|||
|
|||
it 'must answer correctly' do |
|||
{ |
|||
[:critical, :critical] => :critical, |
|||
[:critical, :error] => :critical, |
|||
[:critical, :warning] => :critical, |
|||
[:critical, nil] => :critical, |
|||
[:critical, :good] => :critical, |
|||
[:critical, :great] => :critical, |
|||
[:critical, :best] => :critical, |
|||
|
|||
[:error, :critical] => :critical, |
|||
[:error, :error] => :error, |
|||
[:error, :warning] => :error, |
|||
[:error, nil] => :error, |
|||
[:error, :good] => :error, |
|||
[:error, :great] => :error, |
|||
[:error, :best] => :error, |
|||
|
|||
[:warning, :critical] => :critical, |
|||
[:warning, :error] => :error, |
|||
[:warning, :warning] => :warning, |
|||
[:warning, nil] => :warning, |
|||
[:warning, :good] => :warning, |
|||
[:warning, :great] => :warning, |
|||
[:warning, :best] => :warning, |
|||
|
|||
[:good, :critical] => :critical, |
|||
[:good, :error] => :error, |
|||
[:good, :warning] => :warning, |
|||
[:good, nil] => :good, |
|||
[:good, :good] => :good, |
|||
[:good, :great] => :good, |
|||
[:good, :best] => :good, |
|||
|
|||
[:great, :critical] => :critical, |
|||
[:great, :error] => :error, |
|||
[:great, :warning] => :warning, |
|||
[:great, nil] => :great, |
|||
[:great, :good] => :good, |
|||
[:great, :great] => :great, |
|||
[:great, :best] => :great, |
|||
|
|||
[:best, :critical] => :critical, |
|||
[:best, :error] => :error, |
|||
[:best, :warning] => :warning, |
|||
[:best, nil] => :best, |
|||
[:best, :good] => :good, |
|||
[:best, :great] => :great, |
|||
[:best, :best] => :best |
|||
}.each do |levels, result| |
|||
got = CryptCheck::State.status levels |
|||
expect(got).to be(result), "#{levels} : expected #{result.inspect}, got #{got.inspect}" |
|||
end |
|||
end |
|||
|
|||
it 'must handle object list' do |
|||
critical = OpenStruct.new status: :critical |
|||
warning = OpenStruct.new status: :warning |
|||
expect(CryptCheck::State.status [critical, warning]).to be :critical |
|||
end |
|||
end |
|||
|
|||
describe '::problem' do |
|||
it 'must answer correctly' do |
|||
{ |
|||
[:critical, :critical] => :critical, |
|||
[:critical, :error] => :critical, |
|||
[:critical, :warning] => :critical, |
|||
[:critical, nil] => :critical, |
|||
[:critical, :good] => :critical, |
|||
[:critical, :great] => :critical, |
|||
[:critical, :best] => :critical, |
|||
|
|||
[:error, :critical] => :critical, |
|||
[:error, :error] => :error, |
|||
[:error, :warning] => :error, |
|||
[:error, nil] => :error, |
|||
[:error, :good] => :error, |
|||
[:error, :great] => :error, |
|||
[:error, :best] => :error, |
|||
|
|||
[:warning, :critical] => :critical, |
|||
[:warning, :error] => :error, |
|||
[:warning, :warning] => :warning, |
|||
[:warning, nil] => :warning, |
|||
[:warning, :good] => :warning, |
|||
[:warning, :great] => :warning, |
|||
[:warning, :best] => :warning, |
|||
|
|||
[:good, :critical] => :critical, |
|||
[:good, :error] => :error, |
|||
[:good, :warning] => :warning, |
|||
[:good, nil] => nil, |
|||
[:good, :good] => nil, |
|||
[:good, :great] => nil, |
|||
[:good, :best] => nil, |
|||
|
|||
[:great, :critical] => :critical, |
|||
[:great, :error] => :error, |
|||
[:great, :warning] => :warning, |
|||
[:great, nil] => nil, |
|||
[:great, :good] => nil, |
|||
[:great, :great] => nil, |
|||
[:great, :best] => nil, |
|||
|
|||
[:best, :critical] => :critical, |
|||
[:best, :error] => :error, |
|||
[:best, :warning] => :warning, |
|||
[:best, nil] => nil, |
|||
[:best, :good] => nil, |
|||
[:best, :great] => nil, |
|||
[:best, :best] => nil |
|||
}.each do |levels, result| |
|||
got = CryptCheck::State.problem levels |
|||
expect(got).to be(result), "#{levels} : expected #{result.inspect}, got #{got.inspect}" |
|||
end |
|||
end |
|||
|
|||
it 'must handle object list' do |
|||
critical = OpenStruct.new status: :critical |
|||
warning = OpenStruct.new status: :warning |
|||
expect(CryptCheck::State.problem [critical, warning]).to be :critical |
|||
end |
|||
end |
|||
|
|||
describe '#states' do |
|||
def match_states(obj, **expected) |
|||
expected = CryptCheck::State.empty.merge expected |
|||
expect(obj.states).to eq expected |
|||
end |
|||
|
|||
|
|||
let(:empty) do |
|||
Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[] |
|||
end |
|||
end.new |
|||
end |
|||
let(:childless) do |
|||
Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[ |
|||
[:foo, :critical, -> (_) { true }], |
|||
[:bar, :error, -> (_) { true }], |
|||
[:baz, :warning, -> (_) { false }] |
|||
] |
|||
end |
|||
end.new |
|||
end |
|||
let(:parent) do |
|||
child = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:bar, :error, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def initialize(child) |
|||
@child = child |
|||
end |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
|
|||
def children |
|||
[@child] |
|||
end |
|||
end.new child |
|||
end |
|||
let(:duplicated) do |
|||
child = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, :error, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def initialize(child) |
|||
@child = child |
|||
end |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
|
|||
def children |
|||
[@child] |
|||
end |
|||
end.new(child) |
|||
end |
|||
|
|||
it 'must return the level if single level specified' do |
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: true } |
|||
|
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { false }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false } |
|||
|
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { nil }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: nil } |
|||
end |
|||
|
|||
it 'must return all levels if multiple levels specified' do |
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :critical }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: true }, |
|||
error: { foo: true }, |
|||
good: { foo: false }, |
|||
great: { foo: false } |
|||
|
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :error }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false }, |
|||
error: { foo: true }, |
|||
good: { foo: false }, |
|||
great: { foo: false } |
|||
|
|||
|
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :great }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false }, |
|||
error: { foo: false }, |
|||
good: { foo: true }, |
|||
great: { foo: true } |
|||
|
|||
|
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { :good }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: false }, |
|||
error: { foo: false }, |
|||
good: { foo: true }, |
|||
great: { foo: false } |
|||
|
|||
obj = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, %i(critical error good great), -> (_) { nil }]] |
|||
end |
|||
end.new |
|||
match_states obj, critical: { foo: nil }, |
|||
error: { foo: nil }, |
|||
good: { foo: nil }, |
|||
great: { foo: nil } |
|||
end |
|||
|
|||
it 'must return empty if no check nor child' do |
|||
match_states empty |
|||
end |
|||
|
|||
it 'must return personal status if no child' do |
|||
match_states childless, critical: { foo: true }, error: { bar: true }, warning: { baz: false } |
|||
end |
|||
|
|||
it 'must return personal and children statuses' do |
|||
match_states parent, critical: { foo: true }, error: { bar: true } |
|||
end |
|||
|
|||
it 'must return remove duplicated status' do |
|||
match_states duplicated, critical: { foo: true }, error: { foo: true } |
|||
end |
|||
end |
|||
|
|||
describe '#status' do |
|||
it 'must return nil if nothing special' do |
|||
empty = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[] |
|||
end |
|||
end.new |
|||
expect(empty.status).to be_nil |
|||
end |
|||
|
|||
it 'must return the status if only one' do |
|||
empty = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
expect(empty.status).to be :critical |
|||
end |
|||
|
|||
it 'must return the worst status if multiple' do |
|||
empty = Class.new do |
|||
include ::CryptCheck::State |
|||
|
|||
def available_checks |
|||
[[:foo, :critical, -> (_) { true }], |
|||
[:bar, :error, -> (_) { true }]] |
|||
end |
|||
end.new |
|||
expect(empty.status).to be :critical |
|||
end |
|||
end |
|||
end |
@ -1,90 +1,92 @@ |
|||
describe CryptCheck::Tls::Cert do |
|||
describe '::trusted?' do |
|||
it 'must accept valid certificate' do |
|||
FakeTime.freeze Time.utc(2000, 1, 1) do |
|||
cert, *chain, ca = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq :trusted |
|||
module CryptCheck::Tls |
|||
describe Cert do |
|||
describe '::trusted?' do |
|||
it 'must accept valid certificate' do |
|||
FakeTime.freeze Time.utc(2000, 1, 1) do |
|||
cert, *chain, ca = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq :trusted |
|||
end |
|||
end |
|||
end |
|||
|
|||
it 'must reject self signed certificate' do |
|||
cert, ca = chain(%w(self-signed ca)) |
|||
trust = ::CryptCheck::Tls::Cert.trusted? cert, [], roots: ca |
|||
expect(trust).to eq 'self signed certificate' |
|||
it 'must reject self signed certificate' do |
|||
cert, ca = chain(%w(self-signed ca)) |
|||
trust = Cert.trusted? cert, [], roots: ca |
|||
expect(trust).to eq 'self signed certificate' |
|||
|
|||
# Case for SSLv2 |
|||
cert, ca = chain(%w(self-signed ca)) |
|||
trust = ::CryptCheck::Tls::Cert.trusted? cert, nil, roots: ca |
|||
expect(trust).to eq 'self signed certificate' |
|||
end |
|||
# Case for SSLv2 |
|||
cert, ca = chain(%w(self-signed ca)) |
|||
trust = Cert.trusted? cert, nil, roots: ca |
|||
expect(trust).to eq 'self signed certificate' |
|||
end |
|||
|
|||
it 'must reject unknown CA' do |
|||
cert, *chain = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: [] |
|||
expect(trust).to eq 'unable to get issuer certificate' |
|||
end |
|||
it 'must reject unknown CA' do |
|||
cert, *chain = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = Cert.trusted? cert, chain, roots: [] |
|||
expect(trust).to eq 'unable to get issuer certificate' |
|||
end |
|||
|
|||
it 'must reject missing intermediate chain' do |
|||
cert, ca = chain(%w(ecdsa-prime256v1 ca)) |
|||
chain = [] |
|||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq 'unable to get local issuer certificate' |
|||
end |
|||
it 'must reject missing intermediate chain' do |
|||
cert, ca = chain(%w(ecdsa-prime256v1 ca)) |
|||
chain = [] |
|||
trust = Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq 'unable to get local issuer certificate' |
|||
end |
|||
|
|||
it 'must reject expired certificate' do |
|||
FakeTime.freeze Time.utc(2002, 1, 1) do |
|||
cert, *chain, ca = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq 'certificate has expired' |
|||
it 'must reject expired certificate' do |
|||
FakeTime.freeze Time.utc(2002, 1, 1) do |
|||
cert, *chain, ca = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq 'certificate has expired' |
|||
end |
|||
end |
|||
end |
|||
|
|||
it 'must reject not yet valid certificate' do |
|||
FakeTime.freeze Time.utc(1999, 1, 1) do |
|||
cert, *chain, ca = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq 'certificate is not yet valid' |
|||
it 'must reject not yet valid certificate' do |
|||
FakeTime.freeze Time.utc(1999, 1, 1) do |
|||
cert, *chain, ca = chain(%w(ecdsa-prime256v1 intermediate ca)) |
|||
trust = Cert.trusted? cert, chain, roots: ca |
|||
expect(trust).to eq 'certificate is not yet valid' |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
describe '#md5?' do |
|||
it 'must detect md5 certificate' do |
|||
cert = ::CryptCheck::Tls::Cert.new cert(:md5) |
|||
expect(cert.md5?).to be true |
|||
describe '#md5?' do |
|||
it 'must detect md5 certificate' do |
|||
cert = Cert.new cert(:md5) |
|||
expect(cert.md5?).to be true |
|||
|
|||
cert = ::CryptCheck::Tls::Cert.new cert(:sha1) |
|||
expect(cert.md5?).to be false |
|||
cert = Cert.new cert(:sha1) |
|||
expect(cert.md5?).to be false |
|||
|
|||
cert = ::CryptCheck::Tls::Cert.new cert(:ecdsa, :prime256v1) |
|||
expect(cert.md5?).to be false |
|||
cert = Cert.new cert(:ecdsa, :prime256v1) |
|||
expect(cert.md5?).to be false |
|||
end |
|||
end |
|||
end |
|||
|
|||
describe '#sha1?' do |
|||
it 'must detect sha1 certificate' do |
|||
cert = ::CryptCheck::Tls::Cert.new cert(:md5) |
|||
expect(cert.sha1?).to be false |
|||
describe '#sha1?' do |
|||
it 'must detect sha1 certificate' do |
|||
cert = Cert.new cert(:md5) |
|||
expect(cert.sha1?).to be false |
|||
|
|||
cert = ::CryptCheck::Tls::Cert.new cert(:sha1) |
|||
expect(cert.sha1?).to be true |
|||
cert = Cert.new cert(:sha1) |
|||
expect(cert.sha1?).to be true |
|||
|
|||
cert = ::CryptCheck::Tls::Cert.new cert(:ecdsa, :prime256v1) |
|||
expect(cert.sha1?).to be false |
|||
cert = Cert.new cert(:ecdsa, :prime256v1) |
|||
expect(cert.sha1?).to be false |
|||
end |
|||
end |
|||
end |
|||
|
|||
describe '#sha2?' do |
|||
it 'must detect sha2 certificate' do |
|||
cert = ::CryptCheck::Tls::Cert.new cert(:md5) |
|||
expect(cert.sha2?).to be false |
|||
describe '#sha2?' do |
|||
it 'must detect sha2 certificate' do |
|||
cert = Cert.new cert(:md5) |
|||
expect(cert.sha2?).to be false |
|||
|
|||
cert = ::CryptCheck::Tls::Cert.new cert(:sha1) |
|||
expect(cert.sha2?).to be false |
|||
cert = Cert.new cert(:sha1) |
|||
expect(cert.sha2?).to be false |
|||
|
|||
cert = ::CryptCheck::Tls::Cert.new cert(:ecdsa, :prime256v1) |
|||
expect(cert.sha2?).to be true |
|||
cert = Cert.new cert(:ecdsa, :prime256v1) |
|||
expect(cert.sha2?).to be true |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
@ -1,129 +1,130 @@ |
|||
describe CryptCheck::Tls::Host do |
|||
def host(*args, **kargs) |
|||
do_in_serv *args, **kargs do |host, port| |
|||
CryptCheck::Tls::Host.new host, port |
|||
module CryptCheck::Tls |
|||
describe Host do |
|||
def host(*args, **kargs) |
|||
do_in_serv *args, **kargs do |host, port| |
|||
Host.new host, port |
|||
end |
|||
end |
|||
end |
|||
|
|||
def servers(*args, **kargs) |
|||
host(*args, **kargs).servers |
|||
end |
|||
|
|||
def error(*args, **kargs) |
|||
host(*args, **kargs).error |
|||
end |
|||
|
|||
it 'return 1 grade with IPv4' do |
|||
servers = servers() |
|||
expect(servers.size).to be 1 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, :ipv4 |
|||
end |
|||
|
|||
it 'return 1 grade with IPv6' do |
|||
addresses = [Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
def servers(*args, **kargs) |
|||
host(*args, **kargs).servers |
|||
end |
|||
|
|||
servers = servers(host: Helpers::DEFAULT_IPv6) |
|||
expect(servers.size).to be 1 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
it 'return 2 grades with hostname (IPv4 & IPv6)' do |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
def error(*args, **kargs) |
|||
host(*args, **kargs).error |
|||
end |
|||
|
|||
servers = servers(host: '::') |
|||
expect(servers.size).to be 2 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, :ipv4 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
it 'return error if DNS resolution problem' do |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) |
|||
.and_raise SocketError, 'getaddrinfo: Name or service not known' |
|||
it 'return 1 grade with IPv4' do |
|||
servers = servers() |
|||
expect(servers.size).to be 1 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, :ipv4 |
|||
end |
|||
|
|||
error = error() |
|||
expect_error error, ::SocketError, 'getaddrinfo: Name or service not known' |
|||
end |
|||
it 'return 1 grade with IPv6' do |
|||
addresses = [Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
end |
|||
|
|||
it 'return error if analysis too long' do |
|||
stub_const 'CryptCheck::Tls::Host::MAX_ANALYSIS_DURATION', 1 |
|||
allow_any_instance_of(CryptCheck::Tls::Host).to receive(:server) { sleep 2 } |
|||
servers = servers(host: Helpers::DEFAULT_IPv6) |
|||
expect(servers.size).to be 1 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
servers = servers() |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Too long analysis (max 1 second)' |
|||
end |
|||
it 'return 2 grades with hostname (IPv4 & IPv6)' do |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
end |
|||
|
|||
it 'return error if unable to connect' do |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
servers = servers(host: '::') |
|||
expect(servers.size).to be 2 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, :ipv4 |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
servers = servers(host: Helpers::DEFAULT_IPv6) |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Connection refused - connect(2) for 127.0.0.1:15000' |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
it 'return error if DNS resolution problem' do |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) |
|||
.and_raise SocketError, 'getaddrinfo: Name or service not known' |
|||
|
|||
it 'return error if TCP timeout' do |
|||
stub_const 'CryptCheck::Tls::Engine::TCP_TIMEOUT', 1 |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
error = error() |
|||
expect_error error, ::SocketError, 'getaddrinfo: Name or service not known' |
|||
end |
|||
|
|||
original = IO.method :select |
|||
allow(IO).to receive(:select) do |*args, &block| |
|||
socket = [args[0]&.first, args[1]&.first].compact.first |
|||
next nil if socket.is_a?(Socket) && (socket.local_address.afamily == Socket::AF_INET) |
|||
original.call *args, &block |
|||
it 'return error if analysis too long' do |
|||
stub_const 'CryptCheck::Tls::Host::MAX_ANALYSIS_DURATION', 1 |
|||
allow_any_instance_of(Host).to receive(:server) { sleep 2 } |
|||
|
|||
servers = servers() |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Too long analysis (max 1 second)' |
|||
end |
|||
|
|||
servers = servers(host: '::') |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Timeout when connecting to 127.0.0.1:15000 (max 1 second)' |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
it 'return error if unable to connect' do |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
end |
|||
|
|||
it 'return error if TLS timeout' do |
|||
stub_const 'CryptCheck::Tls::Engine::TLS_TIMEOUT', 1 |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
servers = servers(host: Helpers::DEFAULT_IPv6) |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Connection refused - connect(2) for 127.0.0.1:15000' |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
original = IO.method :select |
|||
allow(IO).to receive(:select) do |*args, &block| |
|||
socket = [args[0]&.first, args[1]&.first].compact.first |
|||
next nil if socket.is_a?(OpenSSL::SSL::SSLSocket) && (socket.io.local_address.afamily == Socket::AF_INET) |
|||
original.call *args, &block |
|||
it 'return error if TCP timeout' do |
|||
stub_const 'CryptCheck::Tls::Engine::TCP_TIMEOUT', 1 |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
end |
|||
|
|||
original = IO.method :select |
|||
allow(IO).to receive(:select) do |*args, &block| |
|||
socket = [args[0]&.first, args[1]&.first].compact.first |
|||
next nil if socket.is_a?(Socket) && (socket.local_address.afamily == Socket::AF_INET) |
|||
original.call *args, &block |
|||
end |
|||
|
|||
servers = servers(host: '::') |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Timeout when connecting to 127.0.0.1:15000 (max 1 second)' |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
servers = servers(host: '::') |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Timeout when TLS connecting to 127.0.0.1:15000 (max 1 second)' |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
it 'return error if plain server' do |
|||
stub_const 'CryptCheck::Tls::ENGINE::TLS_TIMEOUT', 1 |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
it 'return error if TLS timeout' do |
|||
stub_const 'CryptCheck::Tls::Engine::TLS_TIMEOUT', 1 |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
end |
|||
|
|||
original = IO.method :select |
|||
allow(IO).to receive(:select) do |*args, &block| |
|||
socket = [args[0]&.first, args[1]&.first].compact.first |
|||
next nil if socket.is_a?(OpenSSL::SSL::SSLSocket) && (socket.io.local_address.afamily == Socket::AF_INET) |
|||
original.call *args, &block |
|||
end |
|||
|
|||
servers = servers(host: '::') |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'Timeout when TLS connecting to 127.0.0.1:15000 (max 1 second)' |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
|
|||
servers = plain_serv Helpers::DEFAULT_IPv4 do |
|||
servers(host: Helpers::DEFAULT_IPv6) |
|||
it 'return error if plain server' do |
|||
stub_const 'ENGINE::TLS_TIMEOUT', 1 |
|||
addresses = [Helpers::DEFAULT_IPv4, Helpers::DEFAULT_IPv6] |
|||
allow(Addrinfo).to receive(:getaddrinfo).with(Helpers::DEFAULT_HOST, nil, nil, :STREAM) do |
|||
addresses.collect { |a| Addrinfo.new Socket.sockaddr_in(nil, a) } |
|||
end |
|||
|
|||
servers = plain_serv Helpers::DEFAULT_IPv4 do |
|||
servers(host: Helpers::DEFAULT_IPv6) |
|||
end |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||
'TLS seems not supported on this server' |
|||
expect_grade servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv6, Helpers::DEFAULT_PORT, :ipv6 |
|||
end |
|||
expect_grade_error servers, Helpers::DEFAULT_HOST, Helpers::DEFAULT_IPv4, Helpers::DEFAULT_PORT, |
|||