vinesmod 0.4.5
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/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
|