pebblebed 0.0.22 → 0.0.23
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +7 -0
- data/lib/pebblebed/security/access_data.rb +85 -0
- data/lib/pebblebed/security/client.rb +33 -0
- data/lib/pebblebed/security/listener.rb +94 -0
- data/lib/pebblebed/uid.rb +6 -4
- data/lib/pebblebed/version.rb +1 -1
- data/lib/pebblebed.rb +3 -0
- data/spec/security/access_data_spec.rb +40 -0
- data/spec/security/client_spec.rb +29 -0
- data/spec/security/listener_spec.rb +26 -0
- metadata +109 -29
data/README.md
CHANGED
@@ -152,3 +152,10 @@ For some pebbles Pebblebed may furnish a richer client with helper methods. This
|
|
152
152
|
augmented client in the `/lib/pebblebed/clients` folder and naming the class `Pebblebed::<YourPebbleName>Client`. For
|
153
153
|
an example of this see `CheckpointClient` which in addition to the common http-methods provides the method `me` which
|
154
154
|
returns the logged in user and `god?` which checks whether she's a god(dess).
|
155
|
+
|
156
|
+
Troubleshooting
|
157
|
+
===============
|
158
|
+
|
159
|
+
When something fails, say you're trying to post to grove using a pebblebed connector, it might be a good idea to try the same thing from command line first:
|
160
|
+
|
161
|
+
curl -XPOST 'http://example.com/api/grove/v1/posts/post.todo:dna.org.a.b' --data '{"session":"session_name","post":{"document": {"body": "Hello Grove!"},"tags": ["welcome", "tutorial"]}}' -H "Content-Type: application/json"
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Models the checkpoint group access data for one identity
|
2
|
+
module Pebblebed
|
3
|
+
module Security
|
4
|
+
class AccessData
|
5
|
+
attr_reader :group_ids
|
6
|
+
|
7
|
+
def initialize(data)
|
8
|
+
if data[:subtrees] || data[:group_ids]
|
9
|
+
@group_ids = Set.new(data[:group_ids])
|
10
|
+
@subtrees = Set.new
|
11
|
+
data[:subtrees].each do |subtree|
|
12
|
+
@subtrees << subtree.split('.')
|
13
|
+
end
|
14
|
+
else
|
15
|
+
# Assume this is a /identities/:id/memberships result from checkpoint
|
16
|
+
parse_checkpoint_record(data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Takes a path (possibly with wildcards) and returns
|
21
|
+
# any subtrees that are relevant to determine accessibility
|
22
|
+
# to restricted content in a query of documents in that
|
23
|
+
# wildcard_path. All relevant subtrees are guaranteed to be
|
24
|
+
# returned, but not all returned subtrees are guaranteed to be
|
25
|
+
# relevant. I.e. some irrelevant subtrees may be returned.
|
26
|
+
# (If the path does not use wildcards, relevance is
|
27
|
+
# guaranteed.)
|
28
|
+
def relevant_subtrees(wildcard_path)
|
29
|
+
pristine = self.class.pristine_path(wildcard_path)
|
30
|
+
intersecting_subtrees(pristine)
|
31
|
+
end
|
32
|
+
|
33
|
+
def subtrees
|
34
|
+
@subtrees.map { |subtree| subtree.join('.') }
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Takes a path possibly containing wildcard characters and returns
|
40
|
+
# a superset path that just contains proper labels. E.g. "a.b.c|d.*" returns
|
41
|
+
# "a.b"
|
42
|
+
def self.pristine_path(wildcard_path)
|
43
|
+
result = []
|
44
|
+
wildcard_path.split('.').each do |label|
|
45
|
+
break unless Pebblebed::Uid.valid_label?(label)
|
46
|
+
result << label
|
47
|
+
end
|
48
|
+
result.join('.')
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns any subtrees that "intersect" the provided location. That is
|
52
|
+
# they are either supersets of the location ("a.b" is a superset of "a.b.c")
|
53
|
+
# or subsets ("a.b.c.d" is a subset of "a.b.c"). Also exact matches are returned
|
54
|
+
# ('a.b.c' matches 'a.b.c', duh!)
|
55
|
+
def intersecting_subtrees(location)
|
56
|
+
location = location.split('.')
|
57
|
+
result = []
|
58
|
+
@subtrees.each do |subtree|
|
59
|
+
if subtree.length >= location.length
|
60
|
+
# is this a subset tree?
|
61
|
+
result << subtree if location == subtree[0...location.length]
|
62
|
+
else
|
63
|
+
# is this a superset tree?
|
64
|
+
result << subtree if subtree == location[0...subtree.length]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
result.map { |subtree| subtree.join('.') }
|
68
|
+
end
|
69
|
+
|
70
|
+
# Initializes the instance with data from a checkpoint GET /identities/:id/memberships request
|
71
|
+
def parse_checkpoint_record(memberships_record)
|
72
|
+
@group_ids = Set.new
|
73
|
+
@subtrees = Set.new
|
74
|
+
memberships_record['memberships'].each do |membership|
|
75
|
+
@group_ids << membership['membership']['group_id']
|
76
|
+
end
|
77
|
+
memberships_record['groups'].each do |group|
|
78
|
+
group['group']['subtrees'].each do |subtree|
|
79
|
+
@subtrees << subtree.split('.')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# A class that helps
|
2
|
+
module Pebblebed
|
3
|
+
module Security
|
4
|
+
class Client
|
5
|
+
IDENTITY_MEMBERSHIPS_TTL = 10*60
|
6
|
+
|
7
|
+
def initialize(connector)
|
8
|
+
@connector = connector
|
9
|
+
@access_data = {} # Memoized identity access data records
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns an object representing the current access data for a given identity
|
13
|
+
def access_data_for(identity)
|
14
|
+
identity = identity.id unless identity.is_a?(Numeric)
|
15
|
+
return @access_data[identity] if @access_data[identity]
|
16
|
+
membership_data = fetch_membership_data_for(identity)
|
17
|
+
result = Pebblebed::Security::AccessData.new(membership_data)
|
18
|
+
@access_data[identity] = result
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def fetch_membership_data_for(identity_id)
|
25
|
+
result = Pebblebed.memcached.fetch("identity_membership_data:#{identity}", IDENTITY_MEMBERSHIPS_TTL) do
|
26
|
+
@connector.checkpoint.get("/identities/#{identity}/memberships").to_json
|
27
|
+
end
|
28
|
+
JSON.parse(result)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# Listens to security configuration updates and lets the client application
|
2
|
+
# register custom handlers for each event.
|
3
|
+
module Pebblebed
|
4
|
+
module Security
|
5
|
+
class Listener
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@app_name = options[:app_name]
|
9
|
+
@handlers = {:group => {}, :group_membership => {}, :group_subtree => {}}
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
@thread ||= Thread.new do
|
14
|
+
process
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop
|
19
|
+
@thread.kill if @thread
|
20
|
+
@thread = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_group_declared(&block)
|
24
|
+
@handlers[:group][:create] = block
|
25
|
+
@handlers[:group][:update] = block
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_group_removed(&block)
|
29
|
+
@handlers[:group][:delete] = block
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_subtree_declared(&block)
|
33
|
+
@handlers[:group_subtree][:create] = block
|
34
|
+
@handlers[:group_subtree][:update] = block
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_subtree_removed(&block)
|
38
|
+
@handlers[:group_subtree][:delete] = block
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_membership_declared(&block)
|
42
|
+
@handlers[:group_membership][:create] = block
|
43
|
+
@handlers[:group_membership][:update] = block
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_membership_removed(&block)
|
47
|
+
@handlers[:group_membership][:delete] = block
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Subscribe to queue and handle incoming messages
|
53
|
+
def process
|
54
|
+
river = Pebblebed::River.new
|
55
|
+
queue_options = {
|
56
|
+
:name => "#{@app_name}.security_listener",
|
57
|
+
:path => '**',
|
58
|
+
:klass => 'group|group_membership|group_subtree',
|
59
|
+
:event => '**',
|
60
|
+
:interval => 1
|
61
|
+
}
|
62
|
+
queue = river.queue queue_options
|
63
|
+
queue.subscribe(ack: true) do |message|
|
64
|
+
consider message
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Parse an incoming message and pass it on
|
69
|
+
def consider(message)
|
70
|
+
payload = JSON.parse(message[:payload])
|
71
|
+
event = payload['event']
|
72
|
+
attributes = payload['attributes']
|
73
|
+
klass = Pebblebed::Uid.raw_parse(payload['uid']).first
|
74
|
+
handle(event, klass, attributes)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Determines the correct event handler for the message and calls it
|
78
|
+
def handle(event, klass, attributes)
|
79
|
+
event_handler = @handlers[klass.to_sym][event.to_sym]
|
80
|
+
return unless event_handler
|
81
|
+
case klass
|
82
|
+
when 'group'
|
83
|
+
event_handler.call(:id => attributes['id'], :label => attributes['label'])
|
84
|
+
when 'group_membership'
|
85
|
+
event_handler.call(:group_id => attributes['group_id'],
|
86
|
+
:identity_id => attributes['identity_id'])
|
87
|
+
when 'group_subtree'
|
88
|
+
event_handler.call(:group_id => attributes['group_id'],
|
89
|
+
:location => attributes['location'])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/pebblebed/uid.rb
CHANGED
@@ -116,29 +116,31 @@ module Pebblebed
|
|
116
116
|
stars_are_solitary?(path) && pipes_are_interleaved?(path) && carets_are_leading?(path) && stars_are_terminating?(path)
|
117
117
|
end
|
118
118
|
|
119
|
-
# a.*.c is
|
119
|
+
# a.*.c is accepted
|
120
120
|
# a.*b.c is not
|
121
|
+
# A later rule ensures that * always falls at the end of a path
|
121
122
|
def stars_are_solitary?(path)
|
122
123
|
!path.split('.').any? {|s| s.match(/.+\*|\*.+/)}
|
123
124
|
end
|
124
125
|
|
125
|
-
# a.b|c.d is
|
126
|
+
# a.b|c.d is accepted
|
126
127
|
# a.|b.c is not
|
127
128
|
def pipes_are_interleaved?(path)
|
128
129
|
!path.split('.').any? {|s| s.match(/^\||\|$/)}
|
129
130
|
end
|
130
131
|
|
131
|
-
# a.^b.c is
|
132
|
+
# a.^b.c is accepted
|
132
133
|
# a.b^c.d is not
|
133
134
|
def carets_are_leading?(path)
|
134
135
|
!path.split('.').any? {|s| s.match(/.+\^|\^$/) }
|
135
136
|
end
|
136
137
|
|
137
|
-
# a.b.* is
|
138
|
+
# a.b.* is accepted
|
138
139
|
# *.b.c is not
|
139
140
|
def stars_are_terminating?(path)
|
140
141
|
path !~ /.*\*\.\w/
|
141
142
|
end
|
143
|
+
|
142
144
|
end
|
143
145
|
end
|
144
146
|
|
data/lib/pebblebed/version.rb
CHANGED
data/lib/pebblebed.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pebblebed/uid'
|
3
|
+
require 'pebblebed/security/access_data'
|
4
|
+
|
5
|
+
describe Pebblebed::Security::AccessData do
|
6
|
+
let :access_data do
|
7
|
+
Pebblebed::Security::AccessData.new(
|
8
|
+
:groups => [1,2,3],
|
9
|
+
:subtrees => ['a.b', 'a.b.c.d.e', 'a.c.d', 'a.c.e.f']
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can calculate a pristine path" do
|
14
|
+
Pebblebed::Security::AccessData.pristine_path("a.b.c|d").should eq "a.b"
|
15
|
+
Pebblebed::Security::AccessData.pristine_path("a.b").should eq "a.b"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can calculate relevant paths" do
|
19
|
+
access_data.relevant_subtrees('a.b').sort.should eq ['a.b', 'a.b.c.d.e']
|
20
|
+
access_data.relevant_subtrees('a.b.c').sort.should eq ['a.b', 'a.b.c.d.e']
|
21
|
+
access_data.relevant_subtrees('a.c.e').sort.should eq ['a.c.e.f']
|
22
|
+
access_data.relevant_subtrees('a.*').sort.should eq ['a.b', 'a.b.c.d.e', 'a.c.d', 'a.c.e.f']
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can parse a checkpoint record" do
|
26
|
+
record = {
|
27
|
+
'memberships' => [
|
28
|
+
{'membership' => {'id' => 10, 'group_id' => 1, 'identity_id' => 1}},
|
29
|
+
{'membership' => {'id' => 20, 'group_id' => 2, 'identity_id' => 1}},
|
30
|
+
],
|
31
|
+
'groups' => [
|
32
|
+
{'group' => {'id' => 1, 'label' => "group_1", 'subtrees' => ["a.b.c"]}},
|
33
|
+
{'group' => {'id' => 2, 'label' => "group_2", 'subtrees' => ["a.c.d.c"]}}
|
34
|
+
]
|
35
|
+
}
|
36
|
+
ad = Pebblebed::Security::AccessData.new(record)
|
37
|
+
ad.subtrees.sort.should eq ['a.b.c', 'a.c.d.c']
|
38
|
+
ad.group_ids.sort.should eq [1,2]
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pebblebed/uid'
|
3
|
+
require 'pebblebed/security/access_data'
|
4
|
+
require 'pebblebed/security/client'
|
5
|
+
|
6
|
+
describe Pebblebed::Security::Client do
|
7
|
+
let :client do
|
8
|
+
Pebblebed::Security::Client.new(nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
let :sample_memberships_record do
|
12
|
+
{
|
13
|
+
'memberships' => [
|
14
|
+
{'membership' => {'id' => 10, 'group_id' => 1, 'identity_id' => 1}},
|
15
|
+
{'membership' => {'id' => 20, 'group_id' => 2, 'identity_id' => 1}},
|
16
|
+
],
|
17
|
+
'groups' => [
|
18
|
+
{'group' => {'id' => 1, 'label' => "group_1", 'subtrees' => ["a.b.c"]}},
|
19
|
+
{'group' => {'id' => 2, 'label' => "group_2", 'subtrees' => ["a.c.d.c"]}}
|
20
|
+
]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can fetch access_data" do
|
25
|
+
client.stub(:fetch_membership_data_for).and_return(sample_memberships_record)
|
26
|
+
ad = client.access_data_for(1)
|
27
|
+
ad.subtrees.sort.should eq ['a.b.c', 'a.c.d.c']
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pebblebed/uid'
|
3
|
+
require 'pebblebed/security/listener'
|
4
|
+
|
5
|
+
describe Pebblebed::Security::Listener do
|
6
|
+
let :listener do
|
7
|
+
Pebblebed::Security::Listener.new(:app_name => "test")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "can generate events from incoming messages" do
|
11
|
+
the_attrs = nil
|
12
|
+
listener.on_group_declared do |attrs|
|
13
|
+
the_attrs = attrs
|
14
|
+
end
|
15
|
+
message = {:payload => {
|
16
|
+
'event' => 'create',
|
17
|
+
'uid' => 'group:abc.groups$10',
|
18
|
+
'attributes' => {
|
19
|
+
'id' => 10,
|
20
|
+
'label' => 'the_label'
|
21
|
+
}
|
22
|
+
}.to_json}
|
23
|
+
listener.send(:consider, message)
|
24
|
+
the_attrs[:id].should eq 10
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pebblebed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.23
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-09-
|
13
|
+
date: 2012-09-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
17
|
-
requirement:
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,15 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements:
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
26
31
|
- !ruby/object:Gem::Dependency
|
27
32
|
name: rake
|
28
|
-
requirement:
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
29
34
|
none: false
|
30
35
|
requirements:
|
31
36
|
- - ! '>='
|
@@ -33,10 +38,15 @@ dependencies:
|
|
33
38
|
version: '0'
|
34
39
|
type: :development
|
35
40
|
prerelease: false
|
36
|
-
version_requirements:
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
37
47
|
- !ruby/object:Gem::Dependency
|
38
48
|
name: simplecov
|
39
|
-
requirement:
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
40
50
|
none: false
|
41
51
|
requirements:
|
42
52
|
- - ! '>='
|
@@ -44,10 +54,15 @@ dependencies:
|
|
44
54
|
version: '0'
|
45
55
|
type: :development
|
46
56
|
prerelease: false
|
47
|
-
version_requirements:
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
48
63
|
- !ruby/object:Gem::Dependency
|
49
64
|
name: deepstruct
|
50
|
-
requirement:
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
51
66
|
none: false
|
52
67
|
requirements:
|
53
68
|
- - ! '>='
|
@@ -55,10 +70,15 @@ dependencies:
|
|
55
70
|
version: 0.0.2
|
56
71
|
type: :runtime
|
57
72
|
prerelease: false
|
58
|
-
version_requirements:
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 0.0.2
|
59
79
|
- !ruby/object:Gem::Dependency
|
60
80
|
name: curb
|
61
|
-
requirement:
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
62
82
|
none: false
|
63
83
|
requirements:
|
64
84
|
- - ! '>='
|
@@ -66,10 +86,15 @@ dependencies:
|
|
66
86
|
version: 0.7.14
|
67
87
|
type: :runtime
|
68
88
|
prerelease: false
|
69
|
-
version_requirements:
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.7.14
|
70
95
|
- !ruby/object:Gem::Dependency
|
71
96
|
name: yajl-ruby
|
72
|
-
requirement:
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
73
98
|
none: false
|
74
99
|
requirements:
|
75
100
|
- - ! '>='
|
@@ -77,10 +102,15 @@ dependencies:
|
|
77
102
|
version: '0'
|
78
103
|
type: :runtime
|
79
104
|
prerelease: false
|
80
|
-
version_requirements:
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
81
111
|
- !ruby/object:Gem::Dependency
|
82
112
|
name: queryparams
|
83
|
-
requirement:
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
84
114
|
none: false
|
85
115
|
requirements:
|
86
116
|
- - ! '>='
|
@@ -88,10 +118,15 @@ dependencies:
|
|
88
118
|
version: '0'
|
89
119
|
type: :runtime
|
90
120
|
prerelease: false
|
91
|
-
version_requirements:
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
92
127
|
- !ruby/object:Gem::Dependency
|
93
128
|
name: futurevalue
|
94
|
-
requirement:
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
95
130
|
none: false
|
96
131
|
requirements:
|
97
132
|
- - ! '>='
|
@@ -99,10 +134,15 @@ dependencies:
|
|
99
134
|
version: '0'
|
100
135
|
type: :runtime
|
101
136
|
prerelease: false
|
102
|
-
version_requirements:
|
137
|
+
version_requirements: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
103
143
|
- !ruby/object:Gem::Dependency
|
104
144
|
name: pathbuilder
|
105
|
-
requirement:
|
145
|
+
requirement: !ruby/object:Gem::Requirement
|
106
146
|
none: false
|
107
147
|
requirements:
|
108
148
|
- - ! '>='
|
@@ -110,10 +150,15 @@ dependencies:
|
|
110
150
|
version: '0'
|
111
151
|
type: :runtime
|
112
152
|
prerelease: false
|
113
|
-
version_requirements:
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ! '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
114
159
|
- !ruby/object:Gem::Dependency
|
115
160
|
name: nokogiri
|
116
|
-
requirement:
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
117
162
|
none: false
|
118
163
|
requirements:
|
119
164
|
- - ! '>='
|
@@ -121,10 +166,15 @@ dependencies:
|
|
121
166
|
version: '0'
|
122
167
|
type: :runtime
|
123
168
|
prerelease: false
|
124
|
-
version_requirements:
|
169
|
+
version_requirements: !ruby/object:Gem::Requirement
|
170
|
+
none: false
|
171
|
+
requirements:
|
172
|
+
- - ! '>='
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
125
175
|
- !ruby/object:Gem::Dependency
|
126
176
|
name: i18n
|
127
|
-
requirement:
|
177
|
+
requirement: !ruby/object:Gem::Requirement
|
128
178
|
none: false
|
129
179
|
requirements:
|
130
180
|
- - ! '>='
|
@@ -132,10 +182,15 @@ dependencies:
|
|
132
182
|
version: '0'
|
133
183
|
type: :runtime
|
134
184
|
prerelease: false
|
135
|
-
version_requirements:
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
none: false
|
187
|
+
requirements:
|
188
|
+
- - ! '>='
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '0'
|
136
191
|
- !ruby/object:Gem::Dependency
|
137
192
|
name: activesupport
|
138
|
-
requirement:
|
193
|
+
requirement: !ruby/object:Gem::Requirement
|
139
194
|
none: false
|
140
195
|
requirements:
|
141
196
|
- - ! '>='
|
@@ -143,10 +198,15 @@ dependencies:
|
|
143
198
|
version: '0'
|
144
199
|
type: :runtime
|
145
200
|
prerelease: false
|
146
|
-
version_requirements:
|
201
|
+
version_requirements: !ruby/object:Gem::Requirement
|
202
|
+
none: false
|
203
|
+
requirements:
|
204
|
+
- - ! '>='
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
147
207
|
- !ruby/object:Gem::Dependency
|
148
208
|
name: bunny
|
149
|
-
requirement:
|
209
|
+
requirement: !ruby/object:Gem::Requirement
|
150
210
|
none: false
|
151
211
|
requirements:
|
152
212
|
- - ! '>='
|
@@ -154,7 +214,12 @@ dependencies:
|
|
154
214
|
version: '0'
|
155
215
|
type: :runtime
|
156
216
|
prerelease: false
|
157
|
-
version_requirements:
|
217
|
+
version_requirements: !ruby/object:Gem::Requirement
|
218
|
+
none: false
|
219
|
+
requirements:
|
220
|
+
- - ! '>='
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
158
223
|
description: Development tools for working with Pebblebed
|
159
224
|
email:
|
160
225
|
- katrina@bengler.no
|
@@ -180,6 +245,9 @@ files:
|
|
180
245
|
- lib/pebblebed/parts.rb
|
181
246
|
- lib/pebblebed/river.rb
|
182
247
|
- lib/pebblebed/river/subscription.rb
|
248
|
+
- lib/pebblebed/security/access_data.rb
|
249
|
+
- lib/pebblebed/security/client.rb
|
250
|
+
- lib/pebblebed/security/listener.rb
|
183
251
|
- lib/pebblebed/sinatra.rb
|
184
252
|
- lib/pebblebed/uid.rb
|
185
253
|
- lib/pebblebed/uid_query.rb
|
@@ -194,6 +262,9 @@ files:
|
|
194
262
|
- spec/mockcached.rb
|
195
263
|
- spec/river_spec.rb
|
196
264
|
- spec/river_subscription_spec.rb
|
265
|
+
- spec/security/access_data_spec.rb
|
266
|
+
- spec/security/client_spec.rb
|
267
|
+
- spec/security/listener_spec.rb
|
197
268
|
- spec/spec_helper.rb
|
198
269
|
- spec/uid_query_spec.rb
|
199
270
|
- spec/uid_spec.rb
|
@@ -209,15 +280,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
209
280
|
- - ! '>='
|
210
281
|
- !ruby/object:Gem::Version
|
211
282
|
version: '0'
|
283
|
+
segments:
|
284
|
+
- 0
|
285
|
+
hash: 4364516963973573943
|
212
286
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
287
|
none: false
|
214
288
|
requirements:
|
215
289
|
- - ! '>='
|
216
290
|
- !ruby/object:Gem::Version
|
217
291
|
version: '0'
|
292
|
+
segments:
|
293
|
+
- 0
|
294
|
+
hash: 4364516963973573943
|
218
295
|
requirements: []
|
219
296
|
rubyforge_project: pebblebed
|
220
|
-
rubygems_version: 1.8.
|
297
|
+
rubygems_version: 1.8.24
|
221
298
|
signing_key:
|
222
299
|
specification_version: 3
|
223
300
|
summary: Development tools for working with Pebblebed
|
@@ -231,6 +308,9 @@ test_files:
|
|
231
308
|
- spec/mockcached.rb
|
232
309
|
- spec/river_spec.rb
|
233
310
|
- spec/river_subscription_spec.rb
|
311
|
+
- spec/security/access_data_spec.rb
|
312
|
+
- spec/security/client_spec.rb
|
313
|
+
- spec/security/listener_spec.rb
|
234
314
|
- spec/spec_helper.rb
|
235
315
|
- spec/uid_query_spec.rb
|
236
316
|
- spec/uid_spec.rb
|