vines 0.2.1 → 0.3.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/README +1 -1
- data/Rakefile +10 -10
- data/conf/certs/ca-bundle.crt +112 -378
- data/conf/config.rb +18 -9
- data/lib/vines.rb +8 -1
- data/lib/vines/command/cert.rb +2 -1
- data/lib/vines/command/init.rb +11 -0
- data/lib/vines/command/ldap.rb +6 -3
- data/lib/vines/command/schema.rb +1 -1
- data/lib/vines/config.rb +57 -146
- data/lib/vines/config/host.rb +85 -0
- data/lib/vines/config/port.rb +111 -0
- data/lib/vines/contact.rb +1 -1
- data/lib/vines/jid.rb +26 -4
- data/lib/vines/kit.rb +6 -0
- data/lib/vines/log.rb +24 -0
- data/lib/vines/router.rb +70 -38
- data/lib/vines/stanza.rb +45 -8
- data/lib/vines/stanza/iq.rb +3 -3
- data/lib/vines/stanza/iq/disco_info.rb +5 -1
- data/lib/vines/stanza/iq/disco_items.rb +3 -0
- data/lib/vines/stanza/iq/private_storage.rb +9 -5
- data/lib/vines/stanza/iq/roster.rb +11 -12
- data/lib/vines/stanza/iq/vcard.rb +4 -4
- data/lib/vines/stanza/iq/version.rb +25 -0
- data/lib/vines/stanza/message.rb +4 -5
- data/lib/vines/stanza/presence.rb +20 -18
- data/lib/vines/stanza/presence/probe.rb +3 -4
- data/lib/vines/stanza/presence/subscribe.rb +4 -3
- data/lib/vines/stanza/presence/subscribed.rb +6 -5
- data/lib/vines/stanza/presence/unsubscribe.rb +4 -4
- data/lib/vines/stanza/presence/unsubscribed.rb +4 -3
- data/lib/vines/storage/couchdb.rb +3 -3
- data/lib/vines/storage/ldap.rb +19 -8
- data/lib/vines/storage/local.rb +23 -12
- data/lib/vines/storage/redis.rb +3 -3
- data/lib/vines/storage/sql.rb +5 -5
- data/lib/vines/stream.rb +40 -6
- data/lib/vines/stream/client.rb +5 -6
- data/lib/vines/stream/client/auth.rb +3 -2
- data/lib/vines/stream/client/bind.rb +2 -2
- data/lib/vines/stream/client/bind_restart.rb +1 -2
- data/lib/vines/stream/client/ready.rb +2 -0
- data/lib/vines/stream/client/session.rb +13 -4
- data/lib/vines/stream/client/tls.rb +1 -0
- data/lib/vines/stream/component.rb +6 -5
- data/lib/vines/stream/component/ready.rb +5 -6
- data/lib/vines/stream/http.rb +10 -4
- data/lib/vines/stream/http/request.rb +23 -2
- data/lib/vines/stream/server.rb +13 -11
- data/lib/vines/stream/server/outbound/auth_result.rb +1 -0
- data/lib/vines/stream/server/outbound/tls_result.rb +1 -0
- data/lib/vines/stream/server/ready.rb +2 -2
- data/lib/vines/user.rb +2 -1
- data/lib/vines/version.rb +1 -1
- data/test/config/host_test.rb +292 -0
- data/test/config_test.rb +244 -103
- data/test/contact_test.rb +7 -1
- data/test/jid_test.rb +48 -0
- data/test/router_test.rb +16 -47
- data/test/stanza/iq/disco_info_test.rb +76 -0
- data/test/stanza/iq/disco_items_test.rb +47 -0
- data/test/stanza/iq/private_storage_test.rb +33 -10
- data/test/stanza/iq/roster_test.rb +15 -5
- data/test/stanza/iq/vcard_test.rb +8 -25
- data/test/stanza/iq/version_test.rb +62 -0
- data/test/stanza/iq_test.rb +13 -10
- data/test/stanza/message_test.rb +16 -24
- data/test/stanza/presence/probe_test.rb +52 -0
- data/test/stanza/presence/subscribe_test.rb +1 -5
- data/test/stanza_test.rb +77 -0
- data/test/stream/client/auth_test.rb +1 -0
- data/test/stream/client/ready_test.rb +2 -0
- data/test/stream/client/session_test.rb +7 -2
- data/test/stream/component/ready_test.rb +19 -36
- data/test/stream/http/request_test.rb +22 -2
- data/test/stream/server/ready_test.rb +14 -21
- data/web/404.html +9 -3
- data/web/chat/index.html +2 -2
- data/web/chat/javascripts/app.js +1 -1
- data/web/chat/stylesheets/chat.css +4 -9
- data/web/lib/coffeescripts/layout.coffee +2 -2
- data/web/{chat → lib}/coffeescripts/logout.coffee +0 -0
- data/web/lib/coffeescripts/notification.coffee +14 -0
- data/web/lib/coffeescripts/session.coffee +28 -24
- data/web/lib/coffeescripts/transfer.coffee +37 -34
- data/web/lib/javascripts/base.js +8 -8
- data/web/lib/javascripts/icons.js +3 -0
- data/web/lib/javascripts/jquery.js +4 -18
- data/web/lib/javascripts/layout.js +2 -2
- data/web/{chat → lib}/javascripts/logout.js +0 -0
- data/web/lib/javascripts/notification.js +26 -0
- data/web/lib/javascripts/session.js +20 -16
- data/web/lib/javascripts/transfer.js +45 -55
- data/web/lib/stylesheets/base.css +45 -9
- metadata +31 -15
data/conf/config.rb
CHANGED
@@ -16,17 +16,28 @@ Vines::Config.configure do
|
|
16
16
|
# command. Change the example, 'wonderland.lit', domain name to your actual
|
17
17
|
# domain.
|
18
18
|
#
|
19
|
+
# The private_storage attribute allows clients to store XML fragments
|
20
|
+
# on the server, using the XEP-0049 Private XML Storage feature.
|
21
|
+
#
|
19
22
|
# Shared storage example:
|
20
23
|
# host 'verona.lit', 'wonderland.lit' do
|
24
|
+
# private_storage false
|
25
|
+
# cross_domain_messages false
|
21
26
|
# storage 'fs' do
|
22
27
|
# dir 'data/users'
|
23
28
|
# end
|
29
|
+
# components 'tea' => 'secr3t',
|
30
|
+
# 'cake' => 'passw0rd'
|
24
31
|
# end
|
25
32
|
|
26
33
|
host 'wonderland.lit' do
|
34
|
+
cross_domain_messages false
|
35
|
+
private_storage false
|
27
36
|
storage 'fs' do
|
28
37
|
dir 'data/users'
|
29
38
|
end
|
39
|
+
# components 'tea' => 'secr3t',
|
40
|
+
# 'cake' => 'passw0rd'
|
30
41
|
end
|
31
42
|
|
32
43
|
# Hosts can use LDAP authentication that overrides the authentication
|
@@ -35,6 +46,8 @@ Vines::Config.configure do
|
|
35
46
|
# information, like rosters, is still saved in the storage database.
|
36
47
|
#
|
37
48
|
# host 'wonderland.lit' do
|
49
|
+
# cross_domain_messages false
|
50
|
+
# private_storage false
|
38
51
|
# storage 'fs' do
|
39
52
|
# dir 'data/users'
|
40
53
|
# end
|
@@ -42,19 +55,19 @@ Vines::Config.configure do
|
|
42
55
|
# dn 'cn=Directory Manager'
|
43
56
|
# password 'secr3t'
|
44
57
|
# basedn 'dc=wonderland,dc=lit'
|
58
|
+
# groupdn 'cn=chatters,dc=wonderland,dc=lit' # optional
|
45
59
|
# object_class 'person'
|
46
60
|
# user_attr 'uid'
|
47
61
|
# name_attr 'cn'
|
48
62
|
# tls true
|
49
63
|
# end
|
64
|
+
# components 'tea' => 'secr3t',
|
65
|
+
# 'cake' => 'passw0rd'
|
50
66
|
# end
|
51
67
|
|
52
68
|
# Configure the client-to-server port. The max_resources_per_account attribute
|
53
69
|
# limits how many concurrent connections one user can have to the server.
|
54
|
-
# The private_storage attribute allows clients to store XML fragments
|
55
|
-
# on the server, using the XEP-0049 Private XML Storage feature.
|
56
70
|
client '0.0.0.0', 5222 do
|
57
|
-
private_storage true
|
58
71
|
max_stanza_size 65536
|
59
72
|
max_resources_per_account 5
|
60
73
|
end
|
@@ -75,19 +88,15 @@ Vines::Config.configure do
|
|
75
88
|
# the URL to which BOSH clients must POST their XMPP stanza requests.
|
76
89
|
http '0.0.0.0', 5280 do
|
77
90
|
bind '/xmpp'
|
78
|
-
private_storage true
|
79
91
|
max_stanza_size 65536
|
80
92
|
max_resources_per_account 5
|
81
93
|
root 'web'
|
82
94
|
end
|
83
95
|
|
84
|
-
# Configure the XEP-0114 external component port.
|
85
|
-
#
|
86
|
-
# authenticate with a password.
|
96
|
+
# Configure the XEP-0114 external component port. Component sub-domains and
|
97
|
+
# their passwords are defined with their virtual host entries above.
|
87
98
|
component '0.0.0.0', 5347 do
|
88
99
|
max_stanza_size 131072
|
89
|
-
#components 'tea.wonderland.lit' => 'secr3t',
|
90
|
-
# 'cake.wonderland.lit' => 'passw0rd'
|
91
100
|
end
|
92
101
|
end
|
93
102
|
|
data/lib/vines.rb
CHANGED
@@ -9,6 +9,7 @@ module Vines
|
|
9
9
|
:roster => 'jabber:iq:roster'.freeze,
|
10
10
|
:non_sasl => 'jabber:iq:auth'.freeze,
|
11
11
|
:storage => 'jabber:iq:private'.freeze,
|
12
|
+
:version => 'jabber:iq:version'.freeze,
|
12
13
|
:sasl => 'urn:ietf:params:xml:ns:xmpp-sasl'.freeze,
|
13
14
|
:tls => 'urn:ietf:params:xml:ns:xmpp-tls'.freeze,
|
14
15
|
:bind => 'urn:ietf:params:xml:ns:xmpp-bind'.freeze,
|
@@ -65,7 +66,9 @@ end
|
|
65
66
|
uri
|
66
67
|
yaml
|
67
68
|
|
69
|
+
vines/log
|
68
70
|
vines/jid
|
71
|
+
|
69
72
|
vines/stanza
|
70
73
|
vines/stanza/iq
|
71
74
|
vines/stanza/iq/query
|
@@ -79,6 +82,7 @@ end
|
|
79
82
|
vines/stanza/iq/roster
|
80
83
|
vines/stanza/iq/session
|
81
84
|
vines/stanza/iq/vcard
|
85
|
+
vines/stanza/iq/version
|
82
86
|
vines/stanza/message
|
83
87
|
vines/stanza/presence
|
84
88
|
vines/stanza/presence/error
|
@@ -96,9 +100,12 @@ end
|
|
96
100
|
vines/storage/redis
|
97
101
|
vines/storage/sql
|
98
102
|
|
103
|
+
vines/config
|
104
|
+
vines/config/host
|
105
|
+
vines/config/port
|
106
|
+
|
99
107
|
vines/store
|
100
108
|
vines/contact
|
101
|
-
vines/config
|
102
109
|
vines/daemon
|
103
110
|
vines/error
|
104
111
|
vines/kit
|
data/lib/vines/command/cert.rb
CHANGED
@@ -5,7 +5,7 @@ module Vines
|
|
5
5
|
class Cert
|
6
6
|
def run(opts)
|
7
7
|
raise 'vines cert <domain>' unless opts[:args].size == 1
|
8
|
-
dir = File.expand_path(
|
8
|
+
dir = File.expand_path('../certs', opts[:config])
|
9
9
|
create_cert(opts[:args].first, dir)
|
10
10
|
end
|
11
11
|
|
@@ -36,6 +36,7 @@ module Vines
|
|
36
36
|
{'key' => key, 'crt' => cert}.each_pair do |ext, o|
|
37
37
|
name = File.join(dir, "#{domain}.#{ext}")
|
38
38
|
File.open(name, "w") {|f| f.write(o.to_pem) }
|
39
|
+
File.chmod(0600, name) if ext == 'key'
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
data/lib/vines/command/init.rb
CHANGED
@@ -19,6 +19,7 @@ module Vines
|
|
19
19
|
|
20
20
|
create_users(domain, users)
|
21
21
|
update_config(domain, File.join(dir, 'conf', 'config.rb'))
|
22
|
+
fix_perms(dir)
|
22
23
|
Command::Cert.new.create_cert(domain, File.join(dir, 'conf/certs'))
|
23
24
|
|
24
25
|
puts "Initialized server directory: #{domain}"
|
@@ -27,6 +28,16 @@ module Vines
|
|
27
28
|
|
28
29
|
private
|
29
30
|
|
31
|
+
# Limit file system database directory access so the server is the only
|
32
|
+
# process managing the data. The config.rb file contains component and
|
33
|
+
# database passwords, so restrict access to just the server user as well.
|
34
|
+
def fix_perms(dir)
|
35
|
+
%w[data data/users].each do |f|
|
36
|
+
File.chmod(0700, File.join(dir, f))
|
37
|
+
end
|
38
|
+
File.chmod(0600, File.join(dir, 'conf/config.rb'))
|
39
|
+
end
|
40
|
+
|
30
41
|
def update_config(domain, config)
|
31
42
|
text = File.read(config)
|
32
43
|
File.open(config, 'w') do |f|
|
data/lib/vines/command/ldap.rb
CHANGED
@@ -7,7 +7,7 @@ module Vines
|
|
7
7
|
raise 'vines ldap <domain>' unless opts[:args].size == 1
|
8
8
|
require opts[:config]
|
9
9
|
domain = opts[:args].first
|
10
|
-
unless storage = Config.instance.vhosts[domain]
|
10
|
+
unless storage = Config.instance.vhosts[domain].storage rescue nil
|
11
11
|
raise "#{domain} virtual host not found in conf/config.rb"
|
12
12
|
end
|
13
13
|
unless storage.ldap?
|
@@ -27,8 +27,11 @@ module Vines
|
|
27
27
|
rescue Exception => e
|
28
28
|
raise "LDAP connection failed: #{e.message}"
|
29
29
|
end
|
30
|
-
|
31
|
-
|
30
|
+
|
31
|
+
filter = storage.ldap.filter(jid)
|
32
|
+
raise "User not found with filter:\n #{filter}" unless user
|
33
|
+
name = user.name.empty? ? '<name missing>' : user.name
|
34
|
+
puts "Found user #{name} with filter:\n #{filter}"
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
data/lib/vines/command/schema.rb
CHANGED
@@ -7,7 +7,7 @@ module Vines
|
|
7
7
|
raise 'vines schema <domain>' unless opts[:args].size == 1
|
8
8
|
require opts[:config]
|
9
9
|
domain = opts[:args].first
|
10
|
-
unless storage = Config.instance.vhosts[domain]
|
10
|
+
unless storage = Config.instance.vhosts[domain].storage rescue nil
|
11
11
|
raise "#{domain} virtual host not found in conf/config.rb"
|
12
12
|
end
|
13
13
|
unless storage.respond_to?(:create_schema)
|
data/lib/vines/config.rb
CHANGED
@@ -31,7 +31,7 @@ module Vines
|
|
31
31
|
dupes = names.uniq.size != names.size || (@vhosts.keys & names).any?
|
32
32
|
raise "one host definition per domain allowed" if dupes
|
33
33
|
names.each do |name|
|
34
|
-
@vhosts
|
34
|
+
@vhosts[name] = Host.new(name, &block)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -57,10 +57,36 @@ module Vines
|
|
57
57
|
@ports.values
|
58
58
|
end
|
59
59
|
|
60
|
+
# Return true if the domain is virtual hosted by this server.
|
60
61
|
def vhost?(domain)
|
61
62
|
@vhosts.key?(domain)
|
62
63
|
end
|
63
64
|
|
65
|
+
# Return true if all JID's belong to components hosted by this server.
|
66
|
+
def component?(*jids)
|
67
|
+
!jids.flatten.index do |jid|
|
68
|
+
!component_password(JID.new(jid).domain)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return the password for the component or nil if it's not hosted here.
|
73
|
+
def component_password(domain)
|
74
|
+
host = @vhosts.values.find {|host| host.component?(domain) }
|
75
|
+
host.password(domain) if host
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return true if all of the JID's are hosted by this server.
|
79
|
+
def local_jid?(*jids)
|
80
|
+
!jids.flatten.index do |jid|
|
81
|
+
!vhost?(JID.new(jid).domain)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Return true if private XML fragment storage is enabled for this domain.
|
86
|
+
def private_storage?(domain)
|
87
|
+
@vhosts[domain].private_storage?
|
88
|
+
end
|
89
|
+
|
64
90
|
# Returns true if server-to-server connections are allowed with the
|
65
91
|
# given domain.
|
66
92
|
def s2s?(domain)
|
@@ -73,160 +99,45 @@ module Vines
|
|
73
99
|
@ports[name] or raise ArgumentError.new("no port named #{name}")
|
74
100
|
end
|
75
101
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@ldap = Storage::Ldap.new(host, port, &block)
|
90
|
-
@storage.ldap = @ldap if @storage
|
91
|
-
end
|
92
|
-
|
93
|
-
def to_hash
|
94
|
-
raise "storage required for #{@name}" unless @storage
|
95
|
-
{@name => @storage}
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class Port
|
100
|
-
include Vines::Log
|
101
|
-
|
102
|
-
attr_reader :config, :stream
|
103
|
-
|
104
|
-
%w[host port].each do |name|
|
105
|
-
define_method(name) do
|
106
|
-
@settings[name.to_sym]
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def initialize(config, host, port, &block)
|
111
|
-
@config, @settings = config, {}
|
112
|
-
instance_eval(&block) if block
|
113
|
-
defaults = {:host => host, :port => port,
|
114
|
-
:max_resources_per_account => 5, :max_stanza_size => 128 * 1024}
|
115
|
-
@settings = defaults.merge(@settings)
|
116
|
-
end
|
117
|
-
|
118
|
-
def max_stanza_size(max=nil)
|
119
|
-
if max
|
120
|
-
# rfc 6120 section 13.12
|
121
|
-
@settings[:max_stanza_size] = [10000, max].max
|
122
|
-
else
|
123
|
-
@settings[:max_stanza_size]
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def start
|
128
|
-
type = stream.name.split('::').last.downcase
|
129
|
-
log.info("Accepting #{type} connections on #{host}:#{port}")
|
130
|
-
EventMachine::start_server(host, port, stream, config)
|
131
|
-
end
|
102
|
+
# Return true if the two JID's are allowed to send messages to each other.
|
103
|
+
# Both domains must have enabled cross_domain_messages in their config files.
|
104
|
+
def allowed?(to, from)
|
105
|
+
to, from = JID.new(to), JID.new(from)
|
106
|
+
return false if to.empty? || from.empty?
|
107
|
+
return true if to.domain == from.domain # same domain always allowed
|
108
|
+
return cross_domain?(to, from) if local_jid?(to, from) # both virtual hosted here
|
109
|
+
return check_components(to, from) if component?(to, from) # component to component
|
110
|
+
return check_component(to, from) if component?(to) # to component
|
111
|
+
return check_component(from, to) if component?(from) # from component
|
112
|
+
return cross_domain?(to) if local_jid?(to) # from is remote
|
113
|
+
return cross_domain?(from) if local_jid?(from) # to is remote
|
114
|
+
return false
|
132
115
|
end
|
133
116
|
|
134
|
-
|
135
|
-
def initialize(config, host='0.0.0.0', port=5222, &block)
|
136
|
-
@stream = Vines::Stream::Client
|
137
|
-
super(config, host, port, &block)
|
138
|
-
end
|
139
|
-
|
140
|
-
def max_resources_per_account(max=nil)
|
141
|
-
if max
|
142
|
-
@settings[:max_resources_per_account] = max
|
143
|
-
else
|
144
|
-
@settings[:max_resources_per_account]
|
145
|
-
end
|
146
|
-
end
|
117
|
+
private
|
147
118
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
def private_storage?
|
153
|
-
@settings[:private_storage]
|
154
|
-
end
|
119
|
+
def check_components(to, from)
|
120
|
+
comp1, comp2 = strip_domain(to), strip_domain(from)
|
121
|
+
(comp1 == comp2) || cross_domain?(comp1, comp2)
|
155
122
|
end
|
156
123
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
|
-
def hosts(*hosts)
|
164
|
-
if hosts.any?
|
165
|
-
@hosts << hosts
|
166
|
-
@hosts.flatten!
|
167
|
-
else
|
168
|
-
@hosts
|
169
|
-
end
|
170
|
-
end
|
124
|
+
def check_component(component_jid, jid)
|
125
|
+
comp = strip_domain(component_jid)
|
126
|
+
return true if comp.domain == jid.domain
|
127
|
+
local_jid?(jid) ? cross_domain?(comp, jid) : cross_domain?(comp)
|
171
128
|
end
|
172
129
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
@settings = defaults.merge(@settings)
|
179
|
-
end
|
180
|
-
|
181
|
-
def max_resources_per_account(max=nil)
|
182
|
-
if max
|
183
|
-
@settings[:max_resources_per_account] = max
|
184
|
-
else
|
185
|
-
@settings[:max_resources_per_account]
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def private_storage(enabled)
|
190
|
-
@settings[:private_storage] = !!enabled
|
191
|
-
end
|
192
|
-
|
193
|
-
def private_storage?
|
194
|
-
@settings[:private_storage]
|
195
|
-
end
|
196
|
-
|
197
|
-
def root(dir=nil)
|
198
|
-
if dir
|
199
|
-
@settings[:root] = File.expand_path(dir)
|
200
|
-
else
|
201
|
-
@settings[:root]
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def bind(url=nil)
|
206
|
-
if url
|
207
|
-
@settings[:bind] = url
|
208
|
-
else
|
209
|
-
@settings[:bind]
|
210
|
-
end
|
211
|
-
end
|
130
|
+
# Return the JID's domain with the first subdomain stripped off. For example,
|
131
|
+
# alice@tea.wonderland.lit returns wonderland.lit.
|
132
|
+
def strip_domain(jid)
|
133
|
+
domain = jid.domain.split('.').drop(1).join('.')
|
134
|
+
JID.new(domain)
|
212
135
|
end
|
213
136
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
end
|
219
|
-
|
220
|
-
def components(options=nil)
|
221
|
-
if options
|
222
|
-
@components = options
|
223
|
-
else
|
224
|
-
@components
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def password(component)
|
229
|
-
@components[component]
|
137
|
+
# Return true if all JID's are allowed to exchange cross domain messages.
|
138
|
+
def cross_domain?(*jids)
|
139
|
+
!jids.flatten.index do |jid|
|
140
|
+
!@vhosts[jid.domain].cross_domain_messages?
|
230
141
|
end
|
231
142
|
end
|
232
143
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Config
|
5
|
+
|
6
|
+
# Provides the DSL methods for the virtual host definitions in the
|
7
|
+
# conf/config.rb file. Host instances can be accessed at runtime through
|
8
|
+
# the +Config#vhosts+ method.
|
9
|
+
class Host
|
10
|
+
def initialize(name, &block)
|
11
|
+
@name, @storage, @ldap = name.downcase, nil, nil
|
12
|
+
@cross_domain_messages = false
|
13
|
+
@private_storage = false
|
14
|
+
@components = {}
|
15
|
+
validate_domain(@name)
|
16
|
+
instance_eval(&block)
|
17
|
+
raise "storage required for #{@name}" unless @storage
|
18
|
+
end
|
19
|
+
|
20
|
+
def storage(name=nil, &block)
|
21
|
+
if name
|
22
|
+
raise "one storage mechanism per host allowed" if @storage
|
23
|
+
@storage = Storage.from_name(name, &block)
|
24
|
+
@storage.ldap = @ldap
|
25
|
+
else
|
26
|
+
@storage
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def ldap(host='localhost', port=636, &block)
|
31
|
+
@ldap = Storage::Ldap.new(host, port, &block)
|
32
|
+
@storage.ldap = @ldap if @storage
|
33
|
+
end
|
34
|
+
|
35
|
+
def cross_domain_messages(enabled)
|
36
|
+
@cross_domain_messages = !!enabled
|
37
|
+
end
|
38
|
+
|
39
|
+
def cross_domain_messages?
|
40
|
+
@cross_domain_messages
|
41
|
+
end
|
42
|
+
|
43
|
+
def components(options=nil)
|
44
|
+
return @components unless options
|
45
|
+
|
46
|
+
names = options.keys.map {|domain| "#{domain}.#{@name}".downcase }
|
47
|
+
dupes = names.uniq.size != names.size || (@components.keys & names).any?
|
48
|
+
raise "duplicate component domains not allowed" if dupes
|
49
|
+
|
50
|
+
options.each do |domain, password|
|
51
|
+
raise 'component domain required' if (domain || '').to_s.strip.empty?
|
52
|
+
raise 'component password required' if (password || '').strip.empty?
|
53
|
+
name = "#{domain}.#{@name}".downcase
|
54
|
+
raise "components must be one level below their host: #{name}" if domain.to_s.include?('.')
|
55
|
+
validate_domain(name)
|
56
|
+
@components[name] = password
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def component?(domain)
|
61
|
+
!!@components[domain]
|
62
|
+
end
|
63
|
+
|
64
|
+
def password(domain)
|
65
|
+
@components[domain]
|
66
|
+
end
|
67
|
+
|
68
|
+
def private_storage(enabled)
|
69
|
+
@private_storage = !!enabled
|
70
|
+
end
|
71
|
+
|
72
|
+
def private_storage?
|
73
|
+
@private_storage
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Prevent domains in config files that won't form valid JID's.
|
79
|
+
def validate_domain(name)
|
80
|
+
jid = JID.new(name)
|
81
|
+
raise "incorrect domain: #{name}" if jid.node || jid.resource
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|