lygneo-vines 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +19 -0
  4. data/README.md +7 -0
  5. data/Rakefile +23 -0
  6. data/bin/vines +4 -0
  7. data/conf/certs/README +39 -0
  8. data/conf/certs/ca-bundle.crt +3895 -0
  9. data/conf/config.rb +42 -0
  10. data/lib/vines/cli.rb +132 -0
  11. data/lib/vines/cluster/connection.rb +26 -0
  12. data/lib/vines/cluster/publisher.rb +55 -0
  13. data/lib/vines/cluster/pubsub.rb +92 -0
  14. data/lib/vines/cluster/sessions.rb +125 -0
  15. data/lib/vines/cluster/subscriber.rb +108 -0
  16. data/lib/vines/cluster.rb +246 -0
  17. data/lib/vines/command/bcrypt.rb +12 -0
  18. data/lib/vines/command/cert.rb +50 -0
  19. data/lib/vines/command/init.rb +68 -0
  20. data/lib/vines/command/ldap.rb +38 -0
  21. data/lib/vines/command/restart.rb +12 -0
  22. data/lib/vines/command/schema.rb +24 -0
  23. data/lib/vines/command/start.rb +28 -0
  24. data/lib/vines/command/stop.rb +18 -0
  25. data/lib/vines/config/host.rb +125 -0
  26. data/lib/vines/config/port.rb +132 -0
  27. data/lib/vines/config/pubsub.rb +108 -0
  28. data/lib/vines/config.rb +223 -0
  29. data/lib/vines/daemon.rb +78 -0
  30. data/lib/vines/error.rb +150 -0
  31. data/lib/vines/follower.rb +111 -0
  32. data/lib/vines/jid.rb +95 -0
  33. data/lib/vines/kit.rb +23 -0
  34. data/lib/vines/log.rb +24 -0
  35. data/lib/vines/router.rb +179 -0
  36. data/lib/vines/stanza/iq/auth.rb +18 -0
  37. data/lib/vines/stanza/iq/disco_info.rb +45 -0
  38. data/lib/vines/stanza/iq/disco_items.rb +29 -0
  39. data/lib/vines/stanza/iq/error.rb +16 -0
  40. data/lib/vines/stanza/iq/ping.rb +16 -0
  41. data/lib/vines/stanza/iq/private_storage.rb +83 -0
  42. data/lib/vines/stanza/iq/query.rb +10 -0
  43. data/lib/vines/stanza/iq/result.rb +16 -0
  44. data/lib/vines/stanza/iq/roster.rb +140 -0
  45. data/lib/vines/stanza/iq/session.rb +17 -0
  46. data/lib/vines/stanza/iq/vcard.rb +56 -0
  47. data/lib/vines/stanza/iq/version.rb +25 -0
  48. data/lib/vines/stanza/iq.rb +48 -0
  49. data/lib/vines/stanza/message.rb +40 -0
  50. data/lib/vines/stanza/presence/error.rb +23 -0
  51. data/lib/vines/stanza/presence/probe.rb +37 -0
  52. data/lib/vines/stanza/presence/subscribe.rb +42 -0
  53. data/lib/vines/stanza/presence/subscribed.rb +51 -0
  54. data/lib/vines/stanza/presence/unavailable.rb +15 -0
  55. data/lib/vines/stanza/presence/unsubscribe.rb +38 -0
  56. data/lib/vines/stanza/presence/unsubscribed.rb +38 -0
  57. data/lib/vines/stanza/presence.rb +141 -0
  58. data/lib/vines/stanza/pubsub/create.rb +39 -0
  59. data/lib/vines/stanza/pubsub/delete.rb +41 -0
  60. data/lib/vines/stanza/pubsub/publish.rb +66 -0
  61. data/lib/vines/stanza/pubsub/subscribe.rb +44 -0
  62. data/lib/vines/stanza/pubsub/unsubscribe.rb +30 -0
  63. data/lib/vines/stanza/pubsub.rb +22 -0
  64. data/lib/vines/stanza.rb +175 -0
  65. data/lib/vines/storage/ldap.rb +71 -0
  66. data/lib/vines/storage/local.rb +139 -0
  67. data/lib/vines/storage/null.rb +39 -0
  68. data/lib/vines/storage/sql.rb +138 -0
  69. data/lib/vines/storage.rb +239 -0
  70. data/lib/vines/store.rb +110 -0
  71. data/lib/vines/stream/client/auth.rb +74 -0
  72. data/lib/vines/stream/client/auth_restart.rb +29 -0
  73. data/lib/vines/stream/client/bind.rb +72 -0
  74. data/lib/vines/stream/client/bind_restart.rb +24 -0
  75. data/lib/vines/stream/client/closed.rb +13 -0
  76. data/lib/vines/stream/client/ready.rb +17 -0
  77. data/lib/vines/stream/client/session.rb +210 -0
  78. data/lib/vines/stream/client/start.rb +27 -0
  79. data/lib/vines/stream/client/tls.rb +38 -0
  80. data/lib/vines/stream/client.rb +84 -0
  81. data/lib/vines/stream/component/handshake.rb +26 -0
  82. data/lib/vines/stream/component/ready.rb +23 -0
  83. data/lib/vines/stream/component/start.rb +19 -0
  84. data/lib/vines/stream/component.rb +58 -0
  85. data/lib/vines/stream/http/auth.rb +22 -0
  86. data/lib/vines/stream/http/bind.rb +32 -0
  87. data/lib/vines/stream/http/bind_restart.rb +37 -0
  88. data/lib/vines/stream/http/ready.rb +29 -0
  89. data/lib/vines/stream/http/request.rb +172 -0
  90. data/lib/vines/stream/http/session.rb +120 -0
  91. data/lib/vines/stream/http/sessions.rb +65 -0
  92. data/lib/vines/stream/http/start.rb +23 -0
  93. data/lib/vines/stream/http.rb +157 -0
  94. data/lib/vines/stream/parser.rb +79 -0
  95. data/lib/vines/stream/sasl.rb +128 -0
  96. data/lib/vines/stream/server/auth.rb +13 -0
  97. data/lib/vines/stream/server/auth_restart.rb +13 -0
  98. data/lib/vines/stream/server/final_restart.rb +21 -0
  99. data/lib/vines/stream/server/outbound/auth.rb +31 -0
  100. data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
  101. data/lib/vines/stream/server/outbound/auth_result.rb +32 -0
  102. data/lib/vines/stream/server/outbound/final_features.rb +28 -0
  103. data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
  104. data/lib/vines/stream/server/outbound/start.rb +20 -0
  105. data/lib/vines/stream/server/outbound/tls.rb +30 -0
  106. data/lib/vines/stream/server/outbound/tls_result.rb +34 -0
  107. data/lib/vines/stream/server/ready.rb +24 -0
  108. data/lib/vines/stream/server/start.rb +13 -0
  109. data/lib/vines/stream/server/tls.rb +13 -0
  110. data/lib/vines/stream/server.rb +150 -0
  111. data/lib/vines/stream/state.rb +60 -0
  112. data/lib/vines/stream.rb +247 -0
  113. data/lib/vines/token_bucket.rb +55 -0
  114. data/lib/vines/user.rb +123 -0
  115. data/lib/vines/version.rb +6 -0
  116. data/lib/vines/xmpp_server.rb +25 -0
  117. data/lib/vines.rb +203 -0
  118. data/test/cluster/publisher_test.rb +57 -0
  119. data/test/cluster/sessions_test.rb +47 -0
  120. data/test/cluster/subscriber_test.rb +109 -0
  121. data/test/config/host_test.rb +369 -0
  122. data/test/config/pubsub_test.rb +187 -0
  123. data/test/config_test.rb +732 -0
  124. data/test/error_test.rb +58 -0
  125. data/test/ext/nokogiri.rb +14 -0
  126. data/test/follower_test.rb +102 -0
  127. data/test/jid_test.rb +147 -0
  128. data/test/kit_test.rb +31 -0
  129. data/test/router_test.rb +243 -0
  130. data/test/stanza/iq/disco_info_test.rb +78 -0
  131. data/test/stanza/iq/disco_items_test.rb +49 -0
  132. data/test/stanza/iq/private_storage_test.rb +184 -0
  133. data/test/stanza/iq/roster_test.rb +229 -0
  134. data/test/stanza/iq/session_test.rb +25 -0
  135. data/test/stanza/iq/vcard_test.rb +146 -0
  136. data/test/stanza/iq/version_test.rb +64 -0
  137. data/test/stanza/iq_test.rb +70 -0
  138. data/test/stanza/message_test.rb +126 -0
  139. data/test/stanza/presence/probe_test.rb +50 -0
  140. data/test/stanza/presence/subscribe_test.rb +83 -0
  141. data/test/stanza/pubsub/create_test.rb +116 -0
  142. data/test/stanza/pubsub/delete_test.rb +169 -0
  143. data/test/stanza/pubsub/publish_test.rb +309 -0
  144. data/test/stanza/pubsub/subscribe_test.rb +205 -0
  145. data/test/stanza/pubsub/unsubscribe_test.rb +148 -0
  146. data/test/stanza_test.rb +85 -0
  147. data/test/storage/ldap_test.rb +201 -0
  148. data/test/storage/local_test.rb +59 -0
  149. data/test/storage/mock_redis.rb +97 -0
  150. data/test/storage/null_test.rb +29 -0
  151. data/test/storage/storage_tests.rb +182 -0
  152. data/test/storage_test.rb +85 -0
  153. data/test/store_test.rb +130 -0
  154. data/test/stream/client/auth_test.rb +137 -0
  155. data/test/stream/client/ready_test.rb +47 -0
  156. data/test/stream/client/session_test.rb +27 -0
  157. data/test/stream/component/handshake_test.rb +52 -0
  158. data/test/stream/component/ready_test.rb +103 -0
  159. data/test/stream/component/start_test.rb +39 -0
  160. data/test/stream/http/auth_test.rb +70 -0
  161. data/test/stream/http/ready_test.rb +86 -0
  162. data/test/stream/http/request_test.rb +209 -0
  163. data/test/stream/http/sessions_test.rb +49 -0
  164. data/test/stream/http/start_test.rb +50 -0
  165. data/test/stream/parser_test.rb +122 -0
  166. data/test/stream/sasl_test.rb +195 -0
  167. data/test/stream/server/auth_test.rb +61 -0
  168. data/test/stream/server/outbound/auth_test.rb +75 -0
  169. data/test/stream/server/ready_test.rb +98 -0
  170. data/test/test_helper.rb +42 -0
  171. data/test/token_bucket_test.rb +44 -0
  172. data/test/user_test.rb +96 -0
  173. data/vines.gemspec +30 -0
  174. metadata +387 -0
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::XmppError do
6
+ describe Vines::SaslErrors do
7
+ it 'does not require a text element' do
8
+ expected = %q{<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><temporary-auth-failure/></failure>}
9
+ Vines::SaslErrors::TemporaryAuthFailure.new.to_xml.must_equal expected
10
+ end
11
+
12
+ it 'includes a text element when message is given' do
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
+ Vines::SaslErrors::TemporaryAuthFailure.new('busted').to_xml.must_equal expected
16
+ end
17
+ end
18
+
19
+ describe Vines::StreamErrors do
20
+ it 'does not require a text element' do
21
+ expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></stream:error>}
22
+ Vines::StreamErrors::InternalServerError.new.to_xml.must_equal expected
23
+ end
24
+
25
+ it 'includes a text element when message is given' do
26
+ text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-streams" xml:lang="en">busted</text>}
27
+ expected = %q{<stream:error><internal-server-error xmlns="urn:ietf:params:xml:ns:xmpp-streams"/>%s</stream:error>} % text
28
+ Vines::StreamErrors::InternalServerError.new('busted').to_xml.must_equal expected
29
+ end
30
+ end
31
+
32
+ describe Vines::StanzaErrors do
33
+ it 'raises when given a bad type' do
34
+ node = node('<message/>')
35
+ -> { Vines::StanzaErrors::BadRequest.new(node, 'bogus') }.must_raise RuntimeError
36
+ end
37
+
38
+ it 'raises when given a bad stanza' do
39
+ node = node('<bogus/>')
40
+ -> { Vines::StanzaErrors::BadRequest.new(node, 'modify') }.must_raise RuntimeError
41
+ end
42
+
43
+ it 'does not require a text element' do
44
+ error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>}
45
+ expected = %q{<message from="hatter@wonderland.lit" to="alice@wonderland.lit" type="error">%s</message>} % error
46
+ node = node(%Q{<message from="alice@wonderland.lit" to="hatter@wonderland.lit"/>})
47
+ Vines::StanzaErrors::BadRequest.new(node, 'modify').to_xml.must_equal expected
48
+ end
49
+
50
+ it 'includes a text element when message is given' do
51
+ text = %q{<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">busted</text>}
52
+ error = %q{<error type="modify"><bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>%s</error>} % text
53
+ expected = %q{<message id="42" type="error">%s</message>} % error
54
+ node = node(%Q{<message id="42"/>})
55
+ Vines::StanzaErrors::BadRequest.new(node, 'modify', 'busted').to_xml.must_equal expected
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+
3
+ module Nokogiri
4
+ module XML
5
+ class Node
6
+ # Override equality testing so we can use MiniTest::Mock#expect with
7
+ # Nokogiri::XML::Node arguments. Node's default behavior considers
8
+ # all nodes unequal.
9
+ def ==(node)
10
+ self.to_s == node.to_s
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,102 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Follower do
6
+ subject do
7
+ Vines::Follower.new(
8
+ jid: 'alice@wonderland.lit',
9
+ name: "Alice",
10
+ groups: %w[Friends Buddies],
11
+ subscription: 'from')
12
+ end
13
+
14
+ describe 'follower equality checks' do
15
+ let(:alice) { Vines::Follower.new(jid: 'alice@wonderland.lit') }
16
+ let(:hatter) { Vines::Follower.new(jid: 'hatter@wonderland.lit') }
17
+
18
+ it 'uses class in equality check' do
19
+ (subject <=> 42).must_be_nil
20
+ end
21
+
22
+ it 'is equal to itself' do
23
+ assert subject == subject
24
+ assert subject.eql?(subject)
25
+ assert subject.hash == subject.hash
26
+ end
27
+
28
+ it 'is equal to another follower with the same jid' do
29
+ assert subject == alice
30
+ assert subject.eql?(alice)
31
+ assert subject.hash == alice.hash
32
+ end
33
+
34
+ it 'is not equal to a different jid' do
35
+ refute subject == hatter
36
+ refute subject.eql?(hatter)
37
+ refute subject.hash == hatter.hash
38
+ end
39
+ end
40
+
41
+ describe 'initialize' do
42
+ it 'raises when not given a jid' do
43
+ -> { Vines::Follower.new }.must_raise ArgumentError
44
+ -> { Vines::Follower.new(jid: '') }.must_raise ArgumentError
45
+ end
46
+
47
+ it 'accepts a domain-only jid' do
48
+ follower = Vines::Follower.new(jid: 'tea.wonderland.lit')
49
+ follower.jid.to_s.must_equal 'tea.wonderland.lit'
50
+ end
51
+ end
52
+
53
+ describe '#to_roster_xml' do
54
+ let(:expected) do
55
+ node(%q{
56
+ <item jid="alice@wonderland.lit" name="Alice" subscription="from">
57
+ <group>Buddies</group>
58
+ <group>Friends</group>
59
+ </item>
60
+ })
61
+ end
62
+
63
+ it 'sorts group names' do
64
+ subject.to_roster_xml.must_equal expected
65
+ end
66
+ end
67
+
68
+ describe '#send_roster_push' do
69
+ let(:recipient) { MiniTest::Mock.new }
70
+ let(:expected) do
71
+ node(%q{
72
+ <iq to="hatter@wonderland.lit" type="set">
73
+ <query xmlns="jabber:iq:roster">
74
+ <item jid="alice@wonderland.lit" name="Alice" subscription="from">
75
+ <group>Buddies</group>
76
+ <group>Friends</group>
77
+ </item>
78
+ </query>
79
+ </iq>
80
+ })
81
+ end
82
+
83
+ before do
84
+ recipient.expect :user, Vines::User.new(jid: 'hatter@wonderland.lit')
85
+ class << recipient
86
+ attr_accessor :nodes
87
+ def write(node)
88
+ @nodes ||= []
89
+ @nodes << node
90
+ end
91
+ end
92
+ end
93
+
94
+ it '' do
95
+ subject.send_roster_push(recipient)
96
+ recipient.verify
97
+ recipient.nodes.size.must_equal 1
98
+ recipient.nodes.first.remove_attribute('id') # id is random
99
+ recipient.nodes.first.must_equal expected
100
+ end
101
+ end
102
+ end
data/test/jid_test.rb ADDED
@@ -0,0 +1,147 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::JID do
6
+ it 'handles empty input' do
7
+ [nil, ''].each do |text|
8
+ Vines::JID.new(text) # shouldn't raise an error
9
+ jid = Vines::JID.new(text)
10
+ assert_nil jid.node
11
+ assert_nil jid.resource
12
+ assert_equal '', jid.domain
13
+ assert_equal '', jid.to_s
14
+ assert_equal '', jid.bare.to_s
15
+ assert jid.empty?
16
+ refute jid.domain?
17
+ end
18
+ end
19
+
20
+ it 'raises when a jid part is too long' do
21
+ Vines::JID.new('n' * 1023) # shouldn't raise an error
22
+ assert_raises(ArgumentError) { Vines::JID.new('n' * 1024) }
23
+ assert_raises(ArgumentError) { Vines::JID.new('n', 'd' * 1024) }
24
+ assert_raises(ArgumentError) { Vines::JID.new('n', 'd', 'r' * 1024) }
25
+ Vines::JID.new('n' * 1023, 'd' * 1023, 'r' * 1023) # shouldn't raise an error
26
+ end
27
+
28
+ it 'correctly handles domain only jids' do
29
+ jid = Vines::JID.new('wonderland.lit')
30
+ assert_equal 'wonderland.lit', jid.to_s
31
+ assert_equal 'wonderland.lit', jid.domain
32
+ assert_nil jid.node
33
+ assert_nil jid.resource
34
+ assert_equal jid, jid.bare
35
+ assert jid.domain?
36
+ refute jid.empty?
37
+ end
38
+
39
+ it 'correctly handles bare jid components' do
40
+ jid = Vines::JID.new('alice', 'wonderland.lit')
41
+ assert_equal 'alice@wonderland.lit', jid.to_s
42
+ assert_equal 'wonderland.lit', jid.domain
43
+ assert_equal 'alice', jid.node
44
+ assert_nil jid.resource
45
+ assert_equal jid, jid.bare
46
+ refute jid.domain?
47
+ refute jid.empty?
48
+ end
49
+
50
+ it 'correctly parses bare jids' do
51
+ jid = Vines::JID.new('alice@wonderland.lit')
52
+ assert_equal 'alice@wonderland.lit', jid.to_s
53
+ assert_equal 'wonderland.lit', jid.domain
54
+ assert_equal 'alice', jid.node
55
+ assert_nil jid.resource
56
+ assert_equal jid, jid.bare
57
+ refute jid.domain?
58
+ refute jid.empty?
59
+ end
60
+
61
+ it 'correctly handles full jid components' do
62
+ jid = Vines::JID.new('alice', 'wonderland.lit', 'tea')
63
+ assert_equal 'alice@wonderland.lit/tea', jid.to_s
64
+ assert_equal 'wonderland.lit', jid.domain
65
+ assert_equal 'alice', jid.node
66
+ assert_equal 'tea', jid.resource
67
+ refute_equal jid, jid.bare
68
+ refute jid.domain?
69
+ refute jid.empty?
70
+ end
71
+
72
+ it 'correctly parses full jids' do
73
+ jid = Vines::JID.new('alice@wonderland.lit/tea')
74
+ assert_equal 'alice@wonderland.lit/tea', jid.to_s
75
+ assert_equal 'wonderland.lit', jid.domain
76
+ assert_equal 'alice', jid.node
77
+ assert_equal 'tea', jid.resource
78
+ refute_equal jid, jid.bare
79
+ refute jid.domain?
80
+ refute jid.empty?
81
+ end
82
+
83
+ it 'accepts separator characters in resource part' do
84
+ jid = Vines::JID.new('alice@wonderland.lit/foo/bar@blarg test')
85
+ assert_equal 'alice', jid.node
86
+ assert_equal 'wonderland.lit', jid.domain
87
+ assert_equal 'foo/bar@blarg test', jid.resource
88
+ end
89
+
90
+ it 'accepts separator characters in resource part with missing node part' do
91
+ jid = Vines::JID.new('wonderland.lit/foo/bar@blarg')
92
+ assert_nil jid.node
93
+ assert_equal 'wonderland.lit', jid.domain
94
+ assert_equal 'foo/bar@blarg', jid.resource
95
+ refute jid.domain?
96
+ end
97
+
98
+ it 'accepts strange characters in node part' do
99
+ jid = Vines::JID.new(%q{nasty!#$%()*+,-.;=?[\]^_`{|}~node@example.com})
100
+ jid.node.must_equal %q{nasty!#$%()*+,-.;=?[\]^_`{|}~node}
101
+ jid.domain.must_equal 'example.com'
102
+ jid.resource.must_be_nil
103
+ end
104
+
105
+ it 'accepts strange characters in resource part' do
106
+ jid = Vines::JID.new(%q{node@example.com/repulsive !#"$%&'()*+,-./:;<=>?@[\]^_`{|}~resource})
107
+ jid.node.must_equal 'node'
108
+ jid.domain.must_equal 'example.com'
109
+ jid.resource.must_equal %q{repulsive !#"$%&'()*+,-./:;<=>?@[\]^_`{|}~resource}
110
+ end
111
+
112
+ it 'rejects empty jid parts' do
113
+ assert_raises(ArgumentError) { Vines::JID.new('@wonderland.lit') }
114
+ assert_raises(ArgumentError) { Vines::JID.new('wonderland.lit/') }
115
+ assert_raises(ArgumentError) { Vines::JID.new('@') }
116
+ assert_raises(ArgumentError) { Vines::JID.new('alice@') }
117
+ assert_raises(ArgumentError) { Vines::JID.new('/') }
118
+ assert_raises(ArgumentError) { Vines::JID.new('/res') }
119
+ assert_raises(ArgumentError) { Vines::JID.new('@/') }
120
+ end
121
+
122
+ it 'rejects invalid characters' do
123
+ assert_raises(ArgumentError) { Vines::JID.new(%q{alice"s@wonderland.lit}) }
124
+ assert_raises(ArgumentError) { Vines::JID.new(%q{alice&s@wonderland.lit}) }
125
+ assert_raises(ArgumentError) { Vines::JID.new(%q{alice's@wonderland.lit}) }
126
+ assert_raises(ArgumentError) { Vines::JID.new(%q{alice:s@wonderland.lit}) }
127
+ assert_raises(ArgumentError) { Vines::JID.new(%q{alice<s@wonderland.lit}) }
128
+ assert_raises(ArgumentError) { Vines::JID.new(%q{alice>s@wonderland.lit}) }
129
+ assert_raises(ArgumentError) { Vines::JID.new("alice\u0000s@wonderland.lit") }
130
+ assert_raises(ArgumentError) { Vines::JID.new("alice\ts@wonderland.lit") }
131
+ assert_raises(ArgumentError) { Vines::JID.new("alice\rs@wonderland.lit") }
132
+ assert_raises(ArgumentError) { Vines::JID.new("alice\ns@wonderland.lit") }
133
+ assert_raises(ArgumentError) { Vines::JID.new("alice\vs@wonderland.lit") }
134
+ assert_raises(ArgumentError) { Vines::JID.new("alice\fs@wonderland.lit") }
135
+ assert_raises(ArgumentError) { Vines::JID.new(" alice@wonderland.lit") }
136
+ assert_raises(ArgumentError) { Vines::JID.new("alice@wonderland.lit ") }
137
+ assert_raises(ArgumentError) { Vines::JID.new("alice s@wonderland.lit") }
138
+ assert_raises(ArgumentError) { Vines::JID.new("alice@w onderland.lit") }
139
+ assert_raises(ArgumentError) { Vines::JID.new("alice@w\tonderland.lit") }
140
+ assert_raises(ArgumentError) { Vines::JID.new("alice@w\ronderland.lit") }
141
+ assert_raises(ArgumentError) { Vines::JID.new("alice@w\nonderland.lit") }
142
+ assert_raises(ArgumentError) { Vines::JID.new("alice@w\vonderland.lit") }
143
+ assert_raises(ArgumentError) { Vines::JID.new("alice@w\fonderland.lit") }
144
+ assert_raises(ArgumentError) { Vines::JID.new("alice@w\u0000onderland.lit") }
145
+ assert_raises(ArgumentError) { Vines::JID.new("alice@wonderland.lit/\u0000res") }
146
+ end
147
+ end
data/test/kit_test.rb ADDED
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Kit do
6
+ describe '#hmac' do
7
+ it 'generates a SHA-512 HMAC' do
8
+ Vines::Kit.hmac('secret', 'username').length.must_equal 128
9
+ assert_equal Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s1', 'u1')
10
+ refute_equal Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s2', 'u1')
11
+ refute_equal Vines::Kit.hmac('s1', 'u1'), Vines::Kit.hmac('s1', 'u2')
12
+ end
13
+ end
14
+
15
+ describe '#uuid' do
16
+ it 'returns a random uuid' do
17
+ ids = Array.new(1000) { Vines::Kit.uuid }
18
+ assert ids.all? {|id| !id.nil? }
19
+ assert ids.all? {|id| id.length == 36 }
20
+ assert ids.all? {|id| id.match(/\w{8}-\w{4}-[4]\w{3}-[89ab]\w{3}-\w{12}/) }
21
+ ids.uniq.length.must_equal ids.length
22
+ end
23
+ end
24
+
25
+ describe '#auth_token' do
26
+ it 'returns a random 128 character token' do
27
+ Vines::Kit.auth_token.wont_equal Vines::Kit.auth_token
28
+ Vines::Kit.auth_token.length.must_equal 128
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,243 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Router do
6
+ subject { Vines::Router.new(config) }
7
+ let(:alice) { Vines::JID.new('alice@wonderland.lit/tea') }
8
+ let(:hatter) { 'hatter@wonderland.lit/cake' }
9
+ let(:romeo) { 'romeo@verona.lit/party' }
10
+ let(:config) do
11
+ Vines::Config.new do
12
+ host 'wonderland.lit' do
13
+ storage(:fs) { dir Dir.tmpdir }
14
+ components 'tea' => 'secr3t'
15
+ end
16
+ end
17
+ end
18
+
19
+ describe '#connected_resources' do
20
+ let(:cake) { 'alice@wonderland.lit/cake' }
21
+ let(:stream1) { stream(alice) }
22
+ let(:stream2) { stream(cake) }
23
+
24
+ it 'is empty before any streams are connected' do
25
+ subject.connected_resources(alice, alice).size.must_equal 0
26
+ subject.connected_resources(cake, alice).size.must_equal 0
27
+ subject.size.must_equal 0
28
+ end
29
+
30
+ it 'returns only one stream matching full jid' do
31
+ subject << stream1
32
+ subject << stream2
33
+
34
+ streams = subject.connected_resources(alice, alice)
35
+ streams.size.must_equal 1
36
+ streams.first.user.jid.must_equal alice
37
+
38
+ streams = subject.connected_resources(cake, alice)
39
+ streams.size.must_equal 1
40
+ streams.first.user.jid.to_s.must_equal cake
41
+ end
42
+
43
+ it 'returns all streams matching bare jid' do
44
+ subject << stream1
45
+ subject << stream2
46
+
47
+ streams = subject.connected_resources(alice.bare, alice)
48
+ streams.size.must_equal 2
49
+ subject.size.must_equal 2
50
+ end
51
+ end
52
+
53
+ describe '#connected_resources with permissions' do
54
+ let(:stream1) { stream(alice) }
55
+ let(:stream2) { stream(romeo) }
56
+
57
+ before do
58
+ subject << stream1
59
+ subject << stream2
60
+ end
61
+
62
+ it 'denies access when cross domain messages is off' do
63
+ subject.connected_resources(alice, romeo).size.must_equal 0
64
+ end
65
+
66
+ it 'allows access when cross domain messages is on' do
67
+ config.vhost('wonderland.lit').cross_domain_messages true
68
+ subject.connected_resources(alice, romeo).size.must_equal 1
69
+ end
70
+ end
71
+
72
+ describe '#available_resources' do
73
+ let(:cake) { 'alice@wonderland.lit/cake' }
74
+ let(:stream1) { stream(alice) }
75
+ let(:stream2) { stream(cake) }
76
+
77
+ before do
78
+ stream1.send 'available?=', true
79
+ stream2.send 'available?=', false
80
+ end
81
+
82
+ it 'is empty before any streams are connected' do
83
+ subject.available_resources(alice, alice).size.must_equal 0
84
+ subject.available_resources(cake, alice).size.must_equal 0
85
+ subject.size.must_equal 0
86
+ end
87
+
88
+ it 'returns available streams based on bare jid, not full jid' do
89
+ subject << stream1
90
+ subject << stream2
91
+
92
+ streams = [alice, cake, alice.bare].map do |jid|
93
+ subject.available_resources(jid, alice)
94
+ end.flatten
95
+
96
+ # should only have found alice's stream
97
+ streams.size.must_equal 3
98
+ streams.uniq.size.must_equal 1
99
+ streams.first.user.jid.must_equal alice
100
+
101
+ subject.size.must_equal 2
102
+ end
103
+ end
104
+
105
+ describe '#interested_resources with no streams' do
106
+ it 'is empty before any streams are connected' do
107
+ subject.interested_resources(alice, alice).size.must_equal 0
108
+ subject.interested_resources(hatter, alice).size.must_equal 0
109
+ subject.interested_resources(alice, hatter, alice).size.must_equal 0
110
+ subject.size.must_equal 0
111
+ end
112
+ end
113
+
114
+ describe '#interested_resources' do
115
+ let(:stream1) { stream(alice) }
116
+ let(:stream2) { stream(hatter) }
117
+
118
+ before do
119
+ stream1.send 'interested?=', true
120
+ stream2.send 'interested?=', false
121
+ subject << stream1
122
+ subject << stream2
123
+ end
124
+
125
+ it 'does not find streams for unauthenticated jids' do
126
+ subject.interested_resources('bogus@wonderland.lit', alice).size.must_equal 0
127
+ end
128
+
129
+ it 'finds interested streams for full jids' do
130
+ subject.interested_resources(alice, hatter, alice).size.must_equal 1
131
+ subject.interested_resources([alice, hatter], alice).size.must_equal 1
132
+ subject.interested_resources(alice, hatter, alice)[0].user.jid.must_equal alice
133
+ end
134
+
135
+ it 'does not find streams for uninterested jids' do
136
+ subject.interested_resources(hatter, alice).size.must_equal 0
137
+ subject.interested_resources([hatter], alice).size.must_equal 0
138
+ end
139
+
140
+ it 'finds interested streams for bare jids' do
141
+ subject.interested_resources(alice.bare, alice).size.must_equal 1
142
+ subject.interested_resources(alice.bare, alice)[0].user.jid.must_equal alice
143
+ end
144
+ end
145
+
146
+ describe '#delete' do
147
+ let(:stream1) { stream(alice) }
148
+ let(:stream2) { stream(hatter) }
149
+
150
+ it 'correctly adds and removes streams' do
151
+ subject.size.must_equal 0
152
+
153
+ subject << stream1
154
+ subject << stream2
155
+ subject.size.must_equal 2
156
+
157
+ subject.delete(stream2)
158
+ subject.size.must_equal 1
159
+
160
+ subject.delete(stream2)
161
+ subject.size.must_equal 1
162
+
163
+ subject.delete(stream1)
164
+ subject.size.must_equal 0
165
+ end
166
+ end
167
+
168
+ describe 'load balanced component streams' do
169
+ let(:stream1) { component('tea.wonderland.lit') }
170
+ let(:stream2) { component('tea.wonderland.lit') }
171
+ let(:stanza) { node('<message from="alice@wonderland.lit" to="tea.wonderland.lit">test</message>')}
172
+
173
+ before do
174
+ subject << stream1
175
+ subject << stream2
176
+ end
177
+
178
+ it 'must evenly distribute routed stanzas to both streams' do
179
+ 100.times { subject.route(stanza) }
180
+
181
+ (stream1.count + stream2.count).must_equal 100
182
+ stream1.count.must_be :>, 33
183
+ stream2.count.must_be :>, 33
184
+ end
185
+ end
186
+
187
+ describe 'load balanced s2s streams' do
188
+ let(:stream1) { s2s('wonderland.lit', 'verona.lit') }
189
+ let(:stream2) { s2s('wonderland.lit', 'verona.lit') }
190
+ let(:stanza) { node('<message from="alice@wonderland.lit" to="romeo@verona.lit">test</message>') }
191
+
192
+ before do
193
+ config.vhost('wonderland.lit').cross_domain_messages true
194
+ subject << stream1
195
+ subject << stream2
196
+ end
197
+
198
+ it 'must evenly distribute routed stanzas to both streams' do
199
+ 100.times { subject.route(stanza) }
200
+
201
+ (stream1.count + stream2.count).must_equal 100
202
+ stream1.count.must_be :>, 33
203
+ stream2.count.must_be :>, 33
204
+ end
205
+ end
206
+
207
+ private
208
+
209
+ def stream(jid)
210
+ OpenStruct.new.tap do |stream|
211
+ stream.send('connected?=', true)
212
+ stream.stream_type = :client
213
+ stream.user = Vines::User.new(jid: jid)
214
+ end
215
+ end
216
+
217
+ def component(jid)
218
+ OpenStruct.new.tap do |stream|
219
+ stream.stream_type = :component
220
+ stream.remote_domain = jid
221
+ stream.send('ready?=', true)
222
+ def stream.count; @count || 0; end
223
+ def stream.write(stanza)
224
+ @count ||= 0
225
+ @count += 1
226
+ end
227
+ end
228
+ end
229
+
230
+ def s2s(domain, remote_domain)
231
+ OpenStruct.new.tap do |stream|
232
+ stream.stream_type = :server
233
+ stream.domain = domain
234
+ stream.remote_domain = remote_domain
235
+ stream.send('ready?=', true)
236
+ def stream.count; @count || 0; end
237
+ def stream.write(stanza)
238
+ @count ||= 0
239
+ @count += 1
240
+ end
241
+ end
242
+ end
243
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq::DiscoInfo do
6
+ subject { Vines::Stanza::Iq::DiscoInfo.new(xml, stream) }
7
+ let(:stream) { MiniTest::Mock.new }
8
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/home') }
9
+ let(:config) do
10
+ Vines::Config.new do
11
+ host 'wonderland.lit' do
12
+ storage(:fs) { dir Dir.tmpdir }
13
+ end
14
+ end
15
+ end
16
+
17
+ let(:xml) do
18
+ query = %q{<query xmlns="http://jabber.org/protocol/disco#info"/>}
19
+ node(%Q{<iq id="42" to="wonderland.lit" type="get">#{query}</iq>})
20
+ end
21
+
22
+ before do
23
+ class << stream
24
+ attr_accessor :config, :user
25
+ end
26
+ stream.config = config
27
+ stream.user = alice
28
+ end
29
+
30
+ describe 'when private storage is disabled' do
31
+ let(:expected) do
32
+ node(%Q{
33
+ <iq from="wonderland.lit" id="42" to="#{alice.jid}" type="result">
34
+ <query xmlns="http://jabber.org/protocol/disco#info">
35
+ <identity category="server" type="im"/>
36
+ <feature var="http://jabber.org/protocol/disco#info"/>
37
+ <feature var="http://jabber.org/protocol/disco#items"/>
38
+ <feature var="urn:xmpp:ping"/>
39
+ <feature var="vcard-temp"/>
40
+ <feature var="jabber:iq:version"/>
41
+ </query>
42
+ </iq>
43
+ })
44
+ end
45
+
46
+ it 'returns info stanza without the private storage feature' do
47
+ config.vhost('wonderland.lit').private_storage false
48
+ stream.expect :write, nil, [expected]
49
+ subject.process
50
+ stream.verify
51
+ end
52
+ end
53
+
54
+ describe 'when private storage is enabled' do
55
+ let(:expected) do
56
+ node(%Q{
57
+ <iq from="wonderland.lit" id="42" to="#{alice.jid}" type="result">
58
+ <query xmlns="http://jabber.org/protocol/disco#info">
59
+ <identity category="server" type="im"/>
60
+ <feature var="http://jabber.org/protocol/disco#info"/>
61
+ <feature var="http://jabber.org/protocol/disco#items"/>
62
+ <feature var="urn:xmpp:ping"/>
63
+ <feature var="vcard-temp"/>
64
+ <feature var="jabber:iq:version"/>
65
+ <feature var="jabber:iq:private"/>
66
+ </query>
67
+ </iq>
68
+ })
69
+ end
70
+
71
+ it 'announces private storage feature in info stanza result' do
72
+ config.vhost('wonderland.lit').private_storage true
73
+ stream.expect :write, nil, [expected]
74
+ subject.process
75
+ stream.verify
76
+ end
77
+ end
78
+ end