network-facade 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/network-facade-ssl +117 -0
- data/lib/network-facade/base.rb +150 -0
- data/lib/network-facade/config.rb +10 -0
- data/lib/network-facade/defaults.rb +14 -0
- data/lib/network-facade/ssl.rb +55 -0
- data/lib/network-facade/tcp.rb +44 -0
- data/lib/network-facade/unix.rb +31 -0
- data/lib/network-facade.rb +66 -0
- metadata +60 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'network-facade'
|
3
|
+
|
4
|
+
def create_ca(opts = {})
|
5
|
+
[ :country, :hostname, :domainname ].each do |o|
|
6
|
+
raise "Missing option #{o}" if opts[o].nil?
|
7
|
+
end
|
8
|
+
|
9
|
+
name = [
|
10
|
+
[ 'C', opts[:country], OpenSSL::ASN1::PRINTABLESTRING ],
|
11
|
+
[ 'O', opts[:domainname], OpenSSL::ASN1::UTF8STRING ],
|
12
|
+
[ 'OU', opts[:hostname], OpenSSL::ASN1::UTF8STRING ],
|
13
|
+
[ 'CN', 'CA' ]
|
14
|
+
]
|
15
|
+
|
16
|
+
cert_opts = {
|
17
|
+
:is_ca => true,
|
18
|
+
:name => name,
|
19
|
+
:comment => 'NetworkFacade Certification Authority',
|
20
|
+
:period => 3650
|
21
|
+
}
|
22
|
+
|
23
|
+
create(cert_opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_cert(opts)
|
27
|
+
[ :country, :hostname, :domainname, :ca_cert, :ca_key ].each do |o|
|
28
|
+
raise "Missing option #{o}" if opts[o].nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
name = [
|
32
|
+
[ 'C', opts[:country], OpenSSL::ASN1::PRINTABLESTRING ],
|
33
|
+
[ 'O', opts[:domainname], OpenSSL::ASN1::UTF8STRING ],
|
34
|
+
[ 'OU', opts[:hostname], OpenSSL::ASN1::UTF8STRING ]
|
35
|
+
]
|
36
|
+
|
37
|
+
opts[:ca_cert] = OpenSSL::X509::Certificate.new(File.read(opts[:ca_cert])) if opts[:ca_cert].is_a?(String)
|
38
|
+
opts[:ca_key] = OpenSSL::PKey::RSA.new(File.read(opts[:ca_key])) if opts[:ca_key].is_a?(String)
|
39
|
+
|
40
|
+
cert_opts = {
|
41
|
+
:name => name,
|
42
|
+
:ca_cert => opts[:ca_cert],
|
43
|
+
:ca_key => opts[:ca_key],
|
44
|
+
:comment => opts[:comment] || 'NetworkFacade Generated Certificate',
|
45
|
+
:period => 365
|
46
|
+
}
|
47
|
+
|
48
|
+
create(cert_opts)
|
49
|
+
end
|
50
|
+
|
51
|
+
def create(opts)
|
52
|
+
key = OpenSSL::PKey::RSA.new(1024)
|
53
|
+
|
54
|
+
cert = OpenSSL::X509::Certificate.new
|
55
|
+
cert.subject = ::OpenSSL::X509::Name.new(opts[:name])
|
56
|
+
cert.issuer = opts[:is_ca] ? cert.subject : opts[:ca_cert].subject
|
57
|
+
cert.not_before = Time.now
|
58
|
+
cert.not_after = Time.now + (opts[:period] * 24 * 60 * 60)
|
59
|
+
cert.public_key = key.public_key
|
60
|
+
cert.serial = opts[:is_ca] ? 0x0 : 0x2
|
61
|
+
cert.version = 2
|
62
|
+
|
63
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
64
|
+
ef.subject_certificate = cert
|
65
|
+
ef.issuer_certificate = opts[:is_ca] ? cert : opts[:ca_cert]
|
66
|
+
|
67
|
+
if opts[:is_ca]
|
68
|
+
cert.extensions = [
|
69
|
+
ef.create_extension('basicConstraints','CA:TRUE', true),
|
70
|
+
ef.create_extension('nsComment', opts[:comment]),
|
71
|
+
ef.create_extension('subjectKeyIdentifier', 'hash'),
|
72
|
+
ef.create_extension('keyUsage', 'cRLSign,keyCertSign', true)
|
73
|
+
]
|
74
|
+
cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always'))
|
75
|
+
else
|
76
|
+
cert.extensions = [
|
77
|
+
ef.create_extension('basicConstraints','CA:FALSE', true),
|
78
|
+
ef.create_extension('nsComment', opts[:comment]),
|
79
|
+
ef.create_extension('subjectKeyIdentifier', 'hash'),
|
80
|
+
]
|
81
|
+
cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always'))
|
82
|
+
end
|
83
|
+
|
84
|
+
cert.sign(opts[:is_ca] ? key : opts[:ca_key], OpenSSL::Digest::SHA1.new)
|
85
|
+
|
86
|
+
{ :key => key, :cert => cert }
|
87
|
+
end
|
88
|
+
|
89
|
+
# Authority
|
90
|
+
|
91
|
+
CA = {
|
92
|
+
:country => 'FR',
|
93
|
+
:hostname => 'demo',
|
94
|
+
:domainname => 'example.com'
|
95
|
+
}
|
96
|
+
|
97
|
+
cert = create_ca(CA)
|
98
|
+
File.open('ca.key', 'w') { |fd| fd.puts cert[:key] }
|
99
|
+
File.open('ca.cert', 'w') { |fd| fd.puts cert[:cert].to_pem }
|
100
|
+
|
101
|
+
# Client / Server
|
102
|
+
|
103
|
+
OPTS = {
|
104
|
+
:country => CA[:country],
|
105
|
+
:hostname => CA[:hostname],
|
106
|
+
:domainname => CA[:domainname],
|
107
|
+
:ca_cert => 'ca.cert',
|
108
|
+
:ca_key => 'ca.key'
|
109
|
+
}
|
110
|
+
|
111
|
+
cert = create_cert(OPTS)
|
112
|
+
File.open('client.key', 'w') { |fd| fd.puts cert[:key] }
|
113
|
+
File.open('client.cert', 'w') { |fd| fd.puts cert[:cert].to_pem }
|
114
|
+
|
115
|
+
cert = create_cert(OPTS)
|
116
|
+
File.open('server.key', 'w') { |fd| fd.puts cert[:key] }
|
117
|
+
File.open('server.cert', 'w') { |fd| fd.puts cert[:cert].to_pem }
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module NetworkFacade
|
2
|
+
def self.log=(log)
|
3
|
+
@@log = log.is_a?(IO) ? Logger.new(log) : log
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.log(level, msg, context = nil)
|
7
|
+
return unless defined? @@log
|
8
|
+
if msg.is_a? Array
|
9
|
+
msg.each { |l| @@log << " #{l}\n"}
|
10
|
+
elsif msg.is_a? Exception
|
11
|
+
@@log << " #{msg.message} (#{msg.class})\n"
|
12
|
+
msg.backtrace.each { |l| @@log << " #{l}\n"}
|
13
|
+
else
|
14
|
+
if context.nil?
|
15
|
+
@@log.send(level, msg)
|
16
|
+
else
|
17
|
+
@@log.send(level, context, &Proc.new { msg })
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Base
|
23
|
+
|
24
|
+
class Client
|
25
|
+
def self.uri=(uri)
|
26
|
+
@@uri = uri
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.inherited(klass)
|
30
|
+
@@klass ||= {}
|
31
|
+
if defined? @@uri and not @@uri.nil?
|
32
|
+
@@klass[klass] = URI.parse(@@uri)
|
33
|
+
@@klass[klass].path = '/' + klass.name.downcase
|
34
|
+
NetworkFacade.log(:debug, "#{klass} is bound to #{@@klass[klass]}")
|
35
|
+
end
|
36
|
+
@@uri = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(options = {})
|
40
|
+
@options = options
|
41
|
+
@uri ||= @options[:uri] || @@klass[self.class] ||
|
42
|
+
URI::Generic.new('nf', nil, nil, nil, nil, '/' + self.class.name.downcase, nil, nil, nil)
|
43
|
+
@uri.host = @options[:host] if @options[:host]
|
44
|
+
@uri.port = @options[:port] if @options[:port]
|
45
|
+
@uri.path = @options[:path] if @options[:path]
|
46
|
+
@uri.query = @options[:query] if @options[:query]
|
47
|
+
@uri.userinfo = @options[:userinfo] if @options[:userinfo]
|
48
|
+
@mutex = Mutex.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def method_missing(name, *args)
|
52
|
+
NetworkFacade.log(:debug, "Method called with #{args.inspect}", "#{self.class}##{name}")
|
53
|
+
begin
|
54
|
+
data = Marshal.dump([@uri.path[1..-1], name, args])
|
55
|
+
size = [data.size].pack('N')
|
56
|
+
@client.write(size)
|
57
|
+
@client.write(data)
|
58
|
+
size = @client.read(4).unpack('N').first
|
59
|
+
data = @client.read(size)
|
60
|
+
result = Marshal.load(data)
|
61
|
+
if result.is_a? Exception
|
62
|
+
NetworkFacade.log(:info, "Exception occured : #{result.inspect}", "#{self.class}##{name}")
|
63
|
+
result.backtrace.collect! do |line|
|
64
|
+
@uri.to_s + '/' + line
|
65
|
+
end
|
66
|
+
raise result
|
67
|
+
end
|
68
|
+
result
|
69
|
+
rescue Errno::EPIPE, EOFError, Errno::EINVAL, Errno::ECONNRESET
|
70
|
+
NetworkFacade.log(:warn, "#{$!.inspect} occured, re-connecting...", "#{self.class}##{name}")
|
71
|
+
connect
|
72
|
+
retry
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Server
|
78
|
+
def initialize(options = {})
|
79
|
+
@options = options
|
80
|
+
@fd = [@options[:server]]
|
81
|
+
@objs = {}
|
82
|
+
end
|
83
|
+
|
84
|
+
def accept
|
85
|
+
NetworkFacade.log(:info, "Accepting new client")
|
86
|
+
raise "Default Server#accept method"
|
87
|
+
end
|
88
|
+
|
89
|
+
def add(obj)
|
90
|
+
id = obj.class.name.downcase
|
91
|
+
NetworkFacade.log(:info, "Adding new object #{obj.inspect} at /#{id}")
|
92
|
+
@objs[id] = obj
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
def client_id(client)
|
97
|
+
"0x%08x" % client.object_id
|
98
|
+
end
|
99
|
+
|
100
|
+
def start
|
101
|
+
loop do
|
102
|
+
readable, writable, errors, timeout = IO.select(@fd)
|
103
|
+
begin
|
104
|
+
if readable.include?(@options[:server])
|
105
|
+
accept
|
106
|
+
readable.delete(@options[:server])
|
107
|
+
end
|
108
|
+
rescue Exception
|
109
|
+
NetworkFacade.log(:warn, "An error occured when accapting new client")
|
110
|
+
NetworkFacade.log(:warn, $!)
|
111
|
+
next
|
112
|
+
end
|
113
|
+
|
114
|
+
readable.each do |client|
|
115
|
+
size = nil
|
116
|
+
data = nil
|
117
|
+
begin
|
118
|
+
size = client.read(4)
|
119
|
+
raise EOFError if size.nil?
|
120
|
+
size = size.unpack('N').first
|
121
|
+
data = Marshal.load(client.read(size))
|
122
|
+
result = nil
|
123
|
+
begin
|
124
|
+
if @objs[data[0]].respond_to? data[1]
|
125
|
+
NetworkFacade.log(:info, "Call method #{data[1].inspect} with #{data[2].inspect}", client_id(client))
|
126
|
+
result = @objs[data[0]].send(data[1], *data[2])
|
127
|
+
else
|
128
|
+
NetworkFacade.log(:info, "Call unknown method #{data[1].inspect}", client_id(client))
|
129
|
+
end
|
130
|
+
rescue Exception
|
131
|
+
result = $!
|
132
|
+
NetworkFacade.log(:info, "Error occured when executing #{data[1].inspect} with #{data[2].inspect}", client_id(client))
|
133
|
+
NetworkFacade.log(:info, $!)
|
134
|
+
end
|
135
|
+
result = Marshal.dump(result)
|
136
|
+
client.write([result.size].pack('N'))
|
137
|
+
client.write(result)
|
138
|
+
rescue Exception
|
139
|
+
NetworkFacade.log(:info, "Close connection", client_id(client))
|
140
|
+
client.close
|
141
|
+
@fd.delete(client)
|
142
|
+
GC.start
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module NetworkFacade
|
2
|
+
NAME = 'Network-Facade'
|
3
|
+
VERSION = '0.1'
|
4
|
+
COPYRIGHT = 'Copyright (C) 2007 Florent Solt'
|
5
|
+
DESC = 'Object-oriented netwotk facade'
|
6
|
+
AUTHOR = 'Florent Solt'
|
7
|
+
EMAIL = 'florent@solt.biz'
|
8
|
+
HOMEPAGE = 'http://network-facade.rubyforge.org'
|
9
|
+
LICENSE = 'BSD'
|
10
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module NetworkFacade
|
4
|
+
class SSL
|
5
|
+
|
6
|
+
def self.Client(uri = nil)
|
7
|
+
Client.uri = uri
|
8
|
+
Client
|
9
|
+
end
|
10
|
+
|
11
|
+
PORT = 5043
|
12
|
+
|
13
|
+
class Client < Base::Client
|
14
|
+
def initialize(options = {})
|
15
|
+
[:key, :cert, :ca].each do |o|
|
16
|
+
raise "Missing option #{o}" if options[o].nil?
|
17
|
+
raise "File does not exists #{options[o]}" unless File.exists?(options[o])
|
18
|
+
end
|
19
|
+
super
|
20
|
+
@ctx = OpenSSL::SSL::SSLContext.new
|
21
|
+
@ctx.key = OpenSSL::PKey::RSA.new File.read(@options[:key])
|
22
|
+
@ctx.cert = OpenSSL::X509::Certificate.new File.read(@options[:cert])
|
23
|
+
@ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
24
|
+
@ctx.ca_file = @options[:ca]
|
25
|
+
@client = TCPSocket.new(@uri.host || 'localhost', @uri.port || PORT)
|
26
|
+
@client = OpenSSL::SSL::SSLSocket.new(@client, @ctx)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Server < TCP::Server
|
31
|
+
def initialize(options = {})
|
32
|
+
if options[:server].nil?
|
33
|
+
[:key, :cert, :ca].each do |o|
|
34
|
+
raise "Missing option #{o}" if options[o].nil?
|
35
|
+
raise "File does not exists #{options[o]}" unless File.exists?(options[o])
|
36
|
+
end
|
37
|
+
options[:port] ||= PORT
|
38
|
+
options[:host] ||= '0.0.0.0'
|
39
|
+
@ctx = OpenSSL::SSL::SSLContext.new
|
40
|
+
@ctx.key = OpenSSL::PKey::RSA.new File.read(options[:key])
|
41
|
+
@ctx.cert = OpenSSL::X509::Certificate.new File.read(options[:cert])
|
42
|
+
@ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
43
|
+
@ctx.ca_file = options[:ca]
|
44
|
+
options[:server] = TCPServer.new(options[:host], options[:port])
|
45
|
+
@ssl = OpenSSL::SSL::SSLSocket.new(options[:server], @ctx)
|
46
|
+
options[:server] = @ssl.to_io
|
47
|
+
end
|
48
|
+
super(options)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module NetworkFacade
|
2
|
+
module TCP
|
3
|
+
|
4
|
+
def self.Client(uri = nil)
|
5
|
+
Client.uri = uri
|
6
|
+
Client
|
7
|
+
end
|
8
|
+
|
9
|
+
PORT = 5042
|
10
|
+
|
11
|
+
class Client < Base::Client
|
12
|
+
def initialize(options = {})
|
13
|
+
super
|
14
|
+
@options[:no_delay] ||= true
|
15
|
+
@client ||= TCPSocket.new(@uri.host || 'localhost', @uri.port || PORT)
|
16
|
+
@client.setsockopt(Socket::SOL_TCP, Socket::TCP_NODELAY, 1) if @options[:no_delay]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Server < Base::Server
|
21
|
+
def initialize(options = {})
|
22
|
+
options[:port] ||= PORT
|
23
|
+
options[:host] ||= '0.0.0.0'
|
24
|
+
options[:no_delay] ||= true
|
25
|
+
options[:close_exec] ||= true
|
26
|
+
options[:server] ||= TCPServer.new(options[:host], options[:port])
|
27
|
+
super(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def accept
|
31
|
+
client = @options[:server].accept
|
32
|
+
NetworkFacade.log(:info, "Accept", client.peeraddr[2])
|
33
|
+
client.setsockopt(Socket::SOL_TCP, Socket::TCP_NODELAY, 1) if @options[:no_delay]
|
34
|
+
client.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if @options[:close_exec]
|
35
|
+
@fd << client
|
36
|
+
end
|
37
|
+
|
38
|
+
def client_id(client)
|
39
|
+
client.peeraddr[2]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module NetworkFacade
|
2
|
+
module Unix
|
3
|
+
|
4
|
+
PATH = '/tmp/nf-socket'
|
5
|
+
|
6
|
+
class Client < Base::Client
|
7
|
+
def initialize(options = {})
|
8
|
+
super
|
9
|
+
options[:path] ||= PATH
|
10
|
+
@client = UNIXSocket.open(options[:path])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Server < Base::Server
|
15
|
+
def initialize(options = {})
|
16
|
+
options[:path] ||= PATH
|
17
|
+
options[:close_exec] ||= true
|
18
|
+
File.unlink(PATH)
|
19
|
+
options[:server] ||= UNIXServer.open(options[:path])
|
20
|
+
super(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def accept
|
24
|
+
client = @options[:server].accept
|
25
|
+
client.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if @options[:close_exec]
|
26
|
+
@fd << client
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'uri'
|
3
|
+
require 'fcntl'
|
4
|
+
require 'thread'
|
5
|
+
require 'logger'
|
6
|
+
require 'network-facade/config'
|
7
|
+
require 'network-facade/base'
|
8
|
+
require 'network-facade/tcp'
|
9
|
+
require 'network-facade/unix'
|
10
|
+
require 'network-facade/ssl'
|
11
|
+
require 'network-facade/defaults'
|
12
|
+
|
13
|
+
if __FILE__ == $0
|
14
|
+
NetworkFacade.log = STDERR
|
15
|
+
|
16
|
+
case ARGV.first
|
17
|
+
#=======================<client>==============================#
|
18
|
+
when 'client-tcp-uri'
|
19
|
+
class Foo < NetworkFacade::Client 'nf://backoffice:5042/?hu=dtc'
|
20
|
+
end
|
21
|
+
f = Foo.new
|
22
|
+
p f.bar
|
23
|
+
when 'client-tcp-class'
|
24
|
+
class Foo < NetworkFacade::Client
|
25
|
+
end
|
26
|
+
f = Foo.new(:host => 'dev', :port => 5042)
|
27
|
+
p f.bar
|
28
|
+
when 'client-unix'
|
29
|
+
class Foo < NetworkFacade::Unix::Client
|
30
|
+
end
|
31
|
+
f = Foo.new
|
32
|
+
p f.bar
|
33
|
+
when 'client-ssl'
|
34
|
+
class Foo < NetworkFacade::SSL::Client 'nf://installclick:5044'
|
35
|
+
end
|
36
|
+
f = Foo.new(:ca => '../cert/ca.cert',
|
37
|
+
:cert => '../cert/client.cert',
|
38
|
+
:key => '../cert/client.key')
|
39
|
+
p f.bar
|
40
|
+
#=======================</client>=============================#
|
41
|
+
else
|
42
|
+
class Foo
|
43
|
+
def bar
|
44
|
+
42
|
45
|
+
end
|
46
|
+
def error
|
47
|
+
raise "Error"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
case ARGV.first
|
51
|
+
#=======================<server>==============================#
|
52
|
+
when 'server-tcp'
|
53
|
+
NetworkFacade::Server.new.add(Foo.new).start
|
54
|
+
when 'server-unix'
|
55
|
+
NetworkFacade::Unix::Server.new.add(Foo.new).start
|
56
|
+
when 'server-ssl'
|
57
|
+
s = NetworkFacade::SSL::Server.new(
|
58
|
+
:port => 5044,
|
59
|
+
:ca => '../cert/ca.cert',
|
60
|
+
:cert => '../cert/server.cert',
|
61
|
+
:key => '../cert/server.key')
|
62
|
+
s.add(Foo.new).start
|
63
|
+
#=======================</server>=============================#
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: network-facade
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2007-05-02 00:00:00 +02:00
|
8
|
+
summary: Object-oriented netwotk facade
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: florent@solt.biz
|
12
|
+
homepage: http://network-facade.rubyforge.org
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Florent Solt
|
31
|
+
files:
|
32
|
+
- lib/network-facade/unix.rb
|
33
|
+
- lib/network-facade/tcp.rb
|
34
|
+
- lib/network-facade/config.rb
|
35
|
+
- lib/network-facade/base.rb
|
36
|
+
- lib/network-facade/defaults.rb
|
37
|
+
- lib/network-facade/ssl.rb
|
38
|
+
- lib/network-facade.rb
|
39
|
+
test_files: []
|
40
|
+
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
executables:
|
46
|
+
- network-facade-ssl
|
47
|
+
extensions: []
|
48
|
+
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
dependencies:
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: xmlobject
|
54
|
+
version_requirement:
|
55
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 0.0.0
|
60
|
+
version:
|