vinesmod 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +43 -0
- data/Rakefile +57 -0
- data/bin/vines +93 -0
- data/conf/certs/README +39 -0
- data/conf/certs/ca-bundle.crt +3366 -0
- data/conf/config.rb +149 -0
- data/lib/vines.rb +197 -0
- data/lib/vines/cluster.rb +246 -0
- data/lib/vines/cluster/connection.rb +26 -0
- data/lib/vines/cluster/publisher.rb +55 -0
- data/lib/vines/cluster/pubsub.rb +92 -0
- data/lib/vines/cluster/sessions.rb +125 -0
- data/lib/vines/cluster/subscriber.rb +108 -0
- data/lib/vines/command/bcrypt.rb +12 -0
- data/lib/vines/command/cert.rb +50 -0
- data/lib/vines/command/init.rb +68 -0
- data/lib/vines/command/register.rb +27 -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/command/unregister.rb +27 -0
- data/lib/vines/config.rb +213 -0
- data/lib/vines/config/host.rb +119 -0
- data/lib/vines/config/port.rb +132 -0
- data/lib/vines/config/pubsub.rb +108 -0
- data/lib/vines/contact.rb +111 -0
- data/lib/vines/daemon.rb +78 -0
- data/lib/vines/error.rb +150 -0
- data/lib/vines/jid.rb +95 -0
- data/lib/vines/kit.rb +35 -0
- data/lib/vines/log.rb +24 -0
- data/lib/vines/router.rb +179 -0
- data/lib/vines/stanza.rb +175 -0
- data/lib/vines/stanza/iq.rb +48 -0
- data/lib/vines/stanza/iq/auth.rb +18 -0
- data/lib/vines/stanza/iq/disco_info.rb +45 -0
- data/lib/vines/stanza/iq/disco_items.rb +29 -0
- data/lib/vines/stanza/iq/error.rb +16 -0
- data/lib/vines/stanza/iq/ping.rb +16 -0
- data/lib/vines/stanza/iq/private_storage.rb +83 -0
- data/lib/vines/stanza/iq/query.rb +10 -0
- data/lib/vines/stanza/iq/register.rb +42 -0
- data/lib/vines/stanza/iq/result.rb +16 -0
- data/lib/vines/stanza/iq/roster.rb +140 -0
- data/lib/vines/stanza/iq/session.rb +17 -0
- data/lib/vines/stanza/iq/vcard.rb +56 -0
- data/lib/vines/stanza/iq/version.rb +25 -0
- data/lib/vines/stanza/message.rb +43 -0
- data/lib/vines/stanza/presence.rb +156 -0
- data/lib/vines/stanza/presence/error.rb +23 -0
- data/lib/vines/stanza/presence/probe.rb +37 -0
- data/lib/vines/stanza/presence/subscribe.rb +42 -0
- data/lib/vines/stanza/presence/subscribed.rb +51 -0
- data/lib/vines/stanza/presence/unavailable.rb +15 -0
- data/lib/vines/stanza/presence/unsubscribe.rb +38 -0
- data/lib/vines/stanza/presence/unsubscribed.rb +38 -0
- data/lib/vines/stanza/pubsub.rb +22 -0
- data/lib/vines/stanza/pubsub/create.rb +39 -0
- data/lib/vines/stanza/pubsub/delete.rb +41 -0
- data/lib/vines/stanza/pubsub/publish.rb +66 -0
- data/lib/vines/stanza/pubsub/subscribe.rb +44 -0
- data/lib/vines/stanza/pubsub/unsubscribe.rb +30 -0
- data/lib/vines/storage.rb +188 -0
- data/lib/vines/storage/local.rb +165 -0
- data/lib/vines/storage/null.rb +39 -0
- data/lib/vines/storage/sql.rb +260 -0
- data/lib/vines/store.rb +94 -0
- data/lib/vines/stream.rb +247 -0
- data/lib/vines/stream/client.rb +84 -0
- data/lib/vines/stream/client/auth.rb +74 -0
- data/lib/vines/stream/client/auth_restart.rb +29 -0
- data/lib/vines/stream/client/bind.rb +72 -0
- data/lib/vines/stream/client/bind_restart.rb +24 -0
- data/lib/vines/stream/client/closed.rb +13 -0
- data/lib/vines/stream/client/ready.rb +17 -0
- data/lib/vines/stream/client/session.rb +210 -0
- data/lib/vines/stream/client/start.rb +27 -0
- data/lib/vines/stream/client/tls.rb +38 -0
- data/lib/vines/stream/component.rb +58 -0
- data/lib/vines/stream/component/handshake.rb +26 -0
- data/lib/vines/stream/component/ready.rb +23 -0
- data/lib/vines/stream/component/start.rb +19 -0
- data/lib/vines/stream/http.rb +157 -0
- data/lib/vines/stream/http/auth.rb +22 -0
- data/lib/vines/stream/http/bind.rb +32 -0
- data/lib/vines/stream/http/bind_restart.rb +37 -0
- data/lib/vines/stream/http/ready.rb +29 -0
- data/lib/vines/stream/http/request.rb +172 -0
- data/lib/vines/stream/http/session.rb +120 -0
- data/lib/vines/stream/http/sessions.rb +65 -0
- data/lib/vines/stream/http/start.rb +23 -0
- data/lib/vines/stream/parser.rb +78 -0
- data/lib/vines/stream/sasl.rb +92 -0
- data/lib/vines/stream/server.rb +150 -0
- data/lib/vines/stream/server/auth.rb +13 -0
- data/lib/vines/stream/server/auth_restart.rb +13 -0
- data/lib/vines/stream/server/final_restart.rb +21 -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 +32 -0
- data/lib/vines/stream/server/outbound/final_features.rb +28 -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 +34 -0
- data/lib/vines/stream/server/ready.rb +24 -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 +60 -0
- data/lib/vines/token_bucket.rb +55 -0
- data/lib/vines/user.rb +123 -0
- data/lib/vines/version.rb +5 -0
- data/lib/vines/xmpp_server.rb +43 -0
- data/vines.gemspec +36 -0
- data/web/404.html +51 -0
- data/web/apple-touch-icon.png +0 -0
- data/web/chat/coffeescripts/chat.coffee +362 -0
- data/web/chat/coffeescripts/init.coffee +15 -0
- data/web/chat/index.html +16 -0
- data/web/chat/javascripts/app.js +1 -0
- data/web/chat/stylesheets/chat.css +144 -0
- data/web/favicon.png +0 -0
- data/web/lib/coffeescripts/button.coffee +25 -0
- data/web/lib/coffeescripts/contact.coffee +32 -0
- data/web/lib/coffeescripts/filter.coffee +49 -0
- data/web/lib/coffeescripts/layout.coffee +30 -0
- data/web/lib/coffeescripts/login.coffee +68 -0
- data/web/lib/coffeescripts/logout.coffee +5 -0
- data/web/lib/coffeescripts/navbar.coffee +84 -0
- data/web/lib/coffeescripts/notification.coffee +14 -0
- data/web/lib/coffeescripts/router.coffee +40 -0
- data/web/lib/coffeescripts/session.coffee +229 -0
- data/web/lib/coffeescripts/transfer.coffee +106 -0
- data/web/lib/images/dark-gray.png +0 -0
- data/web/lib/images/default-user.png +0 -0
- data/web/lib/images/light-gray.png +0 -0
- data/web/lib/images/logo-large.png +0 -0
- data/web/lib/images/logo-small.png +0 -0
- data/web/lib/images/white.png +0 -0
- data/web/lib/javascripts/base.js +12 -0
- data/web/lib/javascripts/icons.js +110 -0
- data/web/lib/javascripts/jquery.cookie.js +91 -0
- data/web/lib/javascripts/jquery.js +4 -0
- data/web/lib/javascripts/raphael.js +6 -0
- data/web/lib/javascripts/strophe.js +1 -0
- data/web/lib/stylesheets/base.css +385 -0
- data/web/lib/stylesheets/login.css +68 -0
- metadata +423 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class FinalRestart < State
|
7
|
+
def initialize(stream, success=Ready)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def node(node)
|
12
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
13
|
+
stream.start(node)
|
14
|
+
stream.write('<stream:features/>')
|
15
|
+
stream.router << stream
|
16
|
+
advance
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class Auth < State
|
8
|
+
NS = NAMESPACES[:sasl]
|
9
|
+
|
10
|
+
def initialize(stream, success=AuthResult)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def node(node)
|
15
|
+
raise StreamErrors::NotAuthorized unless external?(node)
|
16
|
+
authzid = Base64.strict_encode64(stream.domain)
|
17
|
+
stream.write(%Q{<auth xmlns="#{NS}" mechanism="EXTERNAL">#{authzid}</auth>})
|
18
|
+
advance
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def external?(node)
|
24
|
+
external = node.xpath("ns:mechanisms/ns:mechanism[text()='EXTERNAL']", 'ns' => NS).any?
|
25
|
+
node.name == 'features' && namespace(node) == NAMESPACES[:stream] && external
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class AuthRestart < State
|
8
|
+
def initialize(stream, success=Auth)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def node(node)
|
13
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
14
|
+
advance
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class AuthResult < State
|
8
|
+
SUCCESS = 'success'.freeze
|
9
|
+
FAILURE = 'failure'.freeze
|
10
|
+
|
11
|
+
def initialize(stream, success=FinalRestart)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def node(node)
|
16
|
+
raise StreamErrors::NotAuthorized unless namespace(node) == NAMESPACES[:sasl]
|
17
|
+
case node.name
|
18
|
+
when SUCCESS
|
19
|
+
stream.start(node)
|
20
|
+
stream.reset
|
21
|
+
advance
|
22
|
+
when FAILURE
|
23
|
+
stream.close_connection
|
24
|
+
else
|
25
|
+
raise StreamErrors::NotAuthorized
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class FinalFeatures < State
|
8
|
+
def initialize(stream, success=Server::Ready)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def node(node)
|
13
|
+
raise StreamErrors::NotAuthorized unless empty_features?(node)
|
14
|
+
stream.router << stream
|
15
|
+
advance
|
16
|
+
stream.notify_connected
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def empty_features?(node)
|
22
|
+
node.name == 'features' && namespace(node) == NAMESPACES[:stream] && node.elements.empty?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class FinalRestart < State
|
8
|
+
def initialize(stream, success=FinalFeatures)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def node(node)
|
13
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
14
|
+
advance
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class Start < State
|
8
|
+
def initialize(stream, success=TLS)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def node(node)
|
13
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
14
|
+
advance
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class TLS < State
|
8
|
+
NS = NAMESPACES[:tls]
|
9
|
+
|
10
|
+
def initialize(stream, success=TLSResult)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def node(node)
|
15
|
+
raise StreamErrors::NotAuthorized unless tls?(node)
|
16
|
+
stream.write("<starttls xmlns='#{NS}'/>")
|
17
|
+
advance
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def tls?(node)
|
23
|
+
tls = node.xpath('ns:starttls', 'ns' => NS).any?
|
24
|
+
node.name == 'features' && namespace(node) == NAMESPACES[:stream] && tls
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Outbound
|
7
|
+
class TLSResult < State
|
8
|
+
NS = NAMESPACES[:tls]
|
9
|
+
PROCEED = 'proceed'.freeze
|
10
|
+
FAILURE = 'failure'.freeze
|
11
|
+
|
12
|
+
def initialize(stream, success=AuthRestart)
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def node(node)
|
17
|
+
raise StreamErrors::NotAuthorized unless namespace(node) == NS
|
18
|
+
case node.name
|
19
|
+
when PROCEED
|
20
|
+
stream.encrypt
|
21
|
+
stream.start(node)
|
22
|
+
stream.reset
|
23
|
+
advance
|
24
|
+
when FAILURE
|
25
|
+
stream.close_connection
|
26
|
+
else
|
27
|
+
raise StreamErrors::NotAuthorized
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
class Server
|
6
|
+
class Ready < State
|
7
|
+
def node(node)
|
8
|
+
stanza = to_stanza(node)
|
9
|
+
raise StreamErrors::UnsupportedStanzaType unless stanza
|
10
|
+
to, from = stanza.validate_to, stanza.validate_from
|
11
|
+
raise StreamErrors::ImproperAddressing unless to && from
|
12
|
+
raise StreamErrors::InvalidFrom unless from.domain == stream.remote_domain
|
13
|
+
raise StreamErrors::HostUnknown unless to.domain == stream.domain
|
14
|
+
stream.user = User.new(jid: from)
|
15
|
+
if stanza.local? || stanza.to_pubsub_domain?
|
16
|
+
stanza.process
|
17
|
+
else
|
18
|
+
stanza.route
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stream
|
5
|
+
|
6
|
+
# The base class of Stream state machines. States know how to process XML
|
7
|
+
# nodes and advance to their next valid state or fail the stream.
|
8
|
+
class State
|
9
|
+
include Nokogiri::XML
|
10
|
+
include Vines::Log
|
11
|
+
|
12
|
+
attr_accessor :stream
|
13
|
+
|
14
|
+
BODY = 'body'.freeze
|
15
|
+
STREAM = 'stream'.freeze
|
16
|
+
|
17
|
+
def initialize(stream, success=nil)
|
18
|
+
@stream, @success = stream, success
|
19
|
+
end
|
20
|
+
|
21
|
+
def node(node)
|
22
|
+
raise 'subclass must implement'
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(state)
|
26
|
+
self.class == state.class
|
27
|
+
end
|
28
|
+
|
29
|
+
def eql?(state)
|
30
|
+
state.is_a?(State) && self == state
|
31
|
+
end
|
32
|
+
|
33
|
+
def hash
|
34
|
+
self.class.hash
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def advance
|
40
|
+
stream.advance(@success.new(stream))
|
41
|
+
end
|
42
|
+
|
43
|
+
def stream?(node)
|
44
|
+
node.name == STREAM && namespace(node) == NAMESPACES[:stream]
|
45
|
+
end
|
46
|
+
|
47
|
+
def body?(node)
|
48
|
+
node.name == BODY && namespace(node) == NAMESPACES[:http_bind]
|
49
|
+
end
|
50
|
+
|
51
|
+
def namespace(node)
|
52
|
+
node.namespace ? node.namespace.href : nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_stanza(node)
|
56
|
+
Stanza.from_node(node, stream)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
|
5
|
+
# The token bucket algorithm is useful for rate limiting.
|
6
|
+
# Before an operation can be completed, a token is taken from
|
7
|
+
# the bucket. If no tokens are available, the operation fails.
|
8
|
+
# The bucket is refilled with tokens at the maximum allowed rate
|
9
|
+
# of operations.
|
10
|
+
class TokenBucket
|
11
|
+
|
12
|
+
# Create a full bucket with `capacity` number of tokens to be filled
|
13
|
+
# at the given rate of tokens/second.
|
14
|
+
#
|
15
|
+
# capacity - The Fixnum maximum number of tokens the bucket can hold.
|
16
|
+
# rate - The Fixnum number of tokens per second at which the bucket is
|
17
|
+
# refilled.
|
18
|
+
def initialize(capacity, rate)
|
19
|
+
raise ArgumentError.new('capacity must be > 0') unless capacity > 0
|
20
|
+
raise ArgumentError.new('rate must be > 0') unless rate > 0
|
21
|
+
@capacity = capacity
|
22
|
+
@tokens = capacity
|
23
|
+
@rate = rate
|
24
|
+
@timestamp = Time.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Remove tokens from the bucket if it's full enough. There's no way, or
|
28
|
+
# need, to add tokens to the bucket. It refills over time.
|
29
|
+
#
|
30
|
+
# tokens - The Fixnum number of tokens to attempt to take from the bucket.
|
31
|
+
#
|
32
|
+
# Returns true if the bucket contains enough tokens to take, false if the
|
33
|
+
# bucket isn't full enough to satisy the request.
|
34
|
+
def take(tokens)
|
35
|
+
raise ArgumentError.new('tokens must be > 0') unless tokens > 0
|
36
|
+
tokens <= fill ? @tokens -= tokens : false
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Add tokens to the bucket at the `rate` provided in the constructor. This
|
42
|
+
# fills the bucket slowly over time.
|
43
|
+
#
|
44
|
+
# Returns the Fixnum number of tokens left in the bucket.
|
45
|
+
def fill
|
46
|
+
if @tokens < @capacity
|
47
|
+
now = Time.new
|
48
|
+
@tokens += (@rate * (now - @timestamp)).round
|
49
|
+
@tokens = @capacity if @tokens > @capacity
|
50
|
+
@timestamp = now
|
51
|
+
end
|
52
|
+
@tokens
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|