vines 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/LICENSE +19 -0
  2. data/README +34 -0
  3. data/Rakefile +55 -0
  4. data/bin/vines +95 -0
  5. data/conf/certs/README +32 -0
  6. data/conf/certs/ca-bundle.crt +3987 -0
  7. data/conf/config.rb +114 -0
  8. data/lib/vines.rb +155 -0
  9. data/lib/vines/command/bcrypt.rb +12 -0
  10. data/lib/vines/command/cert.rb +49 -0
  11. data/lib/vines/command/init.rb +58 -0
  12. data/lib/vines/command/ldap.rb +35 -0
  13. data/lib/vines/command/restart.rb +12 -0
  14. data/lib/vines/command/schema.rb +24 -0
  15. data/lib/vines/command/start.rb +28 -0
  16. data/lib/vines/command/stop.rb +18 -0
  17. data/lib/vines/config.rb +191 -0
  18. data/lib/vines/contact.rb +99 -0
  19. data/lib/vines/daemon.rb +78 -0
  20. data/lib/vines/error.rb +150 -0
  21. data/lib/vines/jid.rb +56 -0
  22. data/lib/vines/kit.rb +23 -0
  23. data/lib/vines/router.rb +125 -0
  24. data/lib/vines/stanza.rb +55 -0
  25. data/lib/vines/stanza/iq.rb +50 -0
  26. data/lib/vines/stanza/iq/auth.rb +18 -0
  27. data/lib/vines/stanza/iq/disco_info.rb +25 -0
  28. data/lib/vines/stanza/iq/disco_items.rb +23 -0
  29. data/lib/vines/stanza/iq/error.rb +16 -0
  30. data/lib/vines/stanza/iq/ping.rb +16 -0
  31. data/lib/vines/stanza/iq/query.rb +10 -0
  32. data/lib/vines/stanza/iq/result.rb +16 -0
  33. data/lib/vines/stanza/iq/roster.rb +153 -0
  34. data/lib/vines/stanza/iq/session.rb +22 -0
  35. data/lib/vines/stanza/iq/vcard.rb +58 -0
  36. data/lib/vines/stanza/message.rb +41 -0
  37. data/lib/vines/stanza/presence.rb +119 -0
  38. data/lib/vines/stanza/presence/error.rb +23 -0
  39. data/lib/vines/stanza/presence/probe.rb +38 -0
  40. data/lib/vines/stanza/presence/subscribe.rb +66 -0
  41. data/lib/vines/stanza/presence/subscribed.rb +64 -0
  42. data/lib/vines/stanza/presence/unavailable.rb +15 -0
  43. data/lib/vines/stanza/presence/unsubscribe.rb +57 -0
  44. data/lib/vines/stanza/presence/unsubscribed.rb +50 -0
  45. data/lib/vines/storage.rb +216 -0
  46. data/lib/vines/storage/couchdb.rb +119 -0
  47. data/lib/vines/storage/ldap.rb +59 -0
  48. data/lib/vines/storage/local.rb +66 -0
  49. data/lib/vines/storage/redis.rb +108 -0
  50. data/lib/vines/storage/sql.rb +174 -0
  51. data/lib/vines/store.rb +51 -0
  52. data/lib/vines/stream.rb +198 -0
  53. data/lib/vines/stream/client.rb +131 -0
  54. data/lib/vines/stream/client/auth.rb +94 -0
  55. data/lib/vines/stream/client/auth_restart.rb +33 -0
  56. data/lib/vines/stream/client/bind.rb +58 -0
  57. data/lib/vines/stream/client/bind_restart.rb +25 -0
  58. data/lib/vines/stream/client/closed.rb +13 -0
  59. data/lib/vines/stream/client/ready.rb +15 -0
  60. data/lib/vines/stream/client/start.rb +27 -0
  61. data/lib/vines/stream/client/tls.rb +37 -0
  62. data/lib/vines/stream/component.rb +53 -0
  63. data/lib/vines/stream/component/handshake.rb +25 -0
  64. data/lib/vines/stream/component/ready.rb +24 -0
  65. data/lib/vines/stream/component/start.rb +19 -0
  66. data/lib/vines/stream/http.rb +111 -0
  67. data/lib/vines/stream/http/http_request.rb +22 -0
  68. data/lib/vines/stream/http/http_state.rb +139 -0
  69. data/lib/vines/stream/http/http_states.rb +53 -0
  70. data/lib/vines/stream/parser.rb +78 -0
  71. data/lib/vines/stream/server.rb +126 -0
  72. data/lib/vines/stream/server/auth.rb +13 -0
  73. data/lib/vines/stream/server/auth_restart.rb +19 -0
  74. data/lib/vines/stream/server/final_restart.rb +20 -0
  75. data/lib/vines/stream/server/outbound/auth.rb +31 -0
  76. data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
  77. data/lib/vines/stream/server/outbound/auth_result.rb +28 -0
  78. data/lib/vines/stream/server/outbound/final_features.rb +27 -0
  79. data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
  80. data/lib/vines/stream/server/outbound/start.rb +20 -0
  81. data/lib/vines/stream/server/outbound/tls.rb +30 -0
  82. data/lib/vines/stream/server/outbound/tls_result.rb +31 -0
  83. data/lib/vines/stream/server/ready.rb +20 -0
  84. data/lib/vines/stream/server/start.rb +13 -0
  85. data/lib/vines/stream/server/tls.rb +13 -0
  86. data/lib/vines/stream/state.rb +55 -0
  87. data/lib/vines/token_bucket.rb +46 -0
  88. data/lib/vines/user.rb +124 -0
  89. data/lib/vines/version.rb +5 -0
  90. data/lib/vines/xmpp_server.rb +25 -0
  91. data/test/config_test.rb +396 -0
  92. data/test/error_test.rb +59 -0
  93. data/test/ext/nokogiri.rb +14 -0
  94. data/test/jid_test.rb +71 -0
  95. data/test/kit_test.rb +21 -0
  96. data/test/router_test.rb +60 -0
  97. data/test/stanza/iq/roster_test.rb +198 -0
  98. data/test/stanza/iq/session_test.rb +30 -0
  99. data/test/stanza/iq/vcard_test.rb +159 -0
  100. data/test/stanza/message_test.rb +124 -0
  101. data/test/stanza/presence/subscribe_test.rb +75 -0
  102. data/test/storage/couchdb_test.rb +102 -0
  103. data/test/storage/ldap_test.rb +207 -0
  104. data/test/storage/local_test.rb +54 -0
  105. data/test/storage/redis_test.rb +75 -0
  106. data/test/storage/sql_test.rb +55 -0
  107. data/test/storage/storage_tests.rb +134 -0
  108. data/test/storage_test.rb +90 -0
  109. data/test/stream/client/auth_test.rb +127 -0
  110. data/test/stream/client/ready_test.rb +47 -0
  111. data/test/stream/component/handshake_test.rb +46 -0
  112. data/test/stream/component/ready_test.rb +105 -0
  113. data/test/stream/component/start_test.rb +41 -0
  114. data/test/stream/parser_test.rb +121 -0
  115. data/test/stream/server/outbound/auth_test.rb +77 -0
  116. data/test/stream/server/ready_test.rb +100 -0
  117. data/test/token_bucket_test.rb +24 -0
  118. data/test/user_test.rb +64 -0
  119. metadata +318 -0
@@ -0,0 +1,5 @@
1
+ # encoding: UTF-8
2
+
3
+ module Vines
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+
3
+ module Vines
4
+
5
+ # The main starting point for the XMPP server process. Starts the
6
+ # EventMachine processing loop and registers the XMPP protocol handler
7
+ # with the ports defined in the server configuration file.
8
+ class XmppServer
9
+ include Vines::Log
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ end
14
+
15
+ def start
16
+ log.info('XMPP server started')
17
+ at_exit { log.fatal('XMPP server stopped') }
18
+ EM.epoll
19
+ EM.kqueue
20
+ EM.run do
21
+ @config.ports.each {|port| port.start }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,396 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'test/unit'
5
+
6
+ class ConfigTest < Test::Unit::TestCase
7
+ def test_missing_host
8
+ assert_raise(RuntimeError) do
9
+ Vines::Config.new do
10
+ # missing hosts
11
+ end
12
+ end
13
+ end
14
+
15
+ def test_duplicate_host
16
+ assert_raise(RuntimeError) do
17
+ Vines::Config.new do
18
+ host 'wonderland.lit' do
19
+ storage 'fs' do
20
+ dir '.'
21
+ end
22
+ end
23
+ host 'wonderland.lit' do
24
+ storage 'fs' do
25
+ dir '.'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def test_duplicate_host_in_one_call
33
+ assert_raise(RuntimeError) do
34
+ Vines::Config.new do
35
+ host 'wonderland.lit', 'wonderland.lit' do
36
+ storage 'fs' do
37
+ dir '.'
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ def test_missing_storage
45
+ assert_raise(RuntimeError) do
46
+ Vines::Config.new do
47
+ host 'wonderland.lit' do
48
+ # missing storage
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def test_bad_storage
55
+ assert_raise(RuntimeError) do
56
+ Vines::Config.new do
57
+ host 'wonderland.lit' do
58
+ storage 'bogus' do
59
+ # no bogus storage implementation
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def test_duplicate_storage
67
+ assert_raise(RuntimeError) do
68
+ Vines::Config.new do
69
+ host 'wonderland.lit' do
70
+ storage('fs') { dir '.' }
71
+ storage('fs') { dir '.' }
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def test_good_storage
78
+ assert_nothing_raised do
79
+ Vines::Config.new do
80
+ host 'wonderland.lit' do
81
+ storage 'fs' do
82
+ dir '.'
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def test_ldap_added_to_storage
90
+ config = Vines::Config.new do
91
+ host 'wonderland.lit' do
92
+ storage(:fs) { dir '.' }
93
+ # added after storage
94
+ ldap 'ldap.wonderland.lit', 1636 do
95
+ tls true
96
+ dn 'cn=Directory Manager'
97
+ password 'secr3t'
98
+ basedn 'dc=wonderland,dc=lit'
99
+ object_class 'person'
100
+ user_attr 'uid'
101
+ name_attr 'cn'
102
+ end
103
+ end
104
+
105
+ host 'verona.lit' do
106
+ ldap 'ldap.verona.lit', 1636 do
107
+ tls true
108
+ dn 'cn=Directory Manager'
109
+ password 'secr3t'
110
+ basedn 'dc=wonderland,dc=lit'
111
+ object_class 'person'
112
+ user_attr 'uid'
113
+ name_attr 'cn'
114
+ end
115
+ # added before storage
116
+ storage(:fs) { dir '.' }
117
+ end
118
+ end
119
+ %w[wonderland.lit verona.lit].each do |domain|
120
+ assert_not_nil config.vhosts[domain].ldap
121
+ assert config.vhosts[domain].ldap?
122
+ end
123
+ end
124
+
125
+ def test_configure
126
+ config = Vines::Config.configure do
127
+ host 'wonderland.lit' do
128
+ storage :fs do
129
+ dir '.'
130
+ end
131
+ end
132
+ end
133
+ assert_not_nil config
134
+ assert_same config, Vines::Config.instance
135
+ end
136
+
137
+ def test_vhost
138
+ config = Vines::Config.new do
139
+ host 'wonderland.lit' do
140
+ storage(:fs) { dir '.' }
141
+ end
142
+ end
143
+ assert_equal ['wonderland.lit'], config.vhosts.keys
144
+ assert config.vhost?('wonderland.lit')
145
+ assert !config.vhost?('bogus')
146
+ end
147
+
148
+ def test_port_lookup
149
+ config = Vines::Config.new do
150
+ host 'wonderland.lit' do
151
+ storage(:fs) { dir '.' }
152
+ end
153
+ client
154
+ end
155
+ assert_not_nil config[:client]
156
+ assert_raise(ArgumentError) { config[:server] }
157
+ assert_raise(ArgumentError) { config[:bogus] }
158
+ end
159
+
160
+ def test_duplicate_client
161
+ assert_raise(RuntimeError) do
162
+ Vines::Config.new do
163
+ client
164
+ client
165
+ end
166
+ end
167
+ end
168
+
169
+ def test_duplicate_server
170
+ assert_raise(RuntimeError) do
171
+ Vines::Config.new do
172
+ server
173
+ server
174
+ end
175
+ end
176
+ end
177
+
178
+ def test_duplicate_http
179
+ assert_raise(RuntimeError) do
180
+ Vines::Config.new do
181
+ http
182
+ http
183
+ end
184
+ end
185
+ end
186
+
187
+ def test_duplicate_component
188
+ assert_raise(RuntimeError) do
189
+ Vines::Config.new do
190
+ component
191
+ component
192
+ end
193
+ end
194
+ end
195
+
196
+ def test_default_client
197
+ config = Vines::Config.new do
198
+ host 'wonderland.lit' do
199
+ storage(:fs) { dir '.' }
200
+ end
201
+ client
202
+ end
203
+ port = config.ports.first
204
+ assert_not_nil port
205
+ assert_equal Vines::Config::ClientPort, port.class
206
+ assert_equal '0.0.0.0', port.host
207
+ assert_equal 5222, port.port
208
+ assert_equal 131_072, port.max_stanza_size
209
+ assert_equal 5, port.max_resources_per_account
210
+ assert_equal Vines::Stream::Client, port.stream
211
+ assert_same config, port.config
212
+ assert_equal 1, config.ports.size
213
+ end
214
+
215
+ def test_configured_client
216
+ config = Vines::Config.new do
217
+ host 'wonderland.lit' do
218
+ storage(:fs) { dir '.' }
219
+ end
220
+ client '0.0.0.1', 42 do
221
+ max_stanza_size 60_000
222
+ max_resources_per_account 1
223
+ end
224
+ end
225
+ port = config.ports.first
226
+ assert_not_nil port
227
+ assert_equal Vines::Config::ClientPort, port.class
228
+ assert_equal '0.0.0.1', port.host
229
+ assert_equal 42, port.port
230
+ assert_equal 60_000, port.max_stanza_size
231
+ assert_equal 1, port.max_resources_per_account
232
+ assert_equal Vines::Stream::Client, port.stream
233
+ assert_same config, port.config
234
+ assert_equal 1, config.ports.size
235
+ end
236
+
237
+ def test_max_stanza_size
238
+ config = Vines::Config.new do
239
+ host 'wonderland.lit' do
240
+ storage(:fs) { dir '.' }
241
+ end
242
+ client do
243
+ max_stanza_size 0
244
+ end
245
+ end
246
+ assert_equal 10_000, config.ports.first.max_stanza_size
247
+ end
248
+
249
+ def test_default_server
250
+ config = Vines::Config.new do
251
+ host 'wonderland.lit' do
252
+ storage(:fs) { dir '.' }
253
+ end
254
+ server
255
+ end
256
+ port = config.ports.first
257
+ assert_not_nil port
258
+ assert !config.s2s?('verona.lit')
259
+ assert_equal Vines::Config::ServerPort, port.class
260
+ assert_equal '0.0.0.0', port.host
261
+ assert_equal 5269, port.port
262
+ assert_equal 131_072, port.max_stanza_size
263
+ assert_equal Vines::Stream::Server, port.stream
264
+ assert_same config, port.config
265
+ assert_equal 1, config.ports.size
266
+ end
267
+
268
+ def test_configured_server
269
+ config = Vines::Config.new do
270
+ host 'wonderland.lit' do
271
+ storage(:fs) { dir '.' }
272
+ end
273
+ server '0.0.0.1', 42 do
274
+ max_stanza_size 60_000
275
+ hosts ['verona.lit', 'denmark.lit']
276
+ end
277
+ end
278
+ port = config.ports.first
279
+ assert_not_nil port
280
+ assert config.s2s?('verona.lit')
281
+ assert config.s2s?('denmark.lit')
282
+ assert !config.s2s?('bogus')
283
+ assert_equal Vines::Config::ServerPort, port.class
284
+ assert_equal '0.0.0.1', port.host
285
+ assert_equal 42, port.port
286
+ assert_equal 60_000, port.max_stanza_size
287
+ assert_equal Vines::Stream::Server, port.stream
288
+ assert_same config, port.config
289
+ assert_equal 1, config.ports.size
290
+ end
291
+
292
+ def test_default_http
293
+ config = Vines::Config.new do
294
+ host 'wonderland.lit' do
295
+ storage(:fs) { dir '.' }
296
+ end
297
+ http
298
+ end
299
+ port = config.ports.first
300
+ assert_not_nil port
301
+ assert_equal Vines::Config::HttpPort, port.class
302
+ assert_equal '0.0.0.0', port.host
303
+ assert_equal 5280, port.port
304
+ assert_equal 131_072, port.max_stanza_size
305
+ assert_equal Vines::Stream::Http, port.stream
306
+ assert_same config, port.config
307
+ assert_equal 1, config.ports.size
308
+ end
309
+
310
+ def test_configured_http
311
+ config = Vines::Config.new do
312
+ host 'wonderland.lit' do
313
+ storage(:fs) { dir '.' }
314
+ end
315
+ http '0.0.0.1', 42 do
316
+ max_stanza_size 60_000
317
+ end
318
+ end
319
+ port = config.ports.first
320
+ assert_not_nil port
321
+ assert_equal Vines::Config::HttpPort, port.class
322
+ assert_equal '0.0.0.1', port.host
323
+ assert_equal 42, port.port
324
+ assert_equal 60_000, port.max_stanza_size
325
+ assert_equal Vines::Stream::Http, port.stream
326
+ assert_same config, port.config
327
+ assert_equal 1, config.ports.size
328
+ end
329
+
330
+ def test_default_component
331
+ config = Vines::Config.new do
332
+ host 'wonderland.lit' do
333
+ storage(:fs) { dir '.' }
334
+ end
335
+ component
336
+ end
337
+ port = config.ports.first
338
+ assert_not_nil port
339
+ assert port.components.empty?
340
+ assert_nil port.password('bogus')
341
+ assert_equal Vines::Config::ComponentPort, port.class
342
+ assert_equal '0.0.0.0', port.host
343
+ assert_equal 5347, port.port
344
+ assert_equal 131_072, port.max_stanza_size
345
+ assert_equal Vines::Stream::Component, port.stream
346
+ assert_same config, port.config
347
+ assert_equal 1, config.ports.size
348
+ end
349
+
350
+ def test_configured_component
351
+ config = Vines::Config.new do
352
+ host 'wonderland.lit' do
353
+ storage(:fs) { dir '.' }
354
+ end
355
+ component '0.0.0.1', 42 do
356
+ max_stanza_size 60_000
357
+ components 'tea.wonderland.lit' => 'secr3t',
358
+ 'cake.wonderland.lit' => 'passw0rd'
359
+ end
360
+ end
361
+ port = config.ports.first
362
+ assert_not_nil port
363
+ assert_equal 2, port.components.size
364
+ assert_equal 'secr3t', port.password('tea.wonderland.lit')
365
+ assert_equal 'passw0rd', port.password('cake.wonderland.lit')
366
+ assert_nil port.password('bogus')
367
+ assert_equal Vines::Config::ComponentPort, port.class
368
+ assert_equal '0.0.0.1', port.host
369
+ assert_equal 42, port.port
370
+ assert_equal 60_000, port.max_stanza_size
371
+ assert_equal Vines::Stream::Component, port.stream
372
+ assert_same config, port.config
373
+ assert_equal 1, config.ports.size
374
+ end
375
+
376
+ def test_invalid_log_level
377
+ assert_raise(RuntimeError) do
378
+ config = Vines::Config.new do
379
+ log 'bogus'
380
+ host 'wonderland.lit' do
381
+ storage(:fs) { dir '.' }
382
+ end
383
+ end
384
+ end
385
+ end
386
+
387
+ def test_valid_log_level
388
+ config = Vines::Config.new do
389
+ log :error
390
+ host 'wonderland.lit' do
391
+ storage(:fs) { dir '.' }
392
+ end
393
+ end
394
+ assert_equal Logger::ERROR, Class.new.extend(Vines::Log).log.level
395
+ end
396
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'test/unit'
5
+
6
+ class ErrorTest < Test::Unit::TestCase
7
+ def test_sasl_error_without_text
8
+ expected = %q{<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><temporary-auth-failure/></failure>}
9
+ assert_equal expected, Vines::SaslErrors::TemporaryAuthFailure.new.to_xml
10
+ end
11
+
12
+ def test_sasl_error_with_text
13
+ text = %q{<text xml:lang="en">busted</text>}
14
+ expected = %q{<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><temporary-auth-failure/>%s</failure>} % text
15
+ assert_equal expected, Vines::SaslErrors::TemporaryAuthFailure.new('busted').to_xml
16
+ end
17
+
18
+ def test_stream_error_without_text
19
+ expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></stream:error>}
20
+ assert_equal expected, Vines::StreamErrors::InternalServerError.new.to_xml
21
+ end
22
+
23
+ def test_stream_error_with_text
24
+ text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-streams" xml:lang="en">busted</text>}
25
+ expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/>%s</stream:error>} % text
26
+ assert_equal expected, Vines::StreamErrors::InternalServerError.new('busted').to_xml
27
+ end
28
+
29
+ def test_stanza_error_with_bad_type
30
+ node = node('<message/>')
31
+ assert_raises(RuntimeError) { Vines::StanzaErrors::BadRequest.new(node, 'bogus') }
32
+ end
33
+
34
+ def test_stanza_error_with_bad_stanza
35
+ node = node('<bogus/>')
36
+ assert_raises(RuntimeError) { Vines::StanzaErrors::BadRequest.new(node, 'modify') }
37
+ end
38
+
39
+ def test_stanza_error_without_text
40
+ error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>}
41
+ expected = %q{<message from="hatter@wonderland.lit" to="alice@wonderland.lit" type="error">%s</message>} % error
42
+ node = node(%Q{<message from="alice@wonderland.lit" to="hatter@wonderland.lit"/>})
43
+ assert_equal expected, Vines::StanzaErrors::BadRequest.new(node, 'modify').to_xml
44
+ end
45
+
46
+ def test_stanza_error_with_text
47
+ text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">busted</text>}
48
+ error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>%s</error>} % text
49
+ expected = %q{<message id="42" type="error">%s</message>} % error
50
+ node = node(%Q{<message id="42"/>})
51
+ assert_equal expected, Vines::StanzaErrors::BadRequest.new(node, 'modify', 'busted').to_xml
52
+ end
53
+
54
+ private
55
+
56
+ def node(xml)
57
+ Nokogiri::XML(xml).root
58
+ end
59
+ end