ably 0.1.3 → 0.1.4

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 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