Skip to content

Commit

Permalink
make specs run even if CURVE is not availble
Browse files Browse the repository at this point in the history
  • Loading branch information
paddor committed Jan 4, 2024
1 parent 02c20b7 commit a10ff0d
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 78 deletions.
6 changes: 6 additions & 0 deletions lib/cztop/cert_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class CertStore
include HasFFIDelegate
extend CZTop::HasFFIDelegate::ClassMethods

unless ::CZMQ::FFI::Zsys.has_curve
def self.new(...)
fail NotImplementedError
end
end

# Initializes a new certificate store.
#
# @param location [String, #to_s, nil] location the path to the
Expand Down
17 changes: 17 additions & 0 deletions lib/cztop/certificate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ class Certificate
extend CZTop::HasFFIDelegate::ClassMethods
include ::CZMQ::FFI

unless ::CZMQ::FFI::Zsys.has_curve
def self.new(...)
fail NotImplementedError
end
end


# Warns if CURVE security isn't available.
# @return [void]
def self.check_curve_availability
Expand Down Expand Up @@ -57,6 +64,16 @@ def initialize
end


KEY_ALL_ZERO = '0000000000000000000000000000000000000000'

# @return [Boolean] whether one of the keys is all zeros (happens when CURVE is not available, i.e. libzmq was
# compiled without libsodium)
# @see .check_curve_availability
def zero?
public_key(format: :z85) == KEY_ALL_ZERO || secret_key(format: :z85) == KEY_ALL_ZERO
end


# Returns the public key either as Z85-encoded ASCII string (default) or
# binary string.
# @param format [Symbol] +:z85+ for Z85, +:binary+ for binary
Expand Down
146 changes: 84 additions & 62 deletions lib/cztop/zsock_options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,58 +111,8 @@ def rcvhwm=(value)

# @!endgroup

# @!group Security Mechanisms

# @return [Boolean] whether this zocket is a CURVE server
def CURVE_server?
Zsock.curve_server(@zocket).positive?
end


# Make this zocket a CURVE server.
# @param bool [Boolean]
# @note You'll have to use a {CZTop::Authenticator}.
def CURVE_server=(bool)
Zsock.set_curve_server(@zocket, bool ? 1 : 0)
end


# @return [String] Z85 encoded server key set
# @return [nil] if the current mechanism isn't CURVE or CURVE isn't
# supported
def CURVE_serverkey
CURVE_key(:curve_serverkey)
end


# Get one of the CURVE keys.
# @param key_name [Symbol] something like +:curve_serverkey+
# @return [String, nil] key, if CURVE is supported and active, or nil
def CURVE_key(key_name)
return nil if mechanism != :CURVE

ptr = Zsock.__send__(key_name, @zocket)
return nil if ptr.null?

ptr.read_string
end
private :CURVE_key

# Sets the server's public key, so the zocket can authenticate the
# remote server.
# @param key [String] Z85 (40 bytes) or binary (32 bytes) server key
# @raise [ArgumentError] if key has wrong size
def CURVE_serverkey=(key)
case key.bytesize
when 40
Zsock.set_curve_serverkey(@zocket, key)
when 32
ptr = ::FFI::MemoryPointer.from_string(key)
Zsock.set_curve_serverkey_bin(@zocket, ptr)
else
raise ArgumentError, format('invalid server key: %p', key)
end
end
# @!group Security Mechanisms

# supported security mechanisms and their macro value equivalent
MECHANISMS = {
Expand All @@ -182,20 +132,92 @@ def mechanism
raise format('unknown ZMQ security mechanism code: %i', code)
end

if ::CZMQ::FFI::Zsys.has_curve
# @return [Boolean] whether this zocket is a CURVE server
def CURVE_server?
Zsock.curve_server(@zocket).positive?
end

# @return [String] Z85 encoded secret key set
# @return [nil] if the current mechanism isn't CURVE or CURVE isn't
# supported
def CURVE_secretkey
CURVE_key(:curve_secretkey)
end

# Make this zocket a CURVE server.
# @param bool [Boolean]
# @note You'll have to use a {CZTop::Authenticator}.
def CURVE_server=(bool)
Zsock.set_curve_server(@zocket, bool ? 1 : 0)
end


# @return [String] Z85 encoded server key set
# @return [nil] if the current mechanism isn't CURVE or CURVE isn't
# supported
def CURVE_serverkey
CURVE_key(:curve_serverkey)
end


# Get one of the CURVE keys.
# @param key_name [Symbol] something like +:curve_serverkey+
# @return [String, nil] key, if CURVE is supported and active, or nil
def CURVE_key(key_name)
return nil if mechanism != :CURVE

ptr = Zsock.__send__(key_name, @zocket)
return nil if ptr.null?

ptr.read_string
end
private :CURVE_key

# Sets the server's public key, so the zocket can authenticate the
# remote server.
# @param key [String] Z85 (40 bytes) or binary (32 bytes) server key
# @raise [ArgumentError] if key has wrong size
def CURVE_serverkey=(key)
case key.bytesize
when 40
Zsock.set_curve_serverkey(@zocket, key)
when 32
ptr = ::FFI::MemoryPointer.from_string(key)
Zsock.set_curve_serverkey_bin(@zocket, ptr)
else
raise ArgumentError, format('invalid server key: %p', key)
end
end


# @return [String] Z85 encoded public key set
# @return [nil] if the current mechanism isn't CURVE or CURVE isn't
# supported
def CURVE_publickey
CURVE_key(:curve_publickey)
# @return [String] Z85 encoded secret key set
# @return [nil] if the current mechanism isn't CURVE or CURVE isn't
# supported
def CURVE_secretkey
CURVE_key(:curve_secretkey)
end


# @return [String] Z85 encoded public key set
# @return [nil] if the current mechanism isn't CURVE or CURVE isn't
# supported
def CURVE_publickey
CURVE_key(:curve_publickey)
end
else
def CURVE_server?
fail NotImplementedError
end
def CURVE_server=(...)
fail NotImplementedError
end
def CURVE_serverkey(...)
fail NotImplementedError
end
def CURVE_serverkey=(...)
fail NotImplementedError
end
def CURVE_secretkey(...)
fail NotImplementedError
end
def CURVE_publickey(...)
fail NotImplementedError
end
end


Expand Down
6 changes: 5 additions & 1 deletion spec/cztop/authenticator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

require_relative '../spec_helper'

unless ::CZMQ::FFI::Zsys.has_curve
warn "Skipping most CZTop::Authenticator specs because CURVE is not available."
end

describe 'CZTop::Authenticator::ZAUTH_FPTR' do
it 'points to a dynamic library symbol' do
assert_kind_of FFI::DynamicLibrary::Symbol, CZTop::Authenticator::ZAUTH_FPTR
end
end

describe CZTop::Authenticator do
describe CZTop::Authenticator, if: ::CZMQ::FFI::Zsys.has_curve do
subject { CZTop::Authenticator.new }
let(:actor) { subject.actor }
after { subject.terminate }
Expand Down
9 changes: 8 additions & 1 deletion spec/cztop/cert_store_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
require 'tmpdir'
require 'pathname'

describe CZTop::CertStore do
unless ::CZMQ::FFI::Zsys.has_curve
warn "Skipping CZTop::Certificate specs because CURVE is not available."
end

describe CZTop::CertStore, if: ::CZMQ::FFI::Zsys.has_curve do
include_examples 'has FFI delegate'

context 'with disk location' do
Expand All @@ -17,6 +21,7 @@
let(:cert1) { CZTop::Certificate.new }

before do
CZTop::Certificate.check_curve_availability
cert1.save(location + 'cert1')
end

Expand All @@ -29,8 +34,10 @@
let(:key) { cert1.public_key(format: :z85) }
it 'finds certificate' do
assert_kind_of CZTop::Certificate, subject.lookup(key)
assert_equal key, subject.lookup(key).public_key(format: :z85)
end
end

context 'with unknown public key' do
let(:key) { CZTop::Certificate.new.public_key(format: :z85) }
it 'returns nil' do
Expand Down
22 changes: 20 additions & 2 deletions spec/cztop/certificate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,32 @@
require 'tmpdir'
require 'pathname'

describe CZTop::Certificate do
unless ::CZMQ::FFI::Zsys.has_curve
warn "Skipping most CZTop::Certificate specs because CURVE is not available."
end


describe CZTop::Certificate, if: !::CZMQ::FFI::Zsys.has_curve do
describe '#initialize' do
it 'raises' do
assert_raises(NotImplementedError) do
CZTop::Certificate.new
end
end
end
end


describe CZTop::Certificate, if: ::CZMQ::FFI::Zsys.has_curve do
include_examples 'has FFI delegate'

context 'with certificate' do
let(:cert) { CZTop::Certificate.new }
let(:ffi_delegate) { cert.ffi_delegate }

describe '#initialize' do
Then { cert }
Then { !cert.zero? }
end

describe '#public_key' do
Expand Down Expand Up @@ -102,7 +120,7 @@
cert[key] = value
end
end
context 'when unsetting', if: has_czmq_drafts? do
context 'when unsetting', if: has_czmq_drafts? && ::CZMQ::FFI::Zsys.has_curve do
Given { cert[key] = value }
When { cert[key] = nil }
Then { cert[key].nil? }
Expand Down
7 changes: 6 additions & 1 deletion spec/cztop/proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

require_relative '../spec_helper'

unless ::CZMQ::FFI::Zsys.has_curve
warn "Skipping some CZTop::Proxy specs because CURVE is not available."
end

describe 'CZTop::Proxy::ZPROXY_FPTR' do
it 'points to a dynamic library symbol' do
assert_kind_of FFI::DynamicLibrary::Symbol, CZTop::Proxy::ZPROXY_FPTR
Expand Down Expand Up @@ -207,7 +211,8 @@
end
end
end
describe '#CURVE!' do

describe '#CURVE!', if: ::CZMQ::FFI::Zsys.has_curve do
let(:cert) { CZTop::Certificate.new }
let(:public_key) { cert.public_key }
let(:secret_key) { cert.secret_key }
Expand Down
8 changes: 6 additions & 2 deletions spec/cztop/socket_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
require 'tmpdir'
require 'pathname'

unless ::CZMQ::FFI::Zsys.has_curve
warn "Skipping some CZTop::Socket specs because CURVE is not available."
end

describe CZTop::Socket do
include_examples 'has FFI delegate'

Expand Down Expand Up @@ -60,7 +64,7 @@
end
end

describe '#CURVE_server!' do
describe '#CURVE_server!', if: ::CZMQ::FFI::Zsys.has_curve do
let(:certificate) { CZTop::Certificate.new }
let(:options) { rep_socket.options }

Expand Down Expand Up @@ -89,7 +93,7 @@
end
end

describe '#CURVE_client!' do
describe '#CURVE_client!', if: ::CZMQ::FFI::Zsys.has_curve do
let(:tmpdir) do
Pathname.new(Dir.mktmpdir('zsock_test'))
end
Expand Down
Loading

0 comments on commit a10ff0d

Please sign in to comment.