diff options
-rw-r--r-- | spec/ruby/core/process/clock_getres_spec.rb | 6 | ||||
-rw-r--r-- | spec/ruby/core/string/crypt_spec.rb | 157 | ||||
-rw-r--r-- | spec/ruby/library/socket/socket/connect_nonblock_spec.rb | 12 | ||||
-rw-r--r-- | spec/ruby/library/socket/udpsocket/initialize_spec.rb | 10 |
4 files changed, 118 insertions, 67 deletions
diff --git a/spec/ruby/core/process/clock_getres_spec.rb b/spec/ruby/core/process/clock_getres_spec.rb index cadb5b7e8c..7112b0520a 100644 --- a/spec/ruby/core/process/clock_getres_spec.rb +++ b/spec/ruby/core/process/clock_getres_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/clocks' describe "Process.clock_getres" do # clock_getres() seems completely buggy on FreeBSD: # https://rubyci.org/logs/rubyci.s3.amazonaws.com/freebsd11zfs/ruby-trunk/log/20190428T093003Z.fail.html.gz - platform_is_not :freebsd do + platform_is_not :freebsd, :openbsd do # NOTE: Look at fixtures/clocks.rb for clock and OS-specific exclusions ProcessSpecs.clock_constants_for_resolution_checks.each do |name, value| it "matches the clock in practice for Process::#{name}" do @@ -50,13 +50,13 @@ describe "Process.clock_getres" do # These are observed - platform_is_not :solaris, :aix do + platform_is_not :solaris, :aix, :openbsd do it "with Process::CLOCK_REALTIME reports at least 1 microsecond" do Process.clock_getres(Process::CLOCK_REALTIME, :nanosecond).should <= 1_000 end end - platform_is_not :aix do + platform_is_not :aix, :openbsd do it "with Process::CLOCK_MONOTONIC reports at least 1 microsecond" do Process.clock_getres(Process::CLOCK_MONOTONIC, :nanosecond).should <= 1_000 end diff --git a/spec/ruby/core/string/crypt_spec.rb b/spec/ruby/core/string/crypt_spec.rb index 01d3830892..66161b280f 100644 --- a/spec/ruby/core/string/crypt_spec.rb +++ b/spec/ruby/core/string/crypt_spec.rb @@ -2,72 +2,117 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "String#crypt" do - # Note: MRI's documentation just says that the C stdlib function crypt() is - # called. - # - # I'm not sure if crypt() is guaranteed to produce the same result across - # different platforms. It seems that there is one standard UNIX implementation - # of crypt(), but that alternative implementations are possible. See - # http://www.unix.org.ua/orelly/networking/puis/ch08_06.htm - it "returns a cryptographic hash of self by applying the UNIX crypt algorithm with the specified salt" do - "".crypt("aa").should == "aaQSqAReePlq6" - "nutmeg".crypt("Mi").should == "MiqkFWCm1fNJI" - "ellen1".crypt("ri").should == "ri79kNd7V6.Sk" - "Sharon".crypt("./").should == "./UY9Q7TvYJDg" - "norahs".crypt("am").should == "amfIADT2iqjA." - "norahs".crypt("7a").should == "7azfT5tIdyh0I" - - # Only uses first 8 chars of string - "01234567".crypt("aa").should == "aa4c4gpuvCkSE" - "012345678".crypt("aa").should == "aa4c4gpuvCkSE" - "0123456789".crypt("aa").should == "aa4c4gpuvCkSE" - - # Only uses first 2 chars of salt - "hello world".crypt("aa").should == "aayPz4hyPS1wI" - "hello world".crypt("aab").should == "aayPz4hyPS1wI" - "hello world".crypt("aabc").should == "aayPz4hyPS1wI" - end + platform_is :openbsd do + it "returns a cryptographic hash of self by applying the bcrypt algorithm with the specified salt" do + "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2." - it "raises an ArgumentError when the salt is shorter than two characters" do - lambda { "hello".crypt("") }.should raise_error(ArgumentError) - lambda { "hello".crypt("f") }.should raise_error(ArgumentError) - lambda { "hello".crypt("\x00\x00") }.should raise_error(ArgumentError) - lambda { "hello".crypt("\x00a") }.should raise_error(ArgumentError) - lambda { "hello".crypt("a\x00") }.should raise_error(ArgumentError) - end + # Only uses first 72 characters of string + ("12345678"*9).crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWukj/ORBnsMjCGpST/zCJnAypc7eAbutK" + ("12345678"*10).crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWukj/ORBnsMjCGpST/zCJnAypc7eAbutK" - it "raises an ArgumentError when the string contains NUL character" do - lambda { "poison\0null".crypt("aa") }.should raise_error(ArgumentError) - end + # Only uses first 29 characters of salt + "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWuB").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2." + end - it "calls #to_str to converts the salt arg to a String" do - obj = mock('aa') - obj.should_receive(:to_str).and_return("aa") + it "raises Errno::EINVAL when the salt is shorter than 29 characters" do + lambda { "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHW") }.should raise_error(Errno::EINVAL) + end - "".crypt(obj).should == "aaQSqAReePlq6" - end + it "calls #to_str to converts the salt arg to a String" do + obj = mock('$2a$04$0WVaz0pV3jzfZ5G5tpmHWu') + obj.should_receive(:to_str).and_return("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu") - it "raises a type error when the salt arg can't be converted to a string" do - lambda { "".crypt(5) }.should raise_error(TypeError) - lambda { "".crypt(mock('x')) }.should raise_error(TypeError) + "mypassword".crypt(obj).should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2." + end + + it "taints the result if either salt or self is tainted" do + tainted_salt = "$2a$04$0WVaz0pV3jzfZ5G5tpmHWu" + tainted_str = "mypassword" + + tainted_salt.taint + tainted_str.taint + + "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").tainted?.should == false + tainted_str.crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").tainted?.should == true + "mypassword".crypt(tainted_salt).tainted?.should == true + tainted_str.crypt(tainted_salt).tainted?.should == true + end + + it "doesn't return subclass instances" do + StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should be_an_instance_of(String) + "mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String) + StringSpecs::MyString.new("mypassword").crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String) + end end - it "taints the result if either salt or self is tainted" do - tainted_salt = "aa" - tainted_str = "hello" + platform_is_not :openbsd do + # Note: MRI's documentation just says that the C stdlib function crypt() is + # called. + # + # I'm not sure if crypt() is guaranteed to produce the same result across + # different platforms. It seems that there is one standard UNIX implementation + # of crypt(), but that alternative implementations are possible. See + # http://www.unix.org.ua/orelly/networking/puis/ch08_06.htm + it "returns a cryptographic hash of self by applying the UNIX crypt algorithm with the specified salt" do + "".crypt("aa").should == "aaQSqAReePlq6" + "nutmeg".crypt("Mi").should == "MiqkFWCm1fNJI" + "ellen1".crypt("ri").should == "ri79kNd7V6.Sk" + "Sharon".crypt("./").should == "./UY9Q7TvYJDg" + "norahs".crypt("am").should == "amfIADT2iqjA." + "norahs".crypt("7a").should == "7azfT5tIdyh0I" - tainted_salt.taint - tainted_str.taint + # Only uses first 8 chars of string + "01234567".crypt("aa").should == "aa4c4gpuvCkSE" + "012345678".crypt("aa").should == "aa4c4gpuvCkSE" + "0123456789".crypt("aa").should == "aa4c4gpuvCkSE" - "hello".crypt("aa").tainted?.should == false - tainted_str.crypt("aa").tainted?.should == true - "hello".crypt(tainted_salt).tainted?.should == true - tainted_str.crypt(tainted_salt).tainted?.should == true + # Only uses first 2 chars of salt + "hello world".crypt("aa").should == "aayPz4hyPS1wI" + "hello world".crypt("aab").should == "aayPz4hyPS1wI" + "hello world".crypt("aabc").should == "aayPz4hyPS1wI" + end + + it "raises an ArgumentError when the string contains NUL character" do + lambda { "poison\0null".crypt("aa") }.should raise_error(ArgumentError) + end + + it "calls #to_str to converts the salt arg to a String" do + obj = mock('aa') + obj.should_receive(:to_str).and_return("aa") + + "".crypt(obj).should == "aaQSqAReePlq6" + end + + it "taints the result if either salt or self is tainted" do + tainted_salt = "aa" + tainted_str = "hello" + + tainted_salt.taint + tainted_str.taint + + "hello".crypt("aa").tainted?.should == false + tainted_str.crypt("aa").tainted?.should == true + "hello".crypt(tainted_salt).tainted?.should == true + tainted_str.crypt(tainted_salt).tainted?.should == true + end + + it "doesn't return subclass instances" do + StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String) + "hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String) + StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String) + end + + it "raises an ArgumentError when the salt is shorter than two characters" do + lambda { "hello".crypt("") }.should raise_error(ArgumentError) + lambda { "hello".crypt("f") }.should raise_error(ArgumentError) + lambda { "hello".crypt("\x00\x00") }.should raise_error(ArgumentError) + lambda { "hello".crypt("\x00a") }.should raise_error(ArgumentError) + lambda { "hello".crypt("a\x00") }.should raise_error(ArgumentError) + end end - it "doesn't return subclass instances" do - StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String) - "hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String) - StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String) + it "raises a type error when the salt arg can't be converted to a string" do + lambda { "".crypt(5) }.should raise_error(TypeError) + lambda { "".crypt(mock('x')) }.should raise_error(TypeError) end end diff --git a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb index c56bebee62..b5f416d96f 100644 --- a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb +++ b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb @@ -114,24 +114,24 @@ describe 'Socket#connect_nonblock' do platform_is_not :windows do it 'raises Errno::EISCONN when already connected' do @server.listen(1) - @client.connect(@server.getsockname).should == 0 + @client.connect(@server.connect_address).should == 0 lambda { - @client.connect_nonblock(@server.getsockname) + @client.connect_nonblock(@server.connect_address) # A second call needed if non-blocking sockets become default # XXX honestly I don't expect any real code to care about this spec # as it's too implementation-dependent and checking for connect() # errors is futile anyways because of TOCTOU - @client.connect_nonblock(@server.getsockname) + @client.connect_nonblock(@server.connect_address) }.should raise_error(Errno::EISCONN) end it 'returns 0 when already connected in exceptionless mode' do @server.listen(1) - @client.connect(@server.getsockname).should == 0 + @client.connect(@server.connect_address).should == 0 - @client.connect_nonblock(@server.getsockname, exception: false).should == 0 + @client.connect_nonblock(@server.connect_address, exception: false).should == 0 end end @@ -140,7 +140,7 @@ describe 'Socket#connect_nonblock' do @server.bind(@sockaddr) lambda { - @client.connect_nonblock(@server.getsockname) + @client.connect_nonblock(@server.connect_address) }.should raise_error(IO::EINPROGRESSWaitWritable) end end diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb index 06f7b5ef1c..9497d0dcbc 100644 --- a/spec/ruby/library/socket/udpsocket/initialize_spec.rb +++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb @@ -30,7 +30,13 @@ describe 'UDPSocket#initialize' do @socket.binmode?.should be_true end - it 'raises Errno::EAFNOSUPPORT when given an invalid address family' do - lambda { UDPSocket.new(666) }.should raise_error(Errno::EAFNOSUPPORT) + it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT when given an invalid address family' do + begin + UDPSocket.new(666) + rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT => e + [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class) + else + raise "expected Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT exception raised" + end end end |