ably 0.7.6 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -7
- data/SPEC.md +310 -269
- data/lib/ably/auth.rb +177 -127
- data/lib/ably/models/presence_message.rb +1 -1
- data/lib/ably/models/protocol_message.rb +1 -2
- data/lib/ably/models/token_details.rb +101 -0
- data/lib/ably/models/token_request.rb +108 -0
- data/lib/ably/modules/http_helpers.rb +1 -1
- data/lib/ably/realtime.rb +2 -6
- data/lib/ably/realtime/channel.rb +14 -8
- data/lib/ably/realtime/client.rb +2 -6
- data/lib/ably/realtime/connection.rb +4 -2
- data/lib/ably/rest.rb +2 -6
- data/lib/ably/rest/channel.rb +10 -6
- data/lib/ably/rest/client.rb +15 -16
- data/lib/ably/rest/presence.rb +12 -10
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/client_spec.rb +15 -15
- data/spec/acceptance/realtime/connection_failures_spec.rb +3 -3
- data/spec/acceptance/realtime/connection_spec.rb +9 -9
- data/spec/acceptance/rest/auth_spec.rb +248 -172
- data/spec/acceptance/rest/base_spec.rb +8 -6
- data/spec/acceptance/rest/channel_spec.rb +9 -2
- data/spec/acceptance/rest/client_spec.rb +21 -21
- data/spec/acceptance/rest/presence_spec.rb +12 -5
- data/spec/acceptance/rest/stats_spec.rb +4 -4
- data/spec/rspec_config.rb +3 -2
- data/spec/shared/client_initializer_behaviour.rb +21 -24
- data/spec/support/api_helper.rb +3 -3
- data/spec/support/test_app.rb +9 -9
- data/spec/unit/auth_spec.rb +17 -0
- data/spec/unit/models/token_details_spec.rb +111 -0
- data/spec/unit/models/token_request_spec.rb +110 -0
- data/spec/unit/rest/client_spec.rb +1 -1
- metadata +8 -5
- data/lib/ably/models/token.rb +0 -74
- data/spec/unit/models/token_spec.rb +0 -86
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/model_behaviour'
|
3
|
+
|
4
|
+
describe Ably::Models::TokenRequest do
|
5
|
+
subject { Ably::Models::TokenRequest }
|
6
|
+
|
7
|
+
it_behaves_like 'a model', with_simple_attributes: %w(key_name client_id nonce mac) do
|
8
|
+
let(:model_args) { [] }
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'attributes' do
|
12
|
+
context '#capability' do
|
13
|
+
let(:capability) { { "value" => random_str } }
|
14
|
+
let(:capability_str) { JSON.dump(capability) }
|
15
|
+
|
16
|
+
subject { Ably::Models::TokenRequest.new({ capability: capability_str }) }
|
17
|
+
|
18
|
+
it 'retrieves attribute :capability as parsed JSON' do
|
19
|
+
expect(subject.capability).to eql(capability)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "#timestamp" do
|
24
|
+
let(:time) { Time.now }
|
25
|
+
|
26
|
+
context 'with :timestamp option as milliseconds in constructor' do
|
27
|
+
subject { Ably::Models::TokenRequest.new(timestamp: time.to_i * 1000) }
|
28
|
+
|
29
|
+
it "retrieves attribute :timestamp as Time" do
|
30
|
+
expect(subject.timestamp).to be_a(Time)
|
31
|
+
expect(subject.timestamp.to_i).to eql(time.to_i)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'with :timestamp option as Time in constructor' do
|
36
|
+
subject { Ably::Models::TokenRequest.new(timestamp: time) }
|
37
|
+
|
38
|
+
it "retrieves attribute :timestamp as Time" do
|
39
|
+
expect(subject.timestamp).to be_a(Time)
|
40
|
+
expect(subject.timestamp.to_i).to eql(time.to_i)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when converted to JSON' do
|
45
|
+
subject { Ably::Models::TokenRequest.new(timestamp: time) }
|
46
|
+
|
47
|
+
it "is in milliseconds since epoch" do
|
48
|
+
expect(JSON.parse(JSON.dump(subject))['timestamp']).to eql((time.to_f * 1000).round)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "#ttl" do
|
54
|
+
let(:ttl) { 500 }
|
55
|
+
|
56
|
+
context 'with :ttl option as milliseconds in constructor' do
|
57
|
+
subject { Ably::Models::TokenRequest.new(ttl: ttl * 1000) }
|
58
|
+
|
59
|
+
it "retrieves attribute :ttl as seconds" do
|
60
|
+
expect(subject.ttl).to be_a(Integer)
|
61
|
+
expect(subject.ttl).to eql(ttl)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when converted to JSON' do
|
66
|
+
subject { Ably::Models::TokenRequest.new(ttl: ttl * 1000) }
|
67
|
+
|
68
|
+
it "is in milliseconds since epoch" do
|
69
|
+
expect(JSON.parse(JSON.dump(subject))['ttl']).to eql(ttl * 1000)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context '==' do
|
76
|
+
let(:token_attributes) { { client_id: random_str } }
|
77
|
+
|
78
|
+
it 'is true when attributes are the same' do
|
79
|
+
new_token = -> { Ably::Models::TokenRequest.new(token_attributes) }
|
80
|
+
expect(new_token[]).to eq(new_token[])
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'is false when attributes are not the same' do
|
84
|
+
expect(Ably::Models::TokenRequest.new(client_id: 1)).to_not eq(Ably::Models::TokenRequest.new(client_id: 2))
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'is false when class type differs' do
|
88
|
+
expect(Ably::Models::TokenRequest.new(client_id: 1)).to_not eq(nil)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'TokenRequest conversion methods', :api_private do
|
93
|
+
context 'with a TokenRequest object' do
|
94
|
+
let(:token_request) { Ably::Models::TokenRequest.new(client_id: random_str) }
|
95
|
+
|
96
|
+
it 'returns the TokenRequest object' do
|
97
|
+
expect(Ably::Models::TokenRequest(token_request)).to eql(token_request)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with a JSON object' do
|
102
|
+
let(:client_id) { random_str }
|
103
|
+
let(:token_request_json) { { client_id: client_id } }
|
104
|
+
|
105
|
+
it 'returns a new TokenRequest object from the JSON' do
|
106
|
+
expect(Ably::Models::TokenRequest(token_request_json).client_id).to eql(client_id)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -40,7 +40,7 @@ describe Ably::Rest::Client do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
context 'set to true' do
|
43
|
-
context 'without an key or
|
43
|
+
context 'without an key or token' do
|
44
44
|
let(:client_options) { { use_token_auth: true, key: true } }
|
45
45
|
|
46
46
|
it 'fails as an key is required to issue tokens' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ably
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lewis Marshall
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-04-
|
12
|
+
date: 2015-04-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -257,7 +257,8 @@ files:
|
|
257
257
|
- lib/ably/models/protocol_message.rb
|
258
258
|
- lib/ably/models/stat.rb
|
259
259
|
- lib/ably/models/stats_types.rb
|
260
|
-
- lib/ably/models/
|
260
|
+
- lib/ably/models/token_details.rb
|
261
|
+
- lib/ably/models/token_request.rb
|
261
262
|
- lib/ably/modules/ably.rb
|
262
263
|
- lib/ably/modules/async_wrapper.rb
|
263
264
|
- lib/ably/modules/channels_collection.rb
|
@@ -356,7 +357,8 @@ files:
|
|
356
357
|
- spec/unit/models/presence_message_spec.rb
|
357
358
|
- spec/unit/models/protocol_message_spec.rb
|
358
359
|
- spec/unit/models/stats_spec.rb
|
359
|
-
- spec/unit/models/
|
360
|
+
- spec/unit/models/token_details_spec.rb
|
361
|
+
- spec/unit/models/token_request_spec.rb
|
360
362
|
- spec/unit/modules/async_wrapper_spec.rb
|
361
363
|
- spec/unit/modules/conversions_spec.rb
|
362
364
|
- spec/unit/modules/enum_spec.rb
|
@@ -449,7 +451,8 @@ test_files:
|
|
449
451
|
- spec/unit/models/presence_message_spec.rb
|
450
452
|
- spec/unit/models/protocol_message_spec.rb
|
451
453
|
- spec/unit/models/stats_spec.rb
|
452
|
-
- spec/unit/models/
|
454
|
+
- spec/unit/models/token_details_spec.rb
|
455
|
+
- spec/unit/models/token_request_spec.rb
|
453
456
|
- spec/unit/modules/async_wrapper_spec.rb
|
454
457
|
- spec/unit/modules/conversions_spec.rb
|
455
458
|
- spec/unit/modules/enum_spec.rb
|
data/lib/ably/models/token.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
module Ably::Models
|
2
|
-
# Authentication token issued by Ably in response to an token request
|
3
|
-
class Token
|
4
|
-
include Ably::Modules::ModelCommon
|
5
|
-
|
6
|
-
DEFAULTS = {
|
7
|
-
capability: { '*' => ['*'] },
|
8
|
-
ttl: 60 * 60 # 1 hour
|
9
|
-
}
|
10
|
-
|
11
|
-
# Buffer in seconds given to the use of a token prior to it being considered unusable
|
12
|
-
# For example, if buffer is 10s, the token can no longer be used for new requests 9s before it expires
|
13
|
-
TOKEN_EXPIRY_BUFFER = 5
|
14
|
-
|
15
|
-
def initialize(attributes)
|
16
|
-
@hash_object = IdiomaticRubyWrapper(attributes.clone.freeze)
|
17
|
-
end
|
18
|
-
|
19
|
-
# @!attribute [r] id
|
20
|
-
# @return [String] Unique token ID used to authenticate requests
|
21
|
-
def id
|
22
|
-
hash.fetch(:id)
|
23
|
-
end
|
24
|
-
|
25
|
-
# @!attribute [r] key_id
|
26
|
-
# @return [String] Key ID used to create this token
|
27
|
-
def key_id
|
28
|
-
hash.fetch(:key)
|
29
|
-
end
|
30
|
-
|
31
|
-
# @!attribute [r] issued_at
|
32
|
-
# @return [Time] Time the token was issued
|
33
|
-
def issued_at
|
34
|
-
as_time_from_epoch(hash.fetch(:issued_at), granularity: :s)
|
35
|
-
end
|
36
|
-
|
37
|
-
# @!attribute [r] expires_at
|
38
|
-
# @return [Time] Time the token expires
|
39
|
-
def expires_at
|
40
|
-
as_time_from_epoch(hash.fetch(:expires), granularity: :s)
|
41
|
-
end
|
42
|
-
|
43
|
-
# @!attribute [r] capability
|
44
|
-
# @return [Hash] Capabilities assigned to this token
|
45
|
-
def capability
|
46
|
-
hash.fetch(:capability)
|
47
|
-
end
|
48
|
-
|
49
|
-
# @!attribute [r] client_id
|
50
|
-
# @return [String] Optional client ID assigned to this token
|
51
|
-
def client_id
|
52
|
-
hash[:client_id]
|
53
|
-
end
|
54
|
-
|
55
|
-
# @!attribute [r] nonce
|
56
|
-
# @return [String] unique nonce used to generate Token and ensure token generation cannot be replayed
|
57
|
-
def nonce
|
58
|
-
hash.fetch(:nonce)
|
59
|
-
end
|
60
|
-
|
61
|
-
# Returns true if token is expired or about to expire
|
62
|
-
#
|
63
|
-
# @return [Boolean]
|
64
|
-
def expired?
|
65
|
-
expires_at < Time.now + TOKEN_EXPIRY_BUFFER
|
66
|
-
end
|
67
|
-
|
68
|
-
# @!attribute [r] hash
|
69
|
-
# @return [Hash] Access the token Hash object ruby'fied to use symbolized keys
|
70
|
-
def hash
|
71
|
-
@hash_object
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Ably::Models::Token do
|
4
|
-
subject { Ably::Models::Token }
|
5
|
-
|
6
|
-
it_behaves_like 'a model', with_simple_attributes: %w(id capability client_id nonce) do
|
7
|
-
let(:model_args) { [] }
|
8
|
-
end
|
9
|
-
|
10
|
-
context 'defaults' do
|
11
|
-
let(:one_hour) { 60 * 60 }
|
12
|
-
let(:all_capabilities) { { "*" => ["*"] } }
|
13
|
-
|
14
|
-
it 'should default TTL to 1 hour' do
|
15
|
-
expect(Ably::Models::Token::DEFAULTS[:ttl]).to eql(one_hour)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should default capability to all' do
|
19
|
-
expect(Ably::Models::Token::DEFAULTS[:capability]).to eql(all_capabilities)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should only have defaults for :ttl and :capability' do
|
23
|
-
expect(Ably::Models::Token::DEFAULTS.keys).to contain_exactly(:ttl, :capability)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
context 'attributes' do
|
28
|
-
let(:unique_value) { 'unique_value' }
|
29
|
-
|
30
|
-
context '#key_id' do
|
31
|
-
subject { Ably::Models::Token.new({ key: unique_value }) }
|
32
|
-
it 'retrieves attribute :key' do
|
33
|
-
expect(subject.key_id).to eql(unique_value)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
{ :issued_at => :issued_at, :expires_at => :expires }.each do |method_name, attribute|
|
38
|
-
let(:time) { Time.now }
|
39
|
-
context "##{method_name}" do
|
40
|
-
subject { Ably::Models::Token.new({ attribute.to_sym => time.to_i }) }
|
41
|
-
|
42
|
-
it "retrieves attribute :#{attribute} as Time" do
|
43
|
-
expect(subject.public_send(method_name)).to be_a(Time)
|
44
|
-
expect(subject.public_send(method_name).to_i).to eql(time.to_i)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context '#expired?' do
|
50
|
-
let(:expire_time) { Time.now + Ably::Models::Token::TOKEN_EXPIRY_BUFFER }
|
51
|
-
|
52
|
-
context 'once grace period buffer has passed' do
|
53
|
-
subject { Ably::Models::Token.new(expires: expire_time - 1) }
|
54
|
-
|
55
|
-
it 'is true' do
|
56
|
-
expect(subject.expired?).to eql(true)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'within grace period buffer' do
|
61
|
-
subject { Ably::Models::Token.new(expires: expire_time + 1) }
|
62
|
-
|
63
|
-
it 'is false' do
|
64
|
-
expect(subject.expired?).to eql(false)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context '==' do
|
71
|
-
let(:token_attributes) { { id: 'unique' } }
|
72
|
-
|
73
|
-
it 'is true when attributes are the same' do
|
74
|
-
new_token = -> { Ably::Models::Token.new(token_attributes) }
|
75
|
-
expect(new_token[]).to eq(new_token[])
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'is false when attributes are not the same' do
|
79
|
-
expect(Ably::Models::Token.new(id: 1)).to_not eq(Ably::Models::Token.new(id: 2))
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'is false when class type differs' do
|
83
|
-
expect(Ably::Models::Token.new(id: 1)).to_not eq(nil)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|