remailer 0.5.2 → 0.9.1
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 +7 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +19 -0
- data/{README.rdoc → README.md} +12 -11
- data/Rakefile +21 -11
- data/VERSION +1 -1
- data/lib/remailer/abstract_connection.rb +36 -20
- data/lib/remailer/imap/client.rb +1 -1
- data/lib/remailer/interpreter.rb +40 -19
- data/lib/remailer/interpreter/state_proxy.rb +1 -1
- data/lib/remailer/smtp/client.rb +20 -26
- data/lib/remailer/smtp/client/interpreter.rb +85 -12
- data/lib/remailer/smtp/server.rb +9 -4
- data/lib/remailer/smtp/server/interpreter.rb +16 -15
- data/lib/remailer/smtp/server/transaction.rb +9 -2
- data/lib/remailer/socks5/client/interpreter.rb +18 -13
- data/remailer.gemspec +33 -23
- data/test/bin/exercise +115 -0
- data/test/config.example.yml +15 -0
- data/test/config.rb +41 -0
- data/test/helper.rb +42 -23
- data/test/unit/remailer_imap_client_interpreter_test.rb +2 -2
- data/test/unit/remailer_imap_client_test.rb +10 -12
- data/test/unit/remailer_interpreter_state_proxy_test.rb +14 -14
- data/test/unit/remailer_interpreter_test.rb +36 -28
- data/test/unit/remailer_smtp_client_interpreter_test.rb +80 -33
- data/test/unit/remailer_smtp_client_test.rb +53 -55
- data/test/unit/remailer_smtp_server_test.rb +24 -18
- data/test/unit/remailer_socks5_client_interpreter_test.rb +71 -10
- data/test/unit/remailer_test.rb +2 -2
- metadata +66 -24
- data/test/config.example.rb +0 -17
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'set'
|
3
|
+
|
1
4
|
class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
2
5
|
# == Constants ============================================================
|
3
6
|
|
@@ -22,7 +25,7 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
22
25
|
# Encodes the given data for an RFC5321-compliant stream where lines with
|
23
26
|
# leading period chracters are escaped.
|
24
27
|
def self.encode_data(data)
|
25
|
-
data.gsub(
|
28
|
+
data.gsub(/\r?\n/, "\r\n").gsub(/\r\n\./, "\r\n..")
|
26
29
|
end
|
27
30
|
|
28
31
|
# Encodes a string in Base64 as a single line
|
@@ -37,6 +40,10 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
37
40
|
end
|
38
41
|
|
39
42
|
state :initialized do
|
43
|
+
enter do
|
44
|
+
@tls = false
|
45
|
+
end
|
46
|
+
|
40
47
|
interpret(220) do |message, continues|
|
41
48
|
message_parts = message.split(/\s+/)
|
42
49
|
delegate.remote = message_parts.first
|
@@ -68,6 +75,8 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
68
75
|
state :helo do
|
69
76
|
enter do
|
70
77
|
delegate.send_line("HELO #{delegate.hostname}")
|
78
|
+
|
79
|
+
delegate.auth_support = Set.new(%i[ plain ])
|
71
80
|
end
|
72
81
|
|
73
82
|
interpret(250) do
|
@@ -85,20 +94,17 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
85
94
|
end
|
86
95
|
|
87
96
|
interpret(250) do |message, continues|
|
88
|
-
message_parts = message.split(/\s+/)
|
97
|
+
directive, *message_parts = message.split(/\s+/)
|
89
98
|
|
90
|
-
case (
|
99
|
+
case (directive.to_s.upcase)
|
91
100
|
when 'SIZE'
|
92
|
-
delegate.max_size = message_parts[
|
101
|
+
delegate.max_size = message_parts[0].to_i
|
93
102
|
when 'PIPELINING'
|
94
103
|
delegate.pipelining = true
|
95
104
|
when 'STARTTLS'
|
96
105
|
delegate.tls_support = true
|
97
106
|
when 'AUTH'
|
98
|
-
delegate.auth_support = message_parts
|
99
|
-
h[v] = true
|
100
|
-
h
|
101
|
-
end
|
107
|
+
delegate.auth_support = Set.new(message_parts.map(&:downcase).map(&:to_sym))
|
102
108
|
end
|
103
109
|
|
104
110
|
unless (continues)
|
@@ -140,7 +146,19 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
140
146
|
|
141
147
|
state :auth do
|
142
148
|
enter do
|
143
|
-
|
149
|
+
if (delegate.auth_support?(:plain))
|
150
|
+
delegate.send_line(
|
151
|
+
'AUTH PLAIN %s' % [
|
152
|
+
self.class.encode_authentication(
|
153
|
+
delegate.options[:username],
|
154
|
+
delegate.options[:password]
|
155
|
+
)
|
156
|
+
]
|
157
|
+
)
|
158
|
+
elsif (delegate.auth_support&.include?(:login))
|
159
|
+
delegate.send_line('AUTH LOGIN')
|
160
|
+
enter_state(:auth_username)
|
161
|
+
end
|
144
162
|
end
|
145
163
|
|
146
164
|
interpret(235) do
|
@@ -158,7 +176,62 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
158
176
|
end
|
159
177
|
end
|
160
178
|
end
|
161
|
-
|
179
|
+
|
180
|
+
state :auth_username do
|
181
|
+
interpret(334) do
|
182
|
+
delegate.send_line(Base64.strict_encode64(delegate.options[:username]))
|
183
|
+
|
184
|
+
enter_state(:auth_password)
|
185
|
+
end
|
186
|
+
|
187
|
+
interpret(535) do |reply_message, continues|
|
188
|
+
handle_reply_continuation(535, reply_message, continues) do |reply_code, reply_message|
|
189
|
+
@error = reply_message
|
190
|
+
|
191
|
+
delegate.debug_notification(:error, "[#{@state}] #{reply_code} #{reply_message}")
|
192
|
+
delegate.error_notification(reply_code, reply_message)
|
193
|
+
|
194
|
+
enter_state(:quit)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
state :auth_password do
|
200
|
+
interpret(334) do
|
201
|
+
delegate.send_line(Base64.strict_encode64(delegate.options[:password]))
|
202
|
+
|
203
|
+
enter_state(:auth_acknowledge)
|
204
|
+
end
|
205
|
+
|
206
|
+
interpret(535) do |reply_message, continues|
|
207
|
+
handle_reply_continuation(535, reply_message, continues) do |reply_code, reply_message|
|
208
|
+
@error = reply_message
|
209
|
+
|
210
|
+
delegate.debug_notification(:error, "[#{@state}] #{reply_code} #{reply_message}")
|
211
|
+
delegate.error_notification(reply_code, reply_message)
|
212
|
+
|
213
|
+
enter_state(:quit)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
state :auth_acknowledge do
|
219
|
+
interpret(235) do
|
220
|
+
enter_state(:established)
|
221
|
+
end
|
222
|
+
|
223
|
+
interpret(535) do |reply_message, continues|
|
224
|
+
handle_reply_continuation(535, reply_message, continues) do |reply_code, reply_message|
|
225
|
+
@error = reply_message
|
226
|
+
|
227
|
+
delegate.debug_notification(:error, "[#{@state}] #{reply_code} #{reply_message}")
|
228
|
+
delegate.error_notification(reply_code, reply_message)
|
229
|
+
|
230
|
+
enter_state(:quit)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
162
235
|
state :established do
|
163
236
|
enter do
|
164
237
|
delegate.connect_notification(true)
|
@@ -251,7 +324,7 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
251
324
|
end
|
252
325
|
end
|
253
326
|
|
254
|
-
interpret(
|
327
|
+
interpret(400..599) do |reply_code, reply_message, continues|
|
255
328
|
handle_reply_continuation(reply_code, reply_message, continues) do |reply_code, reply_message|
|
256
329
|
delegate_call(:after_message_sent, reply_code, reply_message)
|
257
330
|
|
@@ -281,7 +354,7 @@ class Remailer::SMTP::Client::Interpreter < Remailer::Interpreter
|
|
281
354
|
# Ensure that a blank line is sent after the last bit of email content
|
282
355
|
# to ensure that the dot is on its own line.
|
283
356
|
delegate.send_line
|
284
|
-
delegate.send_line(
|
357
|
+
delegate.send_line('.')
|
285
358
|
end
|
286
359
|
|
287
360
|
default do |reply_code, reply_message, continues|
|
data/lib/remailer/smtp/server.rb
CHANGED
@@ -19,7 +19,7 @@ class Remailer::SMTP::Server < EventMachine::Protocols::LineAndTextProtocol
|
|
19
19
|
|
20
20
|
attr_accessor :logger
|
21
21
|
attr_reader :server_name, :quirks
|
22
|
-
attr_reader :remote_ip, :remote_port
|
22
|
+
attr_reader :remote_ip, :remote_port, :remote_name
|
23
23
|
attr_reader :local_ip, :local_port
|
24
24
|
attr_reader :local_config
|
25
25
|
|
@@ -60,6 +60,11 @@ class Remailer::SMTP::Server < EventMachine::Protocols::LineAndTextProtocol
|
|
60
60
|
|
61
61
|
@server_name = @options[:server_name] || self.class.hostname(@local_ip) || @local_ip
|
62
62
|
|
63
|
+
@logger = nil
|
64
|
+
@remote_host = nil
|
65
|
+
@tls_support = false
|
66
|
+
@interpreter_class = options && options[:interpreter] || Interpreter
|
67
|
+
|
63
68
|
log(:debug, "Connection from #{@remote_ip}:#{@remote_port} to #{@local_ip}:#{@local_port}")
|
64
69
|
|
65
70
|
@on_transaction = @options[:on_transaction]
|
@@ -69,15 +74,15 @@ class Remailer::SMTP::Server < EventMachine::Protocols::LineAndTextProtocol
|
|
69
74
|
def post_init
|
70
75
|
super
|
71
76
|
|
72
|
-
@interpreter =
|
77
|
+
@interpreter = @interpreter_class.new(delegate: self)
|
73
78
|
|
74
79
|
if (@on_connect)
|
75
80
|
@on_connect.call(@remote_ip)
|
76
81
|
end
|
77
82
|
end
|
78
83
|
|
79
|
-
def on_transaction
|
80
|
-
@on_transaction =
|
84
|
+
def on_transaction(&block)
|
85
|
+
@on_transaction = block
|
81
86
|
end
|
82
87
|
|
83
88
|
def receive_line(line)
|
@@ -40,7 +40,7 @@ class Remailer::SMTP::Server::Interpreter < Remailer::Interpreter
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
interpret(/^\s*HELO\s+(\S+)\s*$/) do |remote_host|
|
43
|
+
interpret(/^\s*HELO\s+(\S+)\s*$/i) do |remote_host|
|
44
44
|
delegate.validate_hostname(remote_host) do |valid|
|
45
45
|
if (valid)
|
46
46
|
delegate.log(:debug, "#{delegate.remote_ip}:#{delegate.remote_port} to #{delegate.local_ip}:#{delegate.local_port} Accepting connection from #{remote_host}")
|
@@ -54,7 +54,7 @@ class Remailer::SMTP::Server::Interpreter < Remailer::Interpreter
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
interpret(/^\s*MAIL\s+FROM:\s*<([^>]+)>\s*/) do |address|
|
57
|
+
interpret(/^\s*MAIL\s+FROM:\s*<([^>]+)>\s*/i) do |address|
|
58
58
|
if (Remailer::EmailAddress.valid?(address))
|
59
59
|
accept, message = will_accept_sender(address)
|
60
60
|
|
@@ -68,7 +68,7 @@ class Remailer::SMTP::Server::Interpreter < Remailer::Interpreter
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
interpret(/^\s*RCPT\s+TO:\s*<([^>]+)>\s*/) do |address|
|
71
|
+
interpret(/^\s*RCPT\s+TO:\s*<([^>]+)>\s*/i) do |address|
|
72
72
|
if (@transaction.sender)
|
73
73
|
if (Remailer::EmailAddress.valid?(address))
|
74
74
|
accept, message = will_accept_recipient(address)
|
@@ -87,24 +87,24 @@ class Remailer::SMTP::Server::Interpreter < Remailer::Interpreter
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
interpret(/^\s*AUTH\s+PLAIN\s+(.*)\s*$/) do |auth|
|
90
|
+
interpret(/^\s*AUTH\s+PLAIN\s+(.*)\s*$/i) do |auth|
|
91
91
|
# 235 2.7.0 Authentication successful
|
92
|
-
delegate.send("235
|
92
|
+
delegate.send("235 If you insist")
|
93
93
|
end
|
94
94
|
|
95
|
-
interpret(/^\s*AUTH\s+PLAIN\s*$/) do
|
95
|
+
interpret(/^\s*AUTH\s+PLAIN\s*$/i) do
|
96
96
|
# Multi-line authentication method
|
97
97
|
enter_state(:auth_plain)
|
98
98
|
end
|
99
99
|
|
100
|
-
interpret(/^\s*STARTTLS\s*$/) do
|
100
|
+
interpret(/^\s*STARTTLS\s*$/i) do
|
101
101
|
if (@tls_started)
|
102
102
|
delegate.send_line("454 TLS already started")
|
103
103
|
elsif (delegate.tls?)
|
104
104
|
delegate.send_line("220 TLS ready to start")
|
105
105
|
delegate.start_tls(
|
106
|
-
:
|
107
|
-
:
|
106
|
+
private_key_file: Remailer::SMTP::Server.private_key_path,
|
107
|
+
cert_chain_file: Remailer::SMTP::Server.ssl_cert_path
|
108
108
|
)
|
109
109
|
|
110
110
|
@tls_started = true
|
@@ -113,27 +113,27 @@ class Remailer::SMTP::Server::Interpreter < Remailer::Interpreter
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
interpret(/^\s*DATA\s*$/) do
|
116
|
+
interpret(/^\s*DATA\s*$/i) do
|
117
117
|
if (@transaction.sender)
|
118
118
|
else
|
119
|
-
delegate.send_line("503
|
119
|
+
delegate.send_line("503 Valid RCPT command must precede DATA")
|
120
120
|
end
|
121
121
|
|
122
122
|
enter_state(:data)
|
123
123
|
delegate.send_line("354 Supply message data")
|
124
124
|
end
|
125
125
|
|
126
|
-
interpret(/^\s*NOOP\s*$/) do |remote_host|
|
126
|
+
interpret(/^\s*NOOP\s*$/i) do |remote_host|
|
127
127
|
delegate.send_line("250 OK")
|
128
128
|
end
|
129
129
|
|
130
|
-
interpret(/^\s*RSET\s*$/) do |remote_host|
|
130
|
+
interpret(/^\s*RSET\s*$/i) do |remote_host|
|
131
131
|
delegate.send_line("250 Reset OK")
|
132
132
|
|
133
133
|
enter_state(:reset)
|
134
134
|
end
|
135
135
|
|
136
|
-
interpret(/^\s*QUIT\s*$/) do
|
136
|
+
interpret(/^\s*QUIT\s*$/i) do
|
137
137
|
delegate.send_line("221 #{delegate.server_name} closing connection")
|
138
138
|
|
139
139
|
delegate.close_connection(true)
|
@@ -142,6 +142,8 @@ class Remailer::SMTP::Server::Interpreter < Remailer::Interpreter
|
|
142
142
|
|
143
143
|
state :data do
|
144
144
|
interpret(/^\.$/) do
|
145
|
+
@transaction.remote_ip = delegate.remote_ip
|
146
|
+
|
145
147
|
accept, message = will_accept_transaction(@transaction)
|
146
148
|
|
147
149
|
if (accept)
|
@@ -159,7 +161,6 @@ class Remailer::SMTP::Server::Interpreter < Remailer::Interpreter
|
|
159
161
|
|
160
162
|
default do |line|
|
161
163
|
# RFC5321 4.5.2 - Leading dot is removed if line has content
|
162
|
-
|
163
164
|
@transaction.data << (line.sub(/^\./, '') << Remailer::Constants::CRLF)
|
164
165
|
end
|
165
166
|
end
|
@@ -1,11 +1,18 @@
|
|
1
1
|
class Remailer::SMTP::Server::Transaction
|
2
2
|
# == Constants ============================================================
|
3
3
|
|
4
|
-
ATTRIBUTES = [
|
4
|
+
ATTRIBUTES = [
|
5
|
+
:sender,
|
6
|
+
:remote_ip,
|
7
|
+
:remote_name,
|
8
|
+
:auth,
|
9
|
+
:recipients,
|
10
|
+
:data
|
11
|
+
].freeze
|
5
12
|
|
6
13
|
# == Properties ===========================================================
|
7
14
|
|
8
|
-
attr_accessor
|
15
|
+
attr_accessor(*ATTRIBUTES)
|
9
16
|
|
10
17
|
# == Class Methods ========================================================
|
11
18
|
|
@@ -5,14 +5,14 @@ class Remailer::SOCKS5::Client::Interpreter < Remailer::Interpreter
|
|
5
5
|
SOCKS5_VERSION = 5
|
6
6
|
|
7
7
|
SOCKS5_METHOD = {
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
8
|
+
no_auth: 0,
|
9
|
+
gssapi: 1,
|
10
|
+
username_password: 2
|
11
11
|
}.freeze
|
12
12
|
|
13
13
|
SOCKS5_COMMAND = {
|
14
|
-
:
|
15
|
-
:
|
14
|
+
connect: 1,
|
15
|
+
bind: 2
|
16
16
|
}.freeze
|
17
17
|
|
18
18
|
SOCKS5_REPLY = {
|
@@ -28,9 +28,9 @@ class Remailer::SOCKS5::Client::Interpreter < Remailer::Interpreter
|
|
28
28
|
}.freeze
|
29
29
|
|
30
30
|
SOCKS5_ADDRESS_TYPE = {
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
31
|
+
ipv4: 1,
|
32
|
+
domainname: 3,
|
33
|
+
ipv6: 4
|
34
34
|
}.freeze
|
35
35
|
|
36
36
|
# == State Mapping ========================================================
|
@@ -60,7 +60,7 @@ class Remailer::SOCKS5::Client::Interpreter < Remailer::Interpreter
|
|
60
60
|
|
61
61
|
parse do |s|
|
62
62
|
if (s.length >= 2)
|
63
|
-
|
63
|
+
_version, method = s.slice!(0,2).unpack('CC')
|
64
64
|
|
65
65
|
method
|
66
66
|
end
|
@@ -109,14 +109,14 @@ class Remailer::SOCKS5::Client::Interpreter < Remailer::Interpreter
|
|
109
109
|
|
110
110
|
parse do |s|
|
111
111
|
if (s.length >= 10)
|
112
|
-
|
112
|
+
_version, reply, _reserved, address_type, address, port = s.slice!(0,10).unpack('CCCCNn')
|
113
113
|
|
114
114
|
[
|
115
115
|
reply,
|
116
116
|
{
|
117
|
-
:
|
118
|
-
:
|
119
|
-
:
|
117
|
+
address: address,
|
118
|
+
port: port,
|
119
|
+
address_type: address_type
|
120
120
|
}
|
121
121
|
]
|
122
122
|
end
|
@@ -128,6 +128,7 @@ class Remailer::SOCKS5::Client::Interpreter < Remailer::Interpreter
|
|
128
128
|
|
129
129
|
default do |reply|
|
130
130
|
@reply = reply
|
131
|
+
|
131
132
|
enter_state(:failed)
|
132
133
|
end
|
133
134
|
end
|
@@ -189,4 +190,8 @@ class Remailer::SOCKS5::Client::Interpreter < Remailer::Interpreter
|
|
189
190
|
def label
|
190
191
|
'SOCKS5'
|
191
192
|
end
|
193
|
+
|
194
|
+
def finished?
|
195
|
+
self.state == :connected
|
196
|
+
end
|
192
197
|
end
|
data/remailer.gemspec
CHANGED
@@ -1,23 +1,28 @@
|
|
1
|
-
# Generated by
|
1
|
+
# Generated by juwelier
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit
|
3
|
+
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: remailer 0.9.1 ruby lib
|
5
6
|
|
6
7
|
Gem::Specification.new do |s|
|
7
|
-
s.name = "remailer"
|
8
|
-
s.version = "0.
|
8
|
+
s.name = "remailer".freeze
|
9
|
+
s.version = "0.9.1"
|
9
10
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.
|
14
|
-
s.
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib".freeze]
|
13
|
+
s.authors = ["Scott Tadman".freeze]
|
14
|
+
s.date = "2020-09-22"
|
15
|
+
s.description = "EventMachine Mail Agent for SMTP and IMAP".freeze
|
16
|
+
s.email = "tadman@postageapp.com".freeze
|
15
17
|
s.extra_rdoc_files = [
|
16
|
-
"
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.md"
|
17
20
|
]
|
18
21
|
s.files = [
|
19
22
|
".document",
|
20
|
-
"
|
23
|
+
"Gemfile",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.md",
|
21
26
|
"Rakefile",
|
22
27
|
"VERSION",
|
23
28
|
"lib/remailer.rb",
|
@@ -42,7 +47,9 @@ Gem::Specification.new do |s|
|
|
42
47
|
"lib/remailer/socks5/client/interpreter.rb",
|
43
48
|
"lib/remailer/support.rb",
|
44
49
|
"remailer.gemspec",
|
45
|
-
"test/
|
50
|
+
"test/bin/exercise",
|
51
|
+
"test/config.example.yml",
|
52
|
+
"test/config.rb",
|
46
53
|
"test/helper.rb",
|
47
54
|
"test/unit/remailer_imap_client_interpreter_test.rb",
|
48
55
|
"test/unit/remailer_imap_client_test.rb",
|
@@ -54,21 +61,24 @@ Gem::Specification.new do |s|
|
|
54
61
|
"test/unit/remailer_socks5_client_interpreter_test.rb",
|
55
62
|
"test/unit/remailer_test.rb"
|
56
63
|
]
|
57
|
-
s.homepage = "http://github.com/
|
58
|
-
s.
|
59
|
-
s.
|
60
|
-
s.summary = "Reactor-Ready SMTP Mailer"
|
64
|
+
s.homepage = "http://github.com/postageapp/remailer".freeze
|
65
|
+
s.rubygems_version = "3.1.4".freeze
|
66
|
+
s.summary = "Reactor-Ready SMTP Mailer".freeze
|
61
67
|
|
62
68
|
if s.respond_to? :specification_version then
|
63
|
-
s.specification_version =
|
69
|
+
s.specification_version = 4
|
70
|
+
end
|
64
71
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
72
|
+
if s.respond_to? :add_runtime_dependency then
|
73
|
+
s.add_runtime_dependency(%q<eventmachine>.freeze, [">= 0"])
|
74
|
+
s.add_development_dependency(%q<minitest>.freeze, [">= 0"])
|
75
|
+
s.add_development_dependency(%q<minitest-reporters>.freeze, [">= 0"])
|
76
|
+
s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
|
70
77
|
else
|
71
|
-
s.add_dependency(%q<eventmachine
|
78
|
+
s.add_dependency(%q<eventmachine>.freeze, [">= 0"])
|
79
|
+
s.add_dependency(%q<minitest>.freeze, [">= 0"])
|
80
|
+
s.add_dependency(%q<minitest-reporters>.freeze, [">= 0"])
|
81
|
+
s.add_dependency(%q<juwelier>.freeze, [">= 0"])
|
72
82
|
end
|
73
83
|
end
|
74
84
|
|