diaspora-vines 0.1.2 → 0.1.21
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.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/conf/config.rb +6 -2
- data/lib/vines/cluster/subscriber.rb +27 -2
- data/lib/vines/config.rb +16 -2
- data/lib/vines/log.rb +4 -0
- data/lib/vines/storage/sql.rb +76 -38
- data/lib/vines/store.rb +58 -29
- data/lib/vines/user.rb +3 -1
- data/lib/vines/version.rb +1 -1
- data/lib/vines.rb +4 -4
- data/test/config_test.rb +17 -2
- data/test/storage/sql.rb +78 -0
- data/test/storage/sql_schema.rb +117 -0
- data/test/store_test.rb +80 -48
- data/test/test_helper.rb +1 -0
- data/vines.gemspec +8 -4
- metadata +59 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2e10ea8cd78c49254b4e8dc363d3d23759b40f6
|
4
|
+
data.tar.gz: aeedf0672a7578414f0b174b2ab0d61403c0f5b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59a644d8dbd8cab888548ea2d49466ad27d5acc79f99097414d440f3942c72d7ec128ed33df3991841e6d409fca9fccaffc87552925532f0276e4a55e23ead3d
|
7
|
+
data.tar.gz: 7c85dcaaa5359bc99714cf24528b7e0f25731681339503e394b3c3856b5457cc81918395a2fce021d8172dc7ec9ef46e0137948e2ac8dcbee7323d87da4c38ba
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
Diaspora XMPP Integration
|
2
2
|
=========================
|
3
3
|
|
4
|
+
**master** [  ](https://travis-ci.org/diaspora/vines)
|
5
|
+
**develop** [  ](https://travis-ci.org/diaspora/vines)
|
6
|
+
|
4
7
|
This XMPP server was forked from [Negativecode](http://www.getvines.org/)
|
5
8
|
and was slimmed down for [Diaspora](https://diasporafoundation.org) usage only!
|
6
9
|
|
data/conf/config.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
Vines::Config.configure do
|
2
2
|
# Set the logging level to debug, info, warn, error, or fatal. The debug
|
3
3
|
# level logs all XML sent and received by the server.
|
4
|
-
|
4
|
+
# If you want logging to STDOUT remove the path
|
5
|
+
# e.g. `log 'log/vines.log' do` becomes `log do`
|
6
|
+
log 'log/vines.log' do
|
7
|
+
level :info
|
8
|
+
end
|
5
9
|
|
6
10
|
# Set the directory in which to look for virtual hosts' TLS certificates.
|
7
11
|
# This is optional and defaults to the conf/certs directory created during
|
8
12
|
# `vines init`.
|
9
|
-
|
13
|
+
certs 'conf/certs'
|
10
14
|
|
11
15
|
# Setup a pepper to generate the encrypted password.
|
12
16
|
pepper "065eb8798b181ff0ea2c5c16aee0ff8b70e04e2ee6bd6e08b49da46924223e39127d5335e466207d42bf2a045c12be5f90e92012a4f05f7fc6d9f3c875f4c95b"
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Vines
|
4
4
|
class Cluster
|
5
|
-
# Subscribes to the redis nodes:all broadcast channel to listen for
|
5
|
+
# Subscribes to the redis `nodes:all` broadcast channel to listen for
|
6
6
|
# heartbeats from other cluster members. Also subscribes to a channel
|
7
7
|
# exclusively for this particular node, listening for stanzas routed to us
|
8
8
|
# from other nodes.
|
@@ -22,6 +22,8 @@ module Vines
|
|
22
22
|
# Create a new redis connection and subscribe to the nodes:all broadcast
|
23
23
|
# channel as well as the channel for this cluster node. Redis connections
|
24
24
|
# in subscribe mode cannot be used for other key/value operations.
|
25
|
+
#
|
26
|
+
# Returns nothing.
|
25
27
|
def subscribe
|
26
28
|
conn = @cluster.connect
|
27
29
|
conn.subscribe(ALL)
|
@@ -35,6 +37,8 @@ module Vines
|
|
35
37
|
|
36
38
|
# Recursively process incoming messages from the queue, guaranteeing they
|
37
39
|
# are processed in the order they are received.
|
40
|
+
#
|
41
|
+
# Returns nothing.
|
38
42
|
def process_messages
|
39
43
|
@messages.pop do |channel, message|
|
40
44
|
Fiber.new do
|
@@ -46,6 +50,11 @@ module Vines
|
|
46
50
|
|
47
51
|
# Process messages as they arrive on the pubsub channels to which we're
|
48
52
|
# subscribed.
|
53
|
+
#
|
54
|
+
# channel - The String channel name on which the message was received.
|
55
|
+
# message - The JSON formatted message String.
|
56
|
+
#
|
57
|
+
# Returns nothing.
|
49
58
|
def on_message(channel, message)
|
50
59
|
doc = JSON.parse(message)
|
51
60
|
case channel
|
@@ -56,9 +65,13 @@ module Vines
|
|
56
65
|
log.error("Cluster subscription message failed: #{e}")
|
57
66
|
end
|
58
67
|
|
59
|
-
# Process a message sent to the nodes:all broadcast channel. In the case
|
68
|
+
# Process a message sent to the `nodes:all` broadcast channel. In the case
|
60
69
|
# of node heartbeats, we update the last time we heard from this node so
|
61
70
|
# we can cleanup its session if it goes offline.
|
71
|
+
#
|
72
|
+
# message - The parsed Hash of received message data.
|
73
|
+
#
|
74
|
+
# Returns nothing.
|
62
75
|
def to_all(message)
|
63
76
|
case message[TYPE]
|
64
77
|
when ONLINE, HEARTBEAT
|
@@ -71,6 +84,10 @@ module Vines
|
|
71
84
|
# Process a message published to this node's channel. Messages sent to
|
72
85
|
# this channel are stanzas that need to be routed to connections attached
|
73
86
|
# to this node.
|
87
|
+
#
|
88
|
+
# message - The parsed Hash of received message data.
|
89
|
+
#
|
90
|
+
# Returns nothing.
|
74
91
|
def to_node(message)
|
75
92
|
case message[TYPE]
|
76
93
|
when STANZA then route_stanza(message)
|
@@ -80,6 +97,10 @@ module Vines
|
|
80
97
|
|
81
98
|
# Send the stanza, from a remote cluster node, to locally connected
|
82
99
|
# streams for the destination user.
|
100
|
+
#
|
101
|
+
# message - The parsed Hash of received message data.
|
102
|
+
#
|
103
|
+
# Returns nothing.
|
83
104
|
def route_stanza(message)
|
84
105
|
node = Nokogiri::XML(message[STANZA]).root rescue nil
|
85
106
|
return unless node
|
@@ -95,6 +116,10 @@ module Vines
|
|
95
116
|
|
96
117
|
# Update the roster information, that's cached in locally connected
|
97
118
|
# streams, for this user.
|
119
|
+
#
|
120
|
+
# message - The parsed Hash of received message data.
|
121
|
+
#
|
122
|
+
# Returns nothing.
|
98
123
|
def update_user(message)
|
99
124
|
jid = JID.new(message['jid']).bare
|
100
125
|
if user = @cluster.storage(jid.domain).find_user(jid)
|
data/lib/vines/config.rb
CHANGED
@@ -21,6 +21,7 @@ module Vines
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def initialize(&block)
|
24
|
+
@pepper = "" # no pepper set
|
24
25
|
@certs = File.expand_path('conf/certs')
|
25
26
|
@vhosts, @ports, @cluster = {}, {}, nil
|
26
27
|
@null = Storage::Null.new
|
@@ -47,7 +48,7 @@ module Vines
|
|
47
48
|
end
|
48
49
|
|
49
50
|
def pepper(pepper=nil)
|
50
|
-
pepper ? @pepper = pepper : @pepper
|
51
|
+
pepper ? @pepper = pepper : @pepper
|
51
52
|
end
|
52
53
|
|
53
54
|
def domain_name
|
@@ -72,7 +73,20 @@ module Vines
|
|
72
73
|
@cluster = Cluster.new(self, &block)
|
73
74
|
end
|
74
75
|
|
75
|
-
def log(
|
76
|
+
def log(file=nil, &block)
|
77
|
+
unless file.nil?
|
78
|
+
unless File.exists?(file)
|
79
|
+
File.new(file, 'w') rescue raise "log directory doesn't exists"
|
80
|
+
end
|
81
|
+
|
82
|
+
if File.exists?(file)
|
83
|
+
Vines::Log.set_log_file(file)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
instance_eval(&block) if block
|
87
|
+
end
|
88
|
+
|
89
|
+
def level(level)
|
76
90
|
const = Logger.const_get(level.to_s.upcase) rescue nil
|
77
91
|
unless LOG_LEVELS.include?(level.to_s) && const
|
78
92
|
raise "log level must be one of: #{LOG_LEVELS.join(', ')}"
|
data/lib/vines/log.rb
CHANGED
data/lib/vines/storage/sql.rb
CHANGED
@@ -1,19 +1,39 @@
|
|
1
|
-
|
1
|
+
# encoding: UTF-8
|
2
2
|
|
3
3
|
module Vines
|
4
4
|
class Storage
|
5
5
|
class Sql < Storage
|
6
|
+
include Vines::Log
|
7
|
+
|
6
8
|
register :sql
|
7
9
|
|
8
10
|
class Person < ActiveRecord::Base; end
|
11
|
+
class Aspect < ActiveRecord::Base
|
12
|
+
belongs_to :users
|
13
|
+
|
14
|
+
has_many :aspect_memberships
|
15
|
+
has_many :contacts
|
16
|
+
end
|
17
|
+
|
18
|
+
class AspectMembership < ActiveRecord::Base
|
19
|
+
belongs_to :aspect
|
20
|
+
belongs_to :contact
|
21
|
+
|
22
|
+
has_one :users, :through => :contact
|
23
|
+
has_one :person, :through => :contact
|
24
|
+
end
|
25
|
+
|
9
26
|
class Contact < ActiveRecord::Base
|
10
|
-
belongs_to :
|
27
|
+
belongs_to :users
|
11
28
|
belongs_to :person
|
29
|
+
|
30
|
+
has_many :aspect_memberships
|
31
|
+
has_many :aspects, :through => :aspect_memberships
|
12
32
|
end
|
13
33
|
|
14
34
|
class User < ActiveRecord::Base
|
15
|
-
has_many :contacts
|
16
|
-
|
35
|
+
has_many :contacts
|
36
|
+
|
17
37
|
has_one :person, :foreign_key => :owner_id
|
18
38
|
end
|
19
39
|
|
@@ -33,15 +53,15 @@ module Vines
|
|
33
53
|
end
|
34
54
|
|
35
55
|
def initialize(&block)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
56
|
+
@config = {}
|
57
|
+
unless defined? Rails
|
58
|
+
raise "You configured diaspora-sql adapter without Diaspora environment"
|
59
|
+
end
|
60
|
+
|
61
|
+
config = Rails.application.config.database_configuration[Rails.env]
|
62
|
+
%w[adapter database host port username password].each do |key|
|
63
|
+
@config[key.to_sym] = config[key]
|
64
|
+
end
|
45
65
|
|
46
66
|
required = [:adapter, :database]
|
47
67
|
required << [:host, :port] unless @config[:adapter] == 'sqlite3'
|
@@ -55,30 +75,16 @@ module Vines
|
|
55
75
|
return if jid.empty?
|
56
76
|
xuser = user_by_jid(jid)
|
57
77
|
return Vines::User.new(jid: jid).tap do |user|
|
58
|
-
user.name, user.password
|
78
|
+
user.name, user.password, user.token =
|
79
|
+
xuser.username,
|
80
|
+
xuser.encrypted_password,
|
81
|
+
xuser.authentication_token
|
59
82
|
|
60
83
|
xuser.contacts.each do |contact|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
if contact.sharing && contact.receiving
|
66
|
-
subscription = 'both'
|
67
|
-
elsif contact.sharing && !contact.receiving
|
68
|
-
ask = 'suscribe'
|
69
|
-
subscription = 'from'
|
70
|
-
elsif !contact.sharing && contact.receiving
|
71
|
-
subscription = 'to'
|
72
|
-
else
|
73
|
-
ask = 'suscribe'
|
84
|
+
entry = build_roster_entry(contact)
|
85
|
+
unless entry.nil?
|
86
|
+
user.roster << entry
|
74
87
|
end
|
75
|
-
# finally build the roster entry
|
76
|
-
user.roster << Vines::Contact.new(
|
77
|
-
jid: handle,
|
78
|
-
name: handle.gsub(/\@.*?$/, ''),
|
79
|
-
subscription: subscription,
|
80
|
-
ask: ask
|
81
|
-
) if handle
|
82
88
|
end
|
83
89
|
end if xuser
|
84
90
|
end
|
@@ -87,17 +93,18 @@ module Vines
|
|
87
93
|
def authenticate(username, password)
|
88
94
|
user = find_user(username)
|
89
95
|
|
96
|
+
pepper = password
|
97
|
+
pepper << Config.instance.pepper unless Config
|
90
98
|
dbhash = BCrypt::Password.new(user.password) rescue nil
|
91
|
-
hash = BCrypt::Engine.hash_secret(
|
99
|
+
hash = BCrypt::Engine.hash_secret(pepper, dbhash.salt) rescue nil
|
92
100
|
|
93
101
|
userAuth = ((hash && dbhash) && hash == dbhash)
|
94
|
-
tokenAuth = ((password && user
|
102
|
+
tokenAuth = ((password && user) && password == user.token)
|
95
103
|
(tokenAuth || userAuth)? user : nil
|
96
104
|
end
|
97
105
|
|
98
106
|
def save_user(user)
|
99
107
|
# do nothing
|
100
|
-
#log.error("You cannot save a user via XMPP server!")
|
101
108
|
end
|
102
109
|
with_connection :save_user
|
103
110
|
|
@@ -125,7 +132,7 @@ module Vines
|
|
125
132
|
|
126
133
|
private
|
127
134
|
def establish_connection
|
128
|
-
ActiveRecord::Base.logger =
|
135
|
+
ActiveRecord::Base.logger = log # using vines logger
|
129
136
|
ActiveRecord::Base.establish_connection(@config)
|
130
137
|
end
|
131
138
|
|
@@ -133,6 +140,37 @@ module Vines
|
|
133
140
|
name = JID.new(jid).node
|
134
141
|
Sql::User.find_by_username(name)
|
135
142
|
end
|
143
|
+
|
144
|
+
def build_roster_entry(contact)
|
145
|
+
groups = Array.new
|
146
|
+
contact.aspects.each do |aspect|
|
147
|
+
groups.push(aspect.name)
|
148
|
+
end
|
149
|
+
|
150
|
+
handle = contact.person.diaspora_handle
|
151
|
+
ask = 'none'
|
152
|
+
subscription = 'none'
|
153
|
+
|
154
|
+
if contact.sharing && contact.receiving
|
155
|
+
subscription = 'both'
|
156
|
+
elsif contact.sharing && !contact.receiving
|
157
|
+
ask = 'suscribe'
|
158
|
+
subscription = 'from'
|
159
|
+
elsif !contact.sharing && contact.receiving
|
160
|
+
subscription = 'to'
|
161
|
+
else
|
162
|
+
ask = 'suscribe'
|
163
|
+
end
|
164
|
+
|
165
|
+
# finally build the roster entry
|
166
|
+
return Vines::Contact.new(
|
167
|
+
jid: handle,
|
168
|
+
name: handle.gsub(/\@.*?$/, ''),
|
169
|
+
subscription: subscription,
|
170
|
+
groups: groups,
|
171
|
+
ask: ask
|
172
|
+
) || nil
|
173
|
+
end
|
136
174
|
end
|
137
175
|
end
|
138
176
|
end
|
data/lib/vines/store.rb
CHANGED
@@ -1,37 +1,33 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
module Vines
|
4
|
-
|
5
4
|
# An X509 certificate store that validates certificate trust chains.
|
6
5
|
# This uses the conf/certs/*.crt files as the list of trusted root
|
7
6
|
# CA certificates.
|
8
7
|
class Store
|
9
|
-
include Vines::Log
|
10
|
-
|
11
8
|
@@sources = nil
|
12
9
|
|
13
10
|
# Create a certificate store to read certificate files from the given
|
14
11
|
# directory.
|
12
|
+
#
|
13
|
+
# dir - The String directory name (absolute or relative).
|
15
14
|
def initialize(dir)
|
16
15
|
@dir = File.expand_path(dir)
|
17
16
|
@store = OpenSSL::X509::Store.new
|
18
|
-
certs.each {|
|
19
|
-
begin
|
20
|
-
@store.add_cert(c)
|
21
|
-
rescue
|
22
|
-
# do nothing cert is already known
|
23
|
-
log.warn("WARNING! There are duplicate certificates")
|
24
|
-
end
|
25
|
-
}
|
17
|
+
certs.each {|cert| append(cert) }
|
26
18
|
end
|
27
19
|
|
28
20
|
# Return true if the certificate is signed by a CA certificate in the
|
29
21
|
# store. If the certificate can be trusted, it's added to the store so
|
30
22
|
# it can be used to trust other certs.
|
23
|
+
#
|
24
|
+
# pem - The PEM encoded certificate String.
|
25
|
+
#
|
26
|
+
# Returns true if the certificate is trusted.
|
31
27
|
def trusted?(pem)
|
32
28
|
if cert = OpenSSL::X509::Certificate.new(pem) rescue nil
|
33
29
|
@store.verify(cert).tap do |trusted|
|
34
|
-
|
30
|
+
append(cert) if trusted
|
35
31
|
end
|
36
32
|
end
|
37
33
|
end
|
@@ -39,6 +35,11 @@ module Vines
|
|
39
35
|
# Return true if the domain name matches one of the names in the
|
40
36
|
# certificate. In other words, is the certificate provided to us really
|
41
37
|
# for the domain to which we think we're connected?
|
38
|
+
#
|
39
|
+
# pem - The PEM encoded certificate String.
|
40
|
+
# domain - The domain name String.
|
41
|
+
#
|
42
|
+
# Returns true if the certificate was issued for the domain.
|
42
43
|
def domain?(pem, domain)
|
43
44
|
if cert = OpenSSL::X509::Certificate.new(pem) rescue nil
|
44
45
|
OpenSSL::SSL.verify_certificate_identity(cert, domain) rescue false
|
@@ -48,8 +49,10 @@ module Vines
|
|
48
49
|
# Return the trusted root CA certificates installed in conf/certs. These
|
49
50
|
# certificates are used to start the trust chain needed to validate certs
|
50
51
|
# we receive from clients and servers.
|
52
|
+
#
|
53
|
+
# Returns an Array of OpenSSL::X509::Certificate objects.
|
51
54
|
def certs
|
52
|
-
|
55
|
+
@@sources ||= begin
|
53
56
|
pattern = /-{5}BEGIN CERTIFICATE-{5}\n.*?-{5}END CERTIFICATE-{5}\n/m
|
54
57
|
files = Dir[File.join(@dir, '*.crt')]
|
55
58
|
files << AppConfig.environment.certificate_authorities if defined?(AppConfig)
|
@@ -61,7 +64,7 @@ module Vines
|
|
61
64
|
[name, certs]
|
62
65
|
end
|
63
66
|
end
|
64
|
-
|
67
|
+
Hash[pairs]
|
65
68
|
end
|
66
69
|
@@sources.values.flatten
|
67
70
|
end
|
@@ -71,31 +74,43 @@ module Vines
|
|
71
74
|
# wildcard certificate files to serve several subdomains.
|
72
75
|
#
|
73
76
|
# Finding the certificate and private key file for a domain follows these steps:
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
+
#
|
78
|
+
# - Look for <domain>.crt and <domain>.key files in the conf/certs
|
79
|
+
# directory. If found, return those file names, otherwise . . .
|
80
|
+
#
|
81
|
+
# - Inspect all conf/certs/*.crt files for certificates that contain the
|
77
82
|
# domain name either as the subject common name (CN) or as a DNS
|
78
83
|
# subjectAltName. The corresponding private key must be in a file of the
|
79
84
|
# same name as the certificate's, but with a .key extension.
|
80
85
|
#
|
81
|
-
# So in the simplest configuration, the tea.wonderland.lit encryption files
|
82
|
-
# be named
|
86
|
+
# So in the simplest configuration, the tea.wonderland.lit encryption files
|
87
|
+
# would be named:
|
88
|
+
#
|
89
|
+
# - conf/certs/tea.wonderland.lit.crt
|
90
|
+
# - conf/certs/tea.wonderland.lit.key
|
83
91
|
#
|
84
|
-
# However, in the case of a wildcard certificate for *.wonderland.lit,
|
85
|
-
# files would be
|
86
|
-
#
|
87
|
-
#
|
92
|
+
# However, in the case of a wildcard certificate for *.wonderland.lit,
|
93
|
+
# the files would be:
|
94
|
+
#
|
95
|
+
# - conf/certs/wonderland.lit.crt
|
96
|
+
# - conf/certs/wonderland.lit.key
|
97
|
+
#
|
98
|
+
# These same two files would be returned for the subdomains of:
|
99
|
+
#
|
100
|
+
# - tea.wonderland.lit
|
101
|
+
# - crumpets.wonderland.lit
|
102
|
+
# - etc.
|
103
|
+
#
|
104
|
+
# domain - The String domain name.
|
105
|
+
#
|
106
|
+
# Returns a two element String array for the certificate and private key
|
107
|
+
# file names or nil if not found.
|
88
108
|
def files_for_domain(domain)
|
89
109
|
crt = File.expand_path("#{domain}.crt", @dir)
|
90
110
|
key = File.expand_path("#{domain}.key", @dir)
|
91
|
-
# diaspora keys will be prioritized
|
92
|
-
if defined?(AppConfig)
|
93
|
-
crt = AppConfig.server.chat.certificate
|
94
|
-
key = AppConfig.server.chat.key
|
95
|
-
end
|
96
111
|
return [crt, key] if File.exists?(crt) && File.exists?(key)
|
97
112
|
|
98
|
-
#
|
113
|
+
# Might be a wildcard cert file.
|
99
114
|
@@sources.each do |file, certs|
|
100
115
|
certs.each do |cert|
|
101
116
|
if OpenSSL::SSL.verify_certificate_identity(cert, domain)
|
@@ -106,5 +121,19 @@ module Vines
|
|
106
121
|
end
|
107
122
|
nil
|
108
123
|
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
# Add a trusted certificate to the store, suppressing any OpenSSL errors
|
128
|
+
# caused by the certificate already being stored.
|
129
|
+
#
|
130
|
+
# cert - The OpenSSL::X509::Certificate to add.
|
131
|
+
#
|
132
|
+
# Returns nothing.
|
133
|
+
def append(cert)
|
134
|
+
@store.add_cert(cert)
|
135
|
+
rescue OpenSSL::X509::StoreError
|
136
|
+
# Already added to store.
|
137
|
+
end
|
109
138
|
end
|
110
139
|
end
|
data/lib/vines/user.rb
CHANGED
@@ -4,7 +4,7 @@ module Vines
|
|
4
4
|
class User
|
5
5
|
include Comparable
|
6
6
|
|
7
|
-
attr_accessor :name, :password, :roster
|
7
|
+
attr_accessor :name, :token, :password, :roster
|
8
8
|
attr_reader :jid
|
9
9
|
|
10
10
|
def initialize(args={})
|
@@ -13,6 +13,7 @@ module Vines
|
|
13
13
|
|
14
14
|
@name = args[:name]
|
15
15
|
@password = args[:password]
|
16
|
+
@token = args[:token]
|
16
17
|
@roster = args[:roster] || []
|
17
18
|
end
|
18
19
|
|
@@ -30,6 +31,7 @@ module Vines
|
|
30
31
|
def update_from(user)
|
31
32
|
@name = user.name
|
32
33
|
@password = user.password
|
34
|
+
@token = user.token
|
33
35
|
@roster = user.roster.map {|c| c.clone }
|
34
36
|
end
|
35
37
|
|
data/lib/vines/version.rb
CHANGED
data/lib/vines.rb
CHANGED
@@ -55,13 +55,13 @@ module Vines
|
|
55
55
|
end
|
56
56
|
|
57
57
|
begin
|
58
|
-
# try to initialize diaspora
|
58
|
+
# try to initialize diaspora configuration
|
59
|
+
require "#{Dir.pwd}/config/application.rb"
|
59
60
|
require "#{Dir.pwd}/config/load_config.rb"
|
60
|
-
rescue LoadError
|
61
|
-
puts "Cannot find Diaspora environment! Fallback to vines configuration."
|
62
|
-
end
|
61
|
+
rescue LoadError; end
|
63
62
|
|
64
63
|
%w[
|
64
|
+
active_record
|
65
65
|
base64
|
66
66
|
bcrypt
|
67
67
|
digest/sha1
|
data/test/config_test.rb
CHANGED
@@ -353,10 +353,23 @@ describe Vines::Config do
|
|
353
353
|
assert_equal 1, config.ports.size
|
354
354
|
end
|
355
355
|
|
356
|
+
def test_not_existing_file_path
|
357
|
+
assert_raises(RuntimeError) do
|
358
|
+
config = Vines::Config.new do
|
359
|
+
log 'not/existing/path.log'
|
360
|
+
end
|
361
|
+
host 'wonderland.lit' do
|
362
|
+
storage(:fs) { dir Dir.tmpdir }
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
356
367
|
def test_invalid_log_level
|
357
368
|
assert_raises(RuntimeError) do
|
358
369
|
config = Vines::Config.new do
|
359
|
-
log '
|
370
|
+
log 'vines.log' do
|
371
|
+
level 'bogus'
|
372
|
+
end
|
360
373
|
host 'wonderland.lit' do
|
361
374
|
storage(:fs) { dir Dir.tmpdir }
|
362
375
|
end
|
@@ -366,7 +379,9 @@ describe Vines::Config do
|
|
366
379
|
|
367
380
|
def test_valid_log_level
|
368
381
|
config = Vines::Config.new do
|
369
|
-
log
|
382
|
+
log 'vines.log' do
|
383
|
+
level :error
|
384
|
+
end
|
370
385
|
host 'wonderland.lit' do
|
371
386
|
storage(:fs) { dir Dir.tmpdir }
|
372
387
|
end
|
data/test/storage/sql.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'storage/sql_schema'
|
5
|
+
|
6
|
+
module Diaspora
|
7
|
+
class Application < Rails::Application
|
8
|
+
def config.database_configuration
|
9
|
+
{
|
10
|
+
"development" => {
|
11
|
+
"adapter" => "sqlite3",
|
12
|
+
"database" => "test.db"
|
13
|
+
}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Vines::Storage::Sql do
|
20
|
+
include SqlSchema
|
21
|
+
|
22
|
+
before do
|
23
|
+
storage && create_schema(:force => true)
|
24
|
+
|
25
|
+
Vines::Storage::Sql::User.new(
|
26
|
+
username: "test",
|
27
|
+
email: "test@test.de",
|
28
|
+
encrypted_password: "$2a$10$c2G6rHjGeamQIOFI0c1/b.4mvFBw4AfOtgVrAkO1QPMuAyporj5e6", # pppppp
|
29
|
+
authentication_token: "1234"
|
30
|
+
).save
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
db = Rails.application.config.database_configuration["development"]["database"]
|
35
|
+
File.delete(db) if File.exist?(db)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_find_user
|
39
|
+
fibered do
|
40
|
+
db = storage
|
41
|
+
user = db.find_user(nil)
|
42
|
+
assert_nil user
|
43
|
+
|
44
|
+
user = db.find_user("test@local.host")
|
45
|
+
assert (user != nil), "no user found"
|
46
|
+
assert_equal "test", user.name
|
47
|
+
|
48
|
+
user = db.find_user(Vines::JID.new("test@local.host"))
|
49
|
+
assert (user != nil), "no user found"
|
50
|
+
assert_equal "test", user.name
|
51
|
+
|
52
|
+
user = db.find_user(Vines::JID.new("test@local.host/resource"))
|
53
|
+
assert (user != nil), "no user found"
|
54
|
+
assert_equal "test", user.name
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_authenticate
|
59
|
+
fibered do
|
60
|
+
db = storage
|
61
|
+
|
62
|
+
assert_nil db.authenticate(nil, nil)
|
63
|
+
assert_nil db.authenticate(nil, "secret")
|
64
|
+
assert_nil db.authenticate("bogus", nil)
|
65
|
+
|
66
|
+
# user credential auth
|
67
|
+
pepper = "065eb8798b181ff0ea2c5c16aee0ff8b70e04e2ee6bd6e08b49da46924223e39127d5335e466207d42bf2a045c12be5f90e92012a4f05f7fc6d9f3c875f4c95b"
|
68
|
+
user = db.authenticate("test@test.de", "pppppp#{pepper}")
|
69
|
+
assert (user != nil), "no user found"
|
70
|
+
assert_equal "test", user.name
|
71
|
+
|
72
|
+
# user token auth
|
73
|
+
user = db.authenticate("test@test.de", "1234")
|
74
|
+
assert (user != nil), "no user found"
|
75
|
+
assert_equal "test", user.name
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module SqlSchema
|
2
|
+
def fibered
|
3
|
+
EM.run do
|
4
|
+
Fiber.new do
|
5
|
+
yield
|
6
|
+
EM.stop
|
7
|
+
end.resume
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def storage
|
12
|
+
Vines::Storage::Sql.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_schema(args={})
|
16
|
+
args[:force] ||= false
|
17
|
+
|
18
|
+
ActiveRecord::Schema.define do
|
19
|
+
create_table "people", :force => true do |t|
|
20
|
+
t.string "guid", :null => false
|
21
|
+
t.text "url", :null => false
|
22
|
+
t.string "diaspora_handle", :null => false
|
23
|
+
t.text "serialized_public_key", :null => false
|
24
|
+
t.integer "owner_id"
|
25
|
+
t.datetime "created_at", :null => false
|
26
|
+
t.datetime "updated_at", :null => false
|
27
|
+
t.boolean "closed_account", :default => false
|
28
|
+
t.integer "fetch_status", :default => 0
|
29
|
+
end
|
30
|
+
|
31
|
+
add_index "people", ["diaspora_handle"], :name => "index_people_on_diaspora_handle", :unique => true
|
32
|
+
add_index "people", ["guid"], :name => "index_people_on_guid", :unique => true
|
33
|
+
add_index "people", ["owner_id"], :name => "index_people_on_owner_id", :unique => true
|
34
|
+
|
35
|
+
create_table "aspects", :force => true do |t|
|
36
|
+
t.string "name", :null => false
|
37
|
+
t.integer "user_id", :null => false
|
38
|
+
t.datetime "created_at", :null => false
|
39
|
+
t.datetime "updated_at", :null => false
|
40
|
+
t.boolean "contacts_visible", :default => true, :null => false
|
41
|
+
t.integer "order_id"
|
42
|
+
end
|
43
|
+
|
44
|
+
add_index "aspects", ["user_id", "contacts_visible"], :name => "index_aspects_on_user_id_and_contacts_visible"
|
45
|
+
add_index "aspects", ["user_id"], :name => "index_aspects_on_user_id"
|
46
|
+
|
47
|
+
create_table "aspect_memberships", :force => true do |t|
|
48
|
+
t.integer "aspect_id", :null => false
|
49
|
+
t.integer "contact_id", :null => false
|
50
|
+
t.datetime "created_at", :null => false
|
51
|
+
t.datetime "updated_at", :null => false
|
52
|
+
end
|
53
|
+
|
54
|
+
add_index "aspect_memberships", ["aspect_id", "contact_id"], :name => "index_aspect_memberships_on_aspect_id_and_contact_id", :unique => true
|
55
|
+
add_index "aspect_memberships", ["aspect_id"], :name => "index_aspect_memberships_on_aspect_id"
|
56
|
+
add_index "aspect_memberships", ["contact_id"], :name => "index_aspect_memberships_on_contact_id"
|
57
|
+
|
58
|
+
create_table "contacts", :force => true do |t|
|
59
|
+
t.integer "user_id", :null => false
|
60
|
+
t.integer "person_id", :null => false
|
61
|
+
t.datetime "created_at", :null => false
|
62
|
+
t.datetime "updated_at", :null => false
|
63
|
+
t.boolean "sharing", :default => false, :null => false
|
64
|
+
t.boolean "receiving", :default => false, :null => false
|
65
|
+
end
|
66
|
+
|
67
|
+
add_index "contacts", ["person_id"], :name => "index_contacts_on_person_id"
|
68
|
+
add_index "contacts", ["user_id", "person_id"], :name => "index_contacts_on_user_id_and_person_id", :unique => true
|
69
|
+
|
70
|
+
create_table "users", :force => true do |t|
|
71
|
+
t.string "username"
|
72
|
+
t.text "serialized_private_key"
|
73
|
+
t.boolean "getting_started", :default => true, :null => false
|
74
|
+
t.boolean "disable_mail", :default => false, :null => false
|
75
|
+
t.string "language"
|
76
|
+
t.string "email", :default => "", :null => false
|
77
|
+
t.string "encrypted_password", :default => "", :null => false
|
78
|
+
t.string "invitation_token", :limit => 60
|
79
|
+
t.datetime "invitation_sent_at"
|
80
|
+
t.string "reset_password_token"
|
81
|
+
t.datetime "remember_created_at"
|
82
|
+
t.integer "sign_in_count", :default => 0
|
83
|
+
t.datetime "current_sign_in_at"
|
84
|
+
t.datetime "last_sign_in_at"
|
85
|
+
t.string "current_sign_in_ip"
|
86
|
+
t.string "last_sign_in_ip"
|
87
|
+
t.datetime "created_at", :null => false
|
88
|
+
t.datetime "updated_at", :null => false
|
89
|
+
t.string "invitation_service", :limit => 127
|
90
|
+
t.string "invitation_identifier", :limit => 127
|
91
|
+
t.integer "invitation_limit"
|
92
|
+
t.integer "invited_by_id"
|
93
|
+
t.string "invited_by_type"
|
94
|
+
t.string "authentication_token", :limit => 30
|
95
|
+
t.string "unconfirmed_email"
|
96
|
+
t.string "confirm_email_token", :limit => 30
|
97
|
+
t.datetime "locked_at"
|
98
|
+
t.boolean "show_community_spotlight_in_stream", :default => true, :null => false
|
99
|
+
t.boolean "auto_follow_back", :default => false
|
100
|
+
t.integer "auto_follow_back_aspect_id"
|
101
|
+
t.text "hidden_shareables"
|
102
|
+
t.datetime "reset_password_sent_at"
|
103
|
+
t.datetime "last_seen"
|
104
|
+
end
|
105
|
+
|
106
|
+
add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token", :unique => true
|
107
|
+
add_index "users", ["email"], :name => "index_users_on_email"
|
108
|
+
add_index "users", ["invitation_service", "invitation_identifier"], :name => "index_users_on_invitation_service_and_invitation_identifier", :unique => true
|
109
|
+
add_index "users", ["invitation_token"], :name => "index_users_on_invitation_token"
|
110
|
+
add_index "users", ["username"], :name => "index_users_on_username", :unique => true
|
111
|
+
|
112
|
+
#add_foreign_key "aspect_memberships", "aspects", name: "aspect_memberships_aspect_id_fk", dependent: :delete
|
113
|
+
#add_foreign_key "aspect_memberships", "contacts", name: "aspect_memberships_contact_id_fk", dependent: :delete
|
114
|
+
#add_foreign_key "contacts", "people", name: "contacts_person_id_fk", dependent: :delete
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/test/store_test.rb
CHANGED
@@ -3,96 +3,113 @@
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
describe Vines::Store do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
File.open("#{dir}/wonderland.lit.crt", 'w') {|f| f.write(domain) }
|
11
|
-
File.open("#{dir}/wonderland.lit.key", 'w') {|f| f.write(key) }
|
12
|
-
|
13
|
-
wildcard, key = certificate('*.wonderland.lit')
|
14
|
-
File.open("#{dir}/wildcard.lit.crt", 'w') {|f| f.write(wildcard) }
|
15
|
-
File.open("#{dir}/wildcard.lit.key", 'w') {|f| f.write(key) }
|
6
|
+
let(:dir) { 'conf/certs' }
|
7
|
+
let(:domain_pair) { certificate('wonderland.lit') }
|
8
|
+
let(:wildcard_pair) { certificate('*.wonderland.lit') }
|
9
|
+
subject { Vines::Store.new(dir) }
|
16
10
|
|
17
|
-
|
11
|
+
before do
|
12
|
+
@files =
|
13
|
+
save('wonderland.lit', domain_pair) +
|
14
|
+
save('wildcard.lit', wildcard_pair) +
|
15
|
+
save('duplicate.lit', domain_pair)
|
18
16
|
end
|
19
17
|
|
20
18
|
after do
|
21
|
-
|
22
|
-
name = "conf/certs/#{f}"
|
19
|
+
@files.each do |name|
|
23
20
|
File.delete(name) if File.exists?(name)
|
24
21
|
end
|
25
22
|
end
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
describe 'creating a store' do
|
25
|
+
it 'parses certificate files' do
|
26
|
+
refute subject.certs.empty?
|
27
|
+
assert_equal OpenSSL::X509::Certificate, subject.certs.first.class
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'ignores expired certificates' do
|
31
|
+
assert subject.certs.all? {|c| c.not_after > Time.new }
|
32
|
+
end
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
+
it 'does not raise an error for duplicate certificates' do
|
35
|
+
assert Vines::Store.new(dir)
|
36
|
+
end
|
34
37
|
end
|
35
38
|
|
36
39
|
describe 'files_for_domain' do
|
37
40
|
it 'handles invalid input' do
|
38
|
-
assert_nil
|
39
|
-
assert_nil
|
41
|
+
assert_nil subject.files_for_domain(nil)
|
42
|
+
assert_nil subject.files_for_domain('')
|
40
43
|
end
|
41
44
|
|
42
45
|
it 'finds files by name' do
|
43
|
-
refute_nil
|
44
|
-
cert, key =
|
46
|
+
refute_nil subject.files_for_domain('wonderland.lit')
|
47
|
+
cert, key = subject.files_for_domain('wonderland.lit')
|
45
48
|
assert_certificate_matches_key cert, key
|
46
49
|
assert_equal 'wonderland.lit.crt', File.basename(cert)
|
47
50
|
assert_equal 'wonderland.lit.key', File.basename(key)
|
48
51
|
end
|
49
52
|
|
50
53
|
it 'finds files for wildcard' do
|
51
|
-
refute_nil
|
52
|
-
cert, key =
|
54
|
+
refute_nil subject.files_for_domain('foo.wonderland.lit')
|
55
|
+
cert, key = subject.files_for_domain('foo.wonderland.lit')
|
53
56
|
assert_certificate_matches_key cert, key
|
54
57
|
assert_equal 'wildcard.lit.crt', File.basename(cert)
|
55
58
|
assert_equal 'wildcard.lit.key', File.basename(key)
|
56
59
|
end
|
57
60
|
end
|
58
61
|
|
62
|
+
describe 'trusted?' do
|
63
|
+
it 'does not trust malformed certificates' do
|
64
|
+
refute subject.trusted?('bogus')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'does not trust unsigned certificates' do
|
68
|
+
pair = certificate('something.lit')
|
69
|
+
refute subject.trusted?(pair.cert)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
59
73
|
describe 'domain?' do
|
60
74
|
it 'handles invalid input' do
|
61
|
-
|
62
|
-
refute
|
63
|
-
refute
|
64
|
-
refute
|
65
|
-
refute
|
66
|
-
assert
|
75
|
+
pair = certificate('wonderland.lit')
|
76
|
+
refute subject.domain?(nil, nil)
|
77
|
+
refute subject.domain?(pair.cert, nil)
|
78
|
+
refute subject.domain?(pair.cert, '')
|
79
|
+
refute subject.domain?(nil, '')
|
80
|
+
assert subject.domain?(pair.cert, 'wonderland.lit')
|
67
81
|
end
|
68
82
|
|
69
83
|
it 'verifies certificate subject domains' do
|
70
|
-
|
71
|
-
refute
|
72
|
-
refute
|
73
|
-
assert
|
84
|
+
pair = certificate('wonderland.lit')
|
85
|
+
refute subject.domain?(pair.cert, 'bogus')
|
86
|
+
refute subject.domain?(pair.cert, 'www.wonderland.lit')
|
87
|
+
assert subject.domain?(pair.cert, 'wonderland.lit')
|
74
88
|
end
|
75
89
|
|
76
90
|
it 'verifies certificate subject alt domains' do
|
77
|
-
|
78
|
-
refute
|
79
|
-
refute
|
80
|
-
assert
|
81
|
-
assert
|
91
|
+
pair = certificate('wonderland.lit', 'www.wonderland.lit')
|
92
|
+
refute subject.domain?(pair.cert, 'bogus')
|
93
|
+
refute subject.domain?(pair.cert, 'tea.wonderland.lit')
|
94
|
+
assert subject.domain?(pair.cert, 'www.wonderland.lit')
|
95
|
+
assert subject.domain?(pair.cert, 'wonderland.lit')
|
82
96
|
end
|
83
97
|
|
84
98
|
it 'verifies certificate wildcard domains' do
|
85
|
-
|
86
|
-
refute
|
87
|
-
refute
|
88
|
-
assert
|
89
|
-
assert
|
90
|
-
assert
|
99
|
+
pair = certificate('wonderland.lit', '*.wonderland.lit')
|
100
|
+
refute subject.domain?(pair.cert, 'bogus')
|
101
|
+
refute subject.domain?(pair.cert, 'one.two.wonderland.lit')
|
102
|
+
assert subject.domain?(pair.cert, 'tea.wonderland.lit')
|
103
|
+
assert subject.domain?(pair.cert, 'www.wonderland.lit')
|
104
|
+
assert subject.domain?(pair.cert, 'wonderland.lit')
|
91
105
|
end
|
92
106
|
end
|
93
107
|
|
94
108
|
private
|
95
109
|
|
110
|
+
# A public certificate + private key pair.
|
111
|
+
Pair = Struct.new(:cert, :key)
|
112
|
+
|
96
113
|
def assert_certificate_matches_key(cert, key)
|
97
114
|
refute_nil cert
|
98
115
|
refute_nil key
|
@@ -102,7 +119,7 @@ describe Vines::Store do
|
|
102
119
|
end
|
103
120
|
|
104
121
|
def certificate(domain, altname=nil)
|
105
|
-
#
|
122
|
+
# Use small key so tests are fast.
|
106
123
|
key = OpenSSL::PKey::RSA.generate(256)
|
107
124
|
|
108
125
|
name = OpenSSL::X509::Name.parse("/C=US/ST=Colorado/L=Denver/O=Test/CN=#{domain}")
|
@@ -125,6 +142,21 @@ describe Vines::Store do
|
|
125
142
|
].map {|k, v| factory.create_ext(k, v) }
|
126
143
|
end
|
127
144
|
|
128
|
-
|
145
|
+
Pair.new(cert.to_pem, key.to_pem)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Write the domain's certificate and private key files to the filesystem for
|
149
|
+
# the store to use.
|
150
|
+
#
|
151
|
+
# domain - The domain name String to use in the file name (e.g. wonderland.lit).
|
152
|
+
# pair - The Pair containing the public certificate and private key data.
|
153
|
+
#
|
154
|
+
# Returns a String Array of file names that were written.
|
155
|
+
def save(domain, pair)
|
156
|
+
crt = File.expand_path("#{domain}.crt", dir)
|
157
|
+
key = File.expand_path("#{domain}.key", dir)
|
158
|
+
File.open(crt, 'w') {|f| f.write(pair.cert) }
|
159
|
+
File.open(key, 'w') {|f| f.write(pair.key) }
|
160
|
+
[crt, key]
|
129
161
|
end
|
130
162
|
end
|
data/test/test_helper.rb
CHANGED
data/vines.gemspec
CHANGED
@@ -18,11 +18,15 @@ Gem::Specification.new do |s|
|
|
18
18
|
|
19
19
|
s.add_dependency 'bcrypt', '~> 3.1'
|
20
20
|
s.add_dependency 'em-hiredis', '~> 0.1.1'
|
21
|
-
s.add_dependency 'eventmachine', '~> 1.0
|
22
|
-
s.add_dependency 'http_parser.rb', '~> 0.
|
23
|
-
s.add_dependency 'net-ldap', '~> 0.
|
24
|
-
s.add_dependency 'nokogiri', '
|
21
|
+
s.add_dependency 'eventmachine', '~> 1.0'
|
22
|
+
s.add_dependency 'http_parser.rb', '~> 0.6'
|
23
|
+
s.add_dependency 'net-ldap', '~> 0.6'
|
24
|
+
s.add_dependency 'nokogiri', '~> 1.6'
|
25
|
+
s.add_dependency 'activerecord', '~> 4.1.4'
|
25
26
|
|
27
|
+
|
28
|
+
s.add_development_dependency 'rails', '~> 4.1.4'
|
29
|
+
s.add_development_dependency 'sqlite3', '~> 1.3.9'
|
26
30
|
s.add_development_dependency 'minitest', '~> 5.3'
|
27
31
|
s.add_development_dependency 'rake', '~> 10.3'
|
28
32
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: diaspora-vines
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Graham
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-09-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bcrypt
|
@@ -45,56 +45,98 @@ dependencies:
|
|
45
45
|
requirements:
|
46
46
|
- - ~>
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 1.0
|
48
|
+
version: '1.0'
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - ~>
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 1.0
|
55
|
+
version: '1.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: http_parser.rb
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ~>
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 0.
|
62
|
+
version: '0.6'
|
63
63
|
type: :runtime
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: 0.
|
69
|
+
version: '0.6'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: net-ldap
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: 0.
|
76
|
+
version: '0.6'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - ~>
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: 0.
|
83
|
+
version: '0.6'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: nokogiri
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- -
|
88
|
+
- - ~>
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '1.6'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ~>
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '1.6'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: activerecord
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ~>
|
89
103
|
- !ruby/object:Gem::Version
|
90
|
-
version: 1.
|
104
|
+
version: 4.1.4
|
91
105
|
type: :runtime
|
92
106
|
prerelease: false
|
93
107
|
version_requirements: !ruby/object:Gem::Requirement
|
94
108
|
requirements:
|
95
|
-
- -
|
109
|
+
- - ~>
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 4.1.4
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: rails
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ~>
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 4.1.4
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 4.1.4
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: sqlite3
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ~>
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 1.3.9
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ~>
|
96
138
|
- !ruby/object:Gem::Version
|
97
|
-
version: 1.
|
139
|
+
version: 1.3.9
|
98
140
|
- !ruby/object:Gem::Dependency
|
99
141
|
name: minitest
|
100
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -282,6 +324,8 @@ files:
|
|
282
324
|
- test/storage/local_test.rb
|
283
325
|
- test/storage/mock_redis.rb
|
284
326
|
- test/storage/null_test.rb
|
327
|
+
- test/storage/sql.rb
|
328
|
+
- test/storage/sql_schema.rb
|
285
329
|
- test/storage/storage_tests.rb
|
286
330
|
- test/storage_test.rb
|
287
331
|
- test/store_test.rb
|
@@ -325,7 +369,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
325
369
|
version: '0'
|
326
370
|
requirements: []
|
327
371
|
rubyforge_project:
|
328
|
-
rubygems_version: 2.
|
372
|
+
rubygems_version: 2.4.1
|
329
373
|
signing_key:
|
330
374
|
specification_version: 4
|
331
375
|
summary: Diaspora-vines is a Vines fork build for diaspora integration.
|
@@ -381,7 +425,9 @@ test_files:
|
|
381
425
|
- test/config_test.rb
|
382
426
|
- test/test_helper.rb
|
383
427
|
- test/storage/storage_tests.rb
|
428
|
+
- test/storage/sql_schema.rb
|
384
429
|
- test/storage/null_test.rb
|
385
430
|
- test/storage/mock_redis.rb
|
386
431
|
- test/storage/ldap_test.rb
|
387
432
|
- test/storage/local_test.rb
|
433
|
+
- test/storage/sql.rb
|