vines 0.1.0
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.
- data/LICENSE +19 -0
- data/README +34 -0
- data/Rakefile +55 -0
- data/bin/vines +95 -0
- data/conf/certs/README +32 -0
- data/conf/certs/ca-bundle.crt +3987 -0
- data/conf/config.rb +114 -0
- data/lib/vines.rb +155 -0
- data/lib/vines/command/bcrypt.rb +12 -0
- data/lib/vines/command/cert.rb +49 -0
- data/lib/vines/command/init.rb +58 -0
- data/lib/vines/command/ldap.rb +35 -0
- data/lib/vines/command/restart.rb +12 -0
- data/lib/vines/command/schema.rb +24 -0
- data/lib/vines/command/start.rb +28 -0
- data/lib/vines/command/stop.rb +18 -0
- data/lib/vines/config.rb +191 -0
- data/lib/vines/contact.rb +99 -0
- data/lib/vines/daemon.rb +78 -0
- data/lib/vines/error.rb +150 -0
- data/lib/vines/jid.rb +56 -0
- data/lib/vines/kit.rb +23 -0
- data/lib/vines/router.rb +125 -0
- data/lib/vines/stanza.rb +55 -0
- data/lib/vines/stanza/iq.rb +50 -0
- data/lib/vines/stanza/iq/auth.rb +18 -0
- data/lib/vines/stanza/iq/disco_info.rb +25 -0
- data/lib/vines/stanza/iq/disco_items.rb +23 -0
- data/lib/vines/stanza/iq/error.rb +16 -0
- data/lib/vines/stanza/iq/ping.rb +16 -0
- data/lib/vines/stanza/iq/query.rb +10 -0
- data/lib/vines/stanza/iq/result.rb +16 -0
- data/lib/vines/stanza/iq/roster.rb +153 -0
- data/lib/vines/stanza/iq/session.rb +22 -0
- data/lib/vines/stanza/iq/vcard.rb +58 -0
- data/lib/vines/stanza/message.rb +41 -0
- data/lib/vines/stanza/presence.rb +119 -0
- data/lib/vines/stanza/presence/error.rb +23 -0
- data/lib/vines/stanza/presence/probe.rb +38 -0
- data/lib/vines/stanza/presence/subscribe.rb +66 -0
- data/lib/vines/stanza/presence/subscribed.rb +64 -0
- data/lib/vines/stanza/presence/unavailable.rb +15 -0
- data/lib/vines/stanza/presence/unsubscribe.rb +57 -0
- data/lib/vines/stanza/presence/unsubscribed.rb +50 -0
- data/lib/vines/storage.rb +216 -0
- data/lib/vines/storage/couchdb.rb +119 -0
- data/lib/vines/storage/ldap.rb +59 -0
- data/lib/vines/storage/local.rb +66 -0
- data/lib/vines/storage/redis.rb +108 -0
- data/lib/vines/storage/sql.rb +174 -0
- data/lib/vines/store.rb +51 -0
- data/lib/vines/stream.rb +198 -0
- data/lib/vines/stream/client.rb +131 -0
- data/lib/vines/stream/client/auth.rb +94 -0
- data/lib/vines/stream/client/auth_restart.rb +33 -0
- data/lib/vines/stream/client/bind.rb +58 -0
- data/lib/vines/stream/client/bind_restart.rb +25 -0
- data/lib/vines/stream/client/closed.rb +13 -0
- data/lib/vines/stream/client/ready.rb +15 -0
- data/lib/vines/stream/client/start.rb +27 -0
- data/lib/vines/stream/client/tls.rb +37 -0
- data/lib/vines/stream/component.rb +53 -0
- data/lib/vines/stream/component/handshake.rb +25 -0
- data/lib/vines/stream/component/ready.rb +24 -0
- data/lib/vines/stream/component/start.rb +19 -0
- data/lib/vines/stream/http.rb +111 -0
- data/lib/vines/stream/http/http_request.rb +22 -0
- data/lib/vines/stream/http/http_state.rb +139 -0
- data/lib/vines/stream/http/http_states.rb +53 -0
- data/lib/vines/stream/parser.rb +78 -0
- data/lib/vines/stream/server.rb +126 -0
- data/lib/vines/stream/server/auth.rb +13 -0
- data/lib/vines/stream/server/auth_restart.rb +19 -0
- data/lib/vines/stream/server/final_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/auth.rb +31 -0
- data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/auth_result.rb +28 -0
- data/lib/vines/stream/server/outbound/final_features.rb +27 -0
- data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/start.rb +20 -0
- data/lib/vines/stream/server/outbound/tls.rb +30 -0
- data/lib/vines/stream/server/outbound/tls_result.rb +31 -0
- data/lib/vines/stream/server/ready.rb +20 -0
- data/lib/vines/stream/server/start.rb +13 -0
- data/lib/vines/stream/server/tls.rb +13 -0
- data/lib/vines/stream/state.rb +55 -0
- data/lib/vines/token_bucket.rb +46 -0
- data/lib/vines/user.rb +124 -0
- data/lib/vines/version.rb +5 -0
- data/lib/vines/xmpp_server.rb +25 -0
- data/test/config_test.rb +396 -0
- data/test/error_test.rb +59 -0
- data/test/ext/nokogiri.rb +14 -0
- data/test/jid_test.rb +71 -0
- data/test/kit_test.rb +21 -0
- data/test/router_test.rb +60 -0
- data/test/stanza/iq/roster_test.rb +198 -0
- data/test/stanza/iq/session_test.rb +30 -0
- data/test/stanza/iq/vcard_test.rb +159 -0
- data/test/stanza/message_test.rb +124 -0
- data/test/stanza/presence/subscribe_test.rb +75 -0
- data/test/storage/couchdb_test.rb +102 -0
- data/test/storage/ldap_test.rb +207 -0
- data/test/storage/local_test.rb +54 -0
- data/test/storage/redis_test.rb +75 -0
- data/test/storage/sql_test.rb +55 -0
- data/test/storage/storage_tests.rb +134 -0
- data/test/storage_test.rb +90 -0
- data/test/stream/client/auth_test.rb +127 -0
- data/test/stream/client/ready_test.rb +47 -0
- data/test/stream/component/handshake_test.rb +46 -0
- data/test/stream/component/ready_test.rb +105 -0
- data/test/stream/component/start_test.rb +41 -0
- data/test/stream/parser_test.rb +121 -0
- data/test/stream/server/outbound/auth_test.rb +77 -0
- data/test/stream/server/ready_test.rb +100 -0
- data/test/token_bucket_test.rb +24 -0
- data/test/user_test.rb +64 -0
- metadata +318 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'vines'
|
|
4
|
+
require 'minitest/mock'
|
|
5
|
+
require 'test/unit'
|
|
6
|
+
|
|
7
|
+
class ClientReadyTest < Test::Unit::TestCase
|
|
8
|
+
STANZAS = []
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
@stream = MiniTest::Mock.new
|
|
12
|
+
@state = Vines::Stream::Client::Ready.new(@stream, nil)
|
|
13
|
+
def @state.to_stanza(node)
|
|
14
|
+
if node.name == 'bogus'
|
|
15
|
+
nil
|
|
16
|
+
else
|
|
17
|
+
MiniTest::Mock.new.tap do |stanza|
|
|
18
|
+
stanza.expect(:process, nil)
|
|
19
|
+
ClientReadyTest::STANZAS << stanza
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def teardown
|
|
26
|
+
STANZAS.clear
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_good_node_processes
|
|
30
|
+
node = node('<message/>')
|
|
31
|
+
assert_nothing_raised { @state.node(node) }
|
|
32
|
+
assert_equal 1, STANZAS.size
|
|
33
|
+
assert STANZAS.map {|s| s.verify }.all?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_unsupported_stanza_type
|
|
37
|
+
node = node('<bogus/>')
|
|
38
|
+
assert_raise(Vines::StreamErrors::UnsupportedStanzaType) { @state.node(node) }
|
|
39
|
+
assert STANZAS.empty?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def node(xml)
|
|
45
|
+
Nokogiri::XML(xml).root
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'vines'
|
|
4
|
+
require 'minitest/mock'
|
|
5
|
+
require 'test/unit'
|
|
6
|
+
|
|
7
|
+
class HandshakeTest < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@stream = MiniTest::Mock.new
|
|
10
|
+
@state = Vines::Stream::Component::Handshake.new(@stream)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_invalid_element
|
|
14
|
+
node = node('<message/>')
|
|
15
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_missing_text
|
|
19
|
+
@stream.expect(:secret, 'secr3t')
|
|
20
|
+
node = node('<handshake/>')
|
|
21
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
22
|
+
assert @stream.verify
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_invalid_secret
|
|
26
|
+
@stream.expect(:secret, 'secr3t')
|
|
27
|
+
node = node('<handshake>bogus</handshake>')
|
|
28
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
29
|
+
assert @stream.verify
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_valid_secret
|
|
33
|
+
@stream.expect(:secret, 'secr3t')
|
|
34
|
+
@stream.expect(:write, nil, ['<handshake/>'])
|
|
35
|
+
@stream.expect(:advance, nil, [Vines::Stream::Component::Ready.new(@stream)])
|
|
36
|
+
node = node('<handshake>secr3t</handshake>')
|
|
37
|
+
assert_nothing_raised { @state.node(node) }
|
|
38
|
+
assert @stream.verify
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def node(xml)
|
|
44
|
+
Nokogiri::XML(xml).root
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'vines'
|
|
4
|
+
require 'ext/nokogiri'
|
|
5
|
+
require 'minitest/mock'
|
|
6
|
+
require 'test/unit'
|
|
7
|
+
|
|
8
|
+
class ComponentReadyTest < Test::Unit::TestCase
|
|
9
|
+
STANZAS = []
|
|
10
|
+
|
|
11
|
+
def setup
|
|
12
|
+
@stream = MiniTest::Mock.new
|
|
13
|
+
@state = Vines::Stream::Component::Ready.new(@stream, nil)
|
|
14
|
+
def @state.to_stanza(node)
|
|
15
|
+
if node.name == 'bogus'
|
|
16
|
+
nil
|
|
17
|
+
else
|
|
18
|
+
MiniTest::Mock.new.tap do |stanza|
|
|
19
|
+
if node['to'] == 'hatter@wonderland.lit'
|
|
20
|
+
stanza.expect(:local?, true)
|
|
21
|
+
else
|
|
22
|
+
stanza.expect(:local?, false)
|
|
23
|
+
stanza.expect(:route, nil)
|
|
24
|
+
end
|
|
25
|
+
ComponentReadyTest::STANZAS << stanza
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def teardown
|
|
32
|
+
STANZAS.clear
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_missing_to_and_from_addresses
|
|
36
|
+
node = node('<message/>')
|
|
37
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
38
|
+
assert_equal 1, STANZAS.size
|
|
39
|
+
assert @stream.verify
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_missing_from_address
|
|
43
|
+
@stream.expect(:remote_domain, 'tea.wonderland.lit')
|
|
44
|
+
node = node(%q{<message to="hatter@wonderland.lit"/>})
|
|
45
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
46
|
+
assert_equal 1, STANZAS.size
|
|
47
|
+
assert @stream.verify
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_missing_to_address
|
|
51
|
+
node = node(%q{<message from="alice@tea.wonderland.lit"/>})
|
|
52
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
53
|
+
assert_equal 1, STANZAS.size
|
|
54
|
+
assert @stream.verify
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_invalid_from_address
|
|
58
|
+
@stream.expect(:remote_domain, 'tea.wonderland.lit')
|
|
59
|
+
node = node(%q{<message from="alice@bogus.wonderland.lit" to="hatter@wonderland.lit"/>})
|
|
60
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
61
|
+
assert_equal 1, STANZAS.size
|
|
62
|
+
assert @stream.verify
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_unsupported_stanza_type
|
|
66
|
+
node = node('<bogus/>')
|
|
67
|
+
assert_raise(Vines::StreamErrors::UnsupportedStanzaType) { @state.node(node) }
|
|
68
|
+
assert STANZAS.empty?
|
|
69
|
+
assert @stream.verify
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_remote_message_routes
|
|
73
|
+
@stream.expect(:remote_domain, 'tea.wonderland.lit')
|
|
74
|
+
node = node(%q{<message from="alice@tea.wonderland.lit" to="romeo@verona.lit"/>})
|
|
75
|
+
assert_nothing_raised { @state.node(node) }
|
|
76
|
+
assert_equal 1, STANZAS.size
|
|
77
|
+
assert STANZAS.map {|s| s.verify }.all?
|
|
78
|
+
assert @stream.verify
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_local_message_processes
|
|
82
|
+
node = node(%q{<message from="alice@tea.wonderland.lit" to="hatter@wonderland.lit"/>})
|
|
83
|
+
@stream.expect(:remote_domain, 'tea.wonderland.lit')
|
|
84
|
+
|
|
85
|
+
@recipient = MiniTest::Mock.new
|
|
86
|
+
@recipient.expect(:write, nil, [node])
|
|
87
|
+
|
|
88
|
+
@router = MiniTest::Mock.new
|
|
89
|
+
@router.expect(:connected_resources, [@recipient], ['hatter@wonderland.lit'])
|
|
90
|
+
@stream.expect(:router, @router)
|
|
91
|
+
|
|
92
|
+
assert_nothing_raised { @state.node(node) }
|
|
93
|
+
assert_equal 1, STANZAS.size
|
|
94
|
+
assert STANZAS.map {|s| s.verify }.all?
|
|
95
|
+
assert @stream.verify
|
|
96
|
+
assert @router.verify
|
|
97
|
+
assert @recipient.verify
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def node(xml)
|
|
103
|
+
Nokogiri::XML(xml).root
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'vines'
|
|
4
|
+
require 'minitest/mock'
|
|
5
|
+
require 'test/unit'
|
|
6
|
+
|
|
7
|
+
class ComponentStartTest < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@stream = MiniTest::Mock.new
|
|
10
|
+
@state = Vines::Stream::Component::Start.new(@stream)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_invalid_element
|
|
14
|
+
node = node('<message/>')
|
|
15
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_missing_stream_namespace
|
|
19
|
+
node = node('<stream:stream/>')
|
|
20
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_invalid_stream_namespace
|
|
24
|
+
node = node('<stream:stream xmlns="bogus"/>')
|
|
25
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_valid_stream_header
|
|
29
|
+
node = node(%q{<stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:component:accept" to="tea.wonderland.lit"/>})
|
|
30
|
+
@stream.expect(:start, nil, [node])
|
|
31
|
+
@stream.expect(:advance, nil, [Vines::Stream::Component::Handshake.new(@stream)])
|
|
32
|
+
assert_nothing_raised { @state.node(node) }
|
|
33
|
+
assert @stream.verify
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def node(xml)
|
|
39
|
+
Nokogiri::XML(xml).root
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'vines'
|
|
4
|
+
require 'test/unit'
|
|
5
|
+
|
|
6
|
+
class ParserTest < Test::Unit::TestCase
|
|
7
|
+
STREAM_START = '<stream:stream to="wonderland.lit" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">'.freeze
|
|
8
|
+
|
|
9
|
+
def setup
|
|
10
|
+
@events = []
|
|
11
|
+
@parser = Vines::Stream::Parser.new.tap do |p|
|
|
12
|
+
p.stream_open {|el| @events << el }
|
|
13
|
+
p.stream_close { @events << :close }
|
|
14
|
+
p.stanza {|el| @events << el }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_xpath_to_subclass
|
|
19
|
+
expected = []
|
|
20
|
+
stanzas = [
|
|
21
|
+
['<message></message>', Vines::Stanza::Message],
|
|
22
|
+
['<presence/>', Vines::Stanza::Presence],
|
|
23
|
+
['<presence type="bogus"/>', Vines::Stanza::Presence],
|
|
24
|
+
['<presence type="error"/>', Vines::Stanza::Presence::Error],
|
|
25
|
+
['<presence type="probe"/>', Vines::Stanza::Presence::Probe],
|
|
26
|
+
['<presence type="subscribe"/>', Vines::Stanza::Presence::Subscribe],
|
|
27
|
+
['<presence type="subscribed"/>', Vines::Stanza::Presence::Subscribed],
|
|
28
|
+
['<presence type="unavailable"/>', Vines::Stanza::Presence::Unavailable],
|
|
29
|
+
['<presence type="unsubscribe"/>', Vines::Stanza::Presence::Unsubscribe],
|
|
30
|
+
['<presence type="unsubscribed"/>', Vines::Stanza::Presence::Unsubscribed],
|
|
31
|
+
['<iq id="42" type="get"><query xmlns="http://jabber.org/protocol/disco#info"></query></iq>', Vines::Stanza::Iq::Query::DiscoInfo],
|
|
32
|
+
['<iq id="42" type="get"><query xmlns="http://jabber.org/protocol/disco#items"></query></iq>', Vines::Stanza::Iq::Query::DiscoItems],
|
|
33
|
+
['<iq id="42" type="error"></iq>', Vines::Stanza::Iq::Error],
|
|
34
|
+
['<iq id="42" type="get"><ping xmlns="urn:xmpp:ping"/></iq>', Vines::Stanza::Iq::Ping],
|
|
35
|
+
['<iq id="42" type="result"></iq>', Vines::Stanza::Iq::Result],
|
|
36
|
+
['<iq id="42" type="get"><query xmlns="jabber:iq:roster"/></iq>', Vines::Stanza::Iq::Query::Roster],
|
|
37
|
+
['<iq id="42" type="set"><query xmlns="jabber:iq:roster"/></iq>', Vines::Stanza::Iq::Query::Roster],
|
|
38
|
+
['<iq id="42" type="set"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>', Vines::Stanza::Iq::Session],
|
|
39
|
+
['<iq id="42" type="get"><vCard xmlns="vcard-temp"/></iq>', Vines::Stanza::Iq::Vcard],
|
|
40
|
+
['<iq type="get"><vCard xmlns="vcard-temp"/></iq>', Vines::Stanza::Iq],
|
|
41
|
+
['<iq id="42"><vCard xmlns="vcard-temp"/></iq>', Vines::Stanza::Iq],
|
|
42
|
+
['<iq><vCard xmlns="vcard-temp"/></iq>', Vines::Stanza::Iq],
|
|
43
|
+
['<bogus/>', NilClass],
|
|
44
|
+
]
|
|
45
|
+
@parser << STREAM_START
|
|
46
|
+
stanzas.each do |stanza, klass|
|
|
47
|
+
@parser << stanza
|
|
48
|
+
expected << klass
|
|
49
|
+
end
|
|
50
|
+
@parser << '</stream:stream>'
|
|
51
|
+
assert_equal 'stream', @events.shift.name
|
|
52
|
+
assert_equal :close, @events.pop
|
|
53
|
+
assert_equal expected.size, @events.size
|
|
54
|
+
@events.each_with_index do |ev, ix|
|
|
55
|
+
assert_equal expected[ix], Vines::Stanza.from_node(ev, nil).class
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_stream_namespace_with_default_prefix
|
|
60
|
+
@parser << STREAM_START
|
|
61
|
+
assert_equal 1, @events.size
|
|
62
|
+
stream = @events.shift
|
|
63
|
+
assert_equal 'stream', stream.name
|
|
64
|
+
assert_not_nil stream.namespace
|
|
65
|
+
assert_equal 'stream', stream.namespace.prefix
|
|
66
|
+
assert_equal 'http://etherx.jabber.org/streams', stream.namespace.href
|
|
67
|
+
expected = {'xmlns' => 'jabber:client', 'xmlns:stream' => 'http://etherx.jabber.org/streams'}
|
|
68
|
+
assert_equal expected, stream.namespaces
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_stanzas_ignore_default_namespace
|
|
72
|
+
@parser << STREAM_START
|
|
73
|
+
@parser << '<message to="alice@wonderland.lit">hello!</message>'
|
|
74
|
+
assert_equal 2, @events.size
|
|
75
|
+
@events.shift # discard stream
|
|
76
|
+
msg = @events.shift
|
|
77
|
+
assert_equal 'message', msg.name
|
|
78
|
+
assert msg.namespaces.empty?
|
|
79
|
+
assert_nil msg.namespace
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_nested_elements_have_namespace
|
|
83
|
+
@parser << STREAM_START
|
|
84
|
+
@parser << %q{
|
|
85
|
+
<iq from='alice@wonderland.lit/tea' id='42' type='set'>
|
|
86
|
+
<query xmlns='jabber:iq:roster'>
|
|
87
|
+
<item jid='hatter@wonderland.lit' name='Mad Hatter'>
|
|
88
|
+
<group>Tea Party</group>
|
|
89
|
+
</item>
|
|
90
|
+
</query>
|
|
91
|
+
</iq>
|
|
92
|
+
}
|
|
93
|
+
assert_equal 2, @events.size
|
|
94
|
+
@events.shift # discard stream
|
|
95
|
+
iq = @events.shift
|
|
96
|
+
assert_equal 'iq', iq.name
|
|
97
|
+
assert iq.namespaces.empty?
|
|
98
|
+
assert_nil iq.namespace
|
|
99
|
+
|
|
100
|
+
query = iq.elements.first
|
|
101
|
+
assert_not_nil query.namespace
|
|
102
|
+
assert_nil query.namespace.prefix
|
|
103
|
+
assert_equal 'jabber:iq:roster', query.namespace.href
|
|
104
|
+
expected = {'xmlns' => 'jabber:iq:roster'}
|
|
105
|
+
assert_equal expected, query.namespaces
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_error_stanzas_have_stream_namespace
|
|
109
|
+
@parser << STREAM_START
|
|
110
|
+
@parser << '<stream:error><not-well-formed xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></stream:error>'
|
|
111
|
+
assert_equal 2, @events.size
|
|
112
|
+
@events.shift # discard stream
|
|
113
|
+
error = @events.shift
|
|
114
|
+
assert_equal 'error', error.name
|
|
115
|
+
assert_not_nil error.namespace
|
|
116
|
+
assert_equal 'stream', error.namespace.prefix
|
|
117
|
+
assert_equal 'http://etherx.jabber.org/streams', error.namespace.href
|
|
118
|
+
expected = {'xmlns:stream' => 'http://etherx.jabber.org/streams'}
|
|
119
|
+
assert_equal expected, error.namespaces
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'vines'
|
|
4
|
+
require 'minitest/mock'
|
|
5
|
+
require 'test/unit'
|
|
6
|
+
|
|
7
|
+
class OutboundAuthTest < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@stream = MiniTest::Mock.new
|
|
10
|
+
@state = Vines::Stream::Server::Outbound::Auth.new(@stream)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_invalid_element
|
|
14
|
+
node = node('<message/>')
|
|
15
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_invalid_sasl_element
|
|
19
|
+
node = node(%Q{<message xmlns="#{Vines::NAMESPACES[:sasl]}"/>})
|
|
20
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_missing_namespace
|
|
24
|
+
node = node('<stream:features/>')
|
|
25
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_invalid_namespace
|
|
29
|
+
node = node('<stream:features xmlns="bogus"/>')
|
|
30
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_missing_mechanisms
|
|
34
|
+
node = node(%Q{<stream:features xmlns:stream="http://etherx.jabber.org/streams"/>})
|
|
35
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_missing_mechanisms_namespace
|
|
39
|
+
node = node(%Q{<stream:features xmlns:stream="http://etherx.jabber.org/streams"><mechanisms/></stream:features>})
|
|
40
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_missing_mechanism
|
|
44
|
+
mechanisms = %q{<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>}
|
|
45
|
+
node = node(%Q{<stream:features xmlns:stream="http://etherx.jabber.org/streams">#{mechanisms}</stream:features>})
|
|
46
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_missing_mechanism_text
|
|
50
|
+
mechanisms = %q{<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism></mechanism></mechanisms>}
|
|
51
|
+
node = node(%Q{<stream:features xmlns:stream="http://etherx.jabber.org/streams">#{mechanisms}</stream:features>})
|
|
52
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_invalid_mechanism_text
|
|
56
|
+
mechanisms = %q{<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>BOGUS</mechanism></mechanisms>}
|
|
57
|
+
node = node(%Q{<stream:features xmlns:stream="http://etherx.jabber.org/streams">#{mechanisms}</stream:features>})
|
|
58
|
+
assert_raise(Vines::StreamErrors::NotAuthorized) { @state.node(node) }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_valid_mechanism
|
|
62
|
+
@stream.expect(:domain, 'wonderland.lit')
|
|
63
|
+
expected = %Q{<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="EXTERNAL">d29uZGVybGFuZC5saXQ=</auth>}
|
|
64
|
+
@stream.expect(:write, nil, [expected])
|
|
65
|
+
@stream.expect(:advance, nil, [Vines::Stream::Server::Outbound::AuthResult.new(@stream)])
|
|
66
|
+
mechanisms = %q{<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>EXTERNAL</mechanism></mechanisms>}
|
|
67
|
+
node = node(%Q{<stream:features xmlns:stream="http://etherx.jabber.org/streams">#{mechanisms}</stream:features>})
|
|
68
|
+
assert_nothing_raised { @state.node(node) }
|
|
69
|
+
assert @stream.verify
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def node(xml)
|
|
75
|
+
Nokogiri::XML(xml).root
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'vines'
|
|
4
|
+
require 'minitest/mock'
|
|
5
|
+
require 'test/unit'
|
|
6
|
+
|
|
7
|
+
class ServerReadyTest < Test::Unit::TestCase
|
|
8
|
+
STANZAS = []
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
@stream = MiniTest::Mock.new
|
|
12
|
+
@state = Vines::Stream::Server::Ready.new(@stream, nil)
|
|
13
|
+
def @state.to_stanza(node)
|
|
14
|
+
if node.name == 'bogus'
|
|
15
|
+
nil
|
|
16
|
+
else
|
|
17
|
+
MiniTest::Mock.new.tap do |stanza|
|
|
18
|
+
stanza.expect(:process, nil)
|
|
19
|
+
stanza.class.send(:define_method, :[]) do |a|
|
|
20
|
+
node[a]
|
|
21
|
+
end
|
|
22
|
+
ServerReadyTest::STANZAS << stanza
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def teardown
|
|
29
|
+
STANZAS.clear
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_good_node_processes
|
|
33
|
+
@stream.expect(:remote_domain, 'wonderland.lit')
|
|
34
|
+
@stream.expect(:domain, 'verona.lit')
|
|
35
|
+
@stream.expect(:user=, nil, [Vines::User.new(:jid => 'alice@wonderland.lit')])
|
|
36
|
+
node = node(%Q{<message from="alice@wonderland.lit" to="romeo@verona.lit"/>})
|
|
37
|
+
assert_nothing_raised { @state.node(node) }
|
|
38
|
+
assert_equal 1, STANZAS.size
|
|
39
|
+
assert STANZAS.map {|s| s.verify }.all?
|
|
40
|
+
assert @stream.verify
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_unsupported_stanza_type
|
|
44
|
+
node = node('<bogus/>')
|
|
45
|
+
assert_raise(Vines::StreamErrors::UnsupportedStanzaType) { @state.node(node) }
|
|
46
|
+
assert STANZAS.empty?
|
|
47
|
+
assert @stream.verify
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_improper_addressing_missing_to
|
|
51
|
+
node = node(%Q{<message from="alice@wonderland.lit"/>})
|
|
52
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
53
|
+
assert_equal 1, STANZAS.size
|
|
54
|
+
assert @stream.verify
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_improper_addressing_empty_to
|
|
58
|
+
node = node(%Q{<message from="alice@wonderland.lit" to=" "/>})
|
|
59
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
60
|
+
assert_equal 1, STANZAS.size
|
|
61
|
+
assert @stream.verify
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_improper_addressing_missing_from
|
|
65
|
+
node = node(%Q{<message to="romeo@verona.lit"/>})
|
|
66
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
67
|
+
assert_equal 1, STANZAS.size
|
|
68
|
+
assert @stream.verify
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_improper_addressing_empty_from
|
|
72
|
+
node = node(%Q{<message from=" " to="romeo@verona.lit"/>})
|
|
73
|
+
assert_raise(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
|
|
74
|
+
assert_equal 1, STANZAS.size
|
|
75
|
+
assert @stream.verify
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_invalid_from
|
|
79
|
+
@stream.expect(:remote_domain, 'wonderland.lit')
|
|
80
|
+
node = node(%Q{<message from="alice@bogus.lit" to="romeo@verona.lit"/>})
|
|
81
|
+
assert_raise(Vines::StreamErrors::InvalidFrom) { @state.node(node) }
|
|
82
|
+
assert_equal 1, STANZAS.size
|
|
83
|
+
assert @stream.verify
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def test_host_unknown
|
|
87
|
+
@stream.expect(:remote_domain, 'wonderland.lit')
|
|
88
|
+
@stream.expect(:domain, 'verona.lit')
|
|
89
|
+
node = node(%Q{<message from="alice@wonderland.lit" to="romeo@bogus.lit"/>})
|
|
90
|
+
assert_raise(Vines::StreamErrors::HostUnknown) { @state.node(node) }
|
|
91
|
+
assert_equal 1, STANZAS.size
|
|
92
|
+
assert @stream.verify
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def node(xml)
|
|
98
|
+
Nokogiri::XML(xml).root
|
|
99
|
+
end
|
|
100
|
+
end
|