ably 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ea2c608bdda1c7910a086adf11b7d32854df487c
4
- data.tar.gz: d490375a690b51efbe14ebc765ec7786b114a658
3
+ metadata.gz: b13770cd1f3131e42728090c7f7e7b28b56d02be
4
+ data.tar.gz: fe42558802cdccd07138ea9ce370e53091336988
5
5
  SHA512:
6
- metadata.gz: 7d3801488036052b450c6e81cc824e5c223432c697642e3aebe0d8f27c77c2eb1784d84693b5d232110dc9080bd285b6f828094bb383e88d436069922b264bc3
7
- data.tar.gz: 272c272b9beb386d6ae7ca33fd8ee4868cd7ff4d4e0fdd8951a5df65df3af465d586fd5a79325e509b49b7e17f88ca1ce9a5e757f06d976449fd322ecda88912
6
+ metadata.gz: 8795d186ce87c181ac86919760afc845ff49531e2946554b39ca30b8057a82018f57c59d0b22cf7f66270734b83e5adc8c9b8ed1dffb2ec9aee58a78c45f6eed
7
+ data.tar.gz: 46837150a1ae0f22675d25656772cb50f08e34b9cbd0d472f0a2ff12c069fe2d7229ac45f1f6b900dd78e08d384716dba3da3ba0f5fd7fd0bff688c60a9fdeca
@@ -1,4 +1,4 @@
1
- %w(modules models).each do |namespace|
1
+ %w(modules models util).each do |namespace|
2
2
  Dir.glob(File.expand_path("ably/#{namespace}/*.rb", File.dirname(__FILE__))).each do |file|
3
3
  require file
4
4
  end
@@ -34,5 +34,8 @@ module Ably
34
34
 
35
35
  # The token is invalid
36
36
  class InvalidToken < InvalidRequest; end
37
+
38
+ # Encryption or decryption related failures
39
+ class EncryptionError < StandardError; end
37
40
  end
38
41
  end
@@ -1,4 +1,5 @@
1
1
  module Ably
2
+ # Authentication token issued by Ably in response to an token request
2
3
  class Token
3
4
  include Ably::Modules::Conversions
4
5
 
@@ -7,32 +8,52 @@ module Ably
7
8
  ttl: 60 * 60 # 1 hour
8
9
  }
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
10
13
  TOKEN_EXPIRY_BUFFER = 5
11
14
 
12
15
  def initialize(attributes)
13
16
  @attributes = attributes.clone.freeze
14
17
  end
15
18
 
19
+ # Unique token ID used to authenticate requests
20
+ #
21
+ # @return [String]
16
22
  def id
17
23
  attributes.fetch(:id)
18
24
  end
19
25
 
26
+ # Key ID used to create this token
27
+ #
28
+ # @return [String]
20
29
  def key_id
21
30
  attributes.fetch(:key)
22
31
  end
23
32
 
33
+ # Time the token was issued
34
+ #
35
+ # @return [Time]
24
36
  def issued_at
25
37
  as_time_from_epoch(attributes.fetch(:issued_at), granularity: :s)
26
38
  end
27
39
 
40
+ # Time the token expires
41
+ #
42
+ # @return [Time]
28
43
  def expires_at
29
44
  as_time_from_epoch(attributes.fetch(:expires), granularity: :s)
30
45
  end
31
46
 
47
+ # Capabilities assigned to this token
48
+ #
49
+ # @return [Hash]
32
50
  def capability
33
51
  attributes.fetch(:capability)
34
52
  end
35
53
 
54
+ # Optioanl client ID assigned to this token
55
+ #
56
+ # @return [String]
36
57
  def client_id
37
58
  attributes.fetch(:client_id)
38
59
  end
@@ -47,6 +68,8 @@ module Ably
47
68
  end
48
69
 
49
70
  # Returns true if token is expired or about to expire
71
+ #
72
+ # @return [Boolean]
50
73
  def expired?
51
74
  expires_at < Time.now + TOKEN_EXPIRY_BUFFER
52
75
  end
@@ -0,0 +1,77 @@
1
+ require 'msgpack'
2
+ require 'openssl'
3
+
4
+ module Ably::Util
5
+ class Crypto
6
+ DEFAULTS = {
7
+ algorithm: 'AES',
8
+ mode: 'CBC',
9
+ key_length: 128,
10
+ block_length: 16
11
+ }
12
+
13
+ attr_reader :options
14
+
15
+ def initialize(options = {})
16
+ raise ArgumentError, ":secret is required" unless options.has_key?(:secret)
17
+ @options = DEFAULTS.merge(options).freeze
18
+ end
19
+
20
+ def encrypt(payload)
21
+ cipher = openssl_cipher
22
+ cipher.encrypt
23
+ cipher.key = secret
24
+ iv = cipher.random_iv
25
+ cipher.iv = iv
26
+
27
+ iv << cipher.update(pack(payload)) << cipher.final
28
+ end
29
+
30
+ def decrypt(encrypted_payload_with_iv)
31
+ raise Ably::Exceptions::EncryptionError, "iv is missing" unless encrypted_payload_with_iv.length >= block_length*2
32
+
33
+ iv = encrypted_payload_with_iv.slice(0..15)
34
+ encrypted_payload = encrypted_payload_with_iv.slice(16..-1)
35
+
36
+ decipher = openssl_cipher
37
+ decipher.decrypt
38
+ decipher.key = secret
39
+ decipher.iv = iv
40
+
41
+ unpack(decipher.update(encrypted_payload) << decipher.final)
42
+ end
43
+
44
+ def random_key
45
+ openssl_cipher.random_key
46
+ end
47
+
48
+ def random_iv
49
+ openssl_cipher.random_iv
50
+ end
51
+
52
+ private
53
+ def pack(object)
54
+ object.to_msgpack
55
+ end
56
+
57
+ def unpack(msgpack_binary)
58
+ MessagePack.unpack(msgpack_binary)
59
+ end
60
+
61
+ def secret
62
+ options[:secret]
63
+ end
64
+
65
+ def block_length
66
+ options[:block_length]
67
+ end
68
+
69
+ def cipher_type
70
+ "#{options[:algorithm]}-#{options[:key_length]}-#{options[:mode]}"
71
+ end
72
+
73
+ def openssl_cipher
74
+ OpenSSL::Cipher.new(cipher_type)
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module Ably
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Util::Crypto do
4
+ let(:secret) { SecureRandom.hex }
5
+ subject { Ably::Util::Crypto.new(secret: secret) }
6
+
7
+ context 'encrypts & decrypt' do
8
+ let(:string) { SecureRandom.hex }
9
+ let(:int) { SecureRandom.random_number(1_000_000_000) }
10
+ let(:float) { SecureRandom.random_number(1_000_000_000) * 0.1 }
11
+ let(:int64) { 15241578750190521 }
12
+ let(:hash) do
13
+ {
14
+ 10 => nil,
15
+ 'string' => 1,
16
+ 'float' => 1.2
17
+ }
18
+ end
19
+ let(:array) { [string, int, float, int64, hash] }
20
+ let(:boolean) { true }
21
+ let(:nil) { nil }
22
+
23
+ specify 'a string' do
24
+ encrypted = subject.encrypt(string)
25
+ expect(subject.decrypt(encrypted)).to eql(string)
26
+ end
27
+
28
+ specify 'a int' do
29
+ encrypted = subject.encrypt(int)
30
+ expect(subject.decrypt(encrypted)).to eql(int)
31
+ end
32
+
33
+ specify 'a int64' do
34
+ encrypted = subject.encrypt(int64)
35
+ expect(subject.decrypt(encrypted)).to eql(int64)
36
+ end
37
+
38
+ specify 'a float' do
39
+ encrypted = subject.encrypt(float)
40
+ expect(subject.decrypt(encrypted)).to eql(float)
41
+ end
42
+
43
+ specify 'a hash' do
44
+ encrypted = subject.encrypt(hash)
45
+ expect(subject.decrypt(encrypted)).to eql(hash)
46
+ end
47
+
48
+ specify 'an array' do
49
+ encrypted = subject.encrypt(array)
50
+ expect(subject.decrypt(encrypted)).to eql(array)
51
+ end
52
+
53
+ specify 'a boolean' do
54
+ encrypted = subject.encrypt(boolean)
55
+ expect(subject.decrypt(encrypted)).to eql(boolean)
56
+ end
57
+
58
+ specify 'a nil object' do
59
+ encrypted = subject.encrypt(nil)
60
+ expect(subject.decrypt(encrypted)).to eql(nil)
61
+ end
62
+ end
63
+ end
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.1.3
4
+ version: 0.1.4
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: 2014-09-26 00:00:00.000000000 Z
12
+ date: 2014-09-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -192,7 +192,9 @@ files:
192
192
  - lib/ably/rest/models/presence_message.rb
193
193
  - lib/ably/rest/presence.rb
194
194
  - lib/ably/token.rb
195
+ - lib/ably/util/crypto.rb
195
196
  - lib/ably/version.rb
197
+ - spec/acceptance/crypto.rb
196
198
  - spec/acceptance/realtime/channel_spec.rb
197
199
  - spec/acceptance/rest/auth_spec.rb
198
200
  - spec/acceptance/rest/base_spec.rb
@@ -242,6 +244,7 @@ signing_key:
242
244
  specification_version: 4
243
245
  summary: A Ruby client library for ably.io, the real-time messaging service
244
246
  test_files:
247
+ - spec/acceptance/crypto.rb
245
248
  - spec/acceptance/realtime/channel_spec.rb
246
249
  - spec/acceptance/rest/auth_spec.rb
247
250
  - spec/acceptance/rest/base_spec.rb