block_io 0.1.3 → 1.0.1

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: d9263fda276a28feff2c874cbe26f0e305529a2d
4
- data.tar.gz: 575708414988f13c9648fc9a9e958ef7d8929b3f
3
+ metadata.gz: 0a5c7f9ebfcf7f608010b2f742ebe7e2c44035ab
4
+ data.tar.gz: 29253bde1cdcf14f17c7000165ea00571936fef7
5
5
  SHA512:
6
- metadata.gz: 635caea39d5a340b3d540e113f358e3c0dc4a5fa15221393f929b8fbeeeed0ff24a3c979d8cb57db8408f291acbaa0021edee33bdc6903084351d8c8378d48bf
7
- data.tar.gz: 18d56b62b86b3d64590540f2e06e37a49a4d5c6d1cde441095e1c2783d38ff424a41d9e80583501342d35ced69301cf5943cc5ac37c28bcaefbc8f91e2db2fd9
6
+ metadata.gz: d999194b92fe5b45ba67ebb21a422f4e1796ffaadfe5a6bb57c0735486e9150339cc0c8638f1577e68fe1392047ba3e8773abea859d7ab26fc12574ca5dc655e
7
+ data.tar.gz: 0332287b974c9bab30ed52f59031d0508b1e410be694c1bcb9b5363e459b1efbf74ebcd59443146f9f35bf8a7b38816926f68753532e26801340177afe9d3565
data/README.md CHANGED
@@ -17,6 +17,8 @@ Or install it yourself as:
17
17
  $ gem install block_io
18
18
 
19
19
  ## Changelog
20
+
21
+ *09/27/14*: Now supporting client-side signatures. API v2 recommended.
20
22
 
21
23
  *07/01/14*: Forcing TLSv1 usage since Block.io does not support SSLv3 due to its vulnerable nature. Fixed:
22
24
  HTTPClient.new.ssl_config.ssl_version = :TLSv1
@@ -27,18 +29,18 @@ Or install it yourself as:
27
29
  It's super easy to get started. In your Ruby shell ($ irb), for example, do this:
28
30
 
29
31
  require 'block_io'
30
- BlockIo.set_options :api_key => 'API KEY', :pin => 'SECRET PIN'
32
+ BlockIo.set_options :api_key => 'API KEY', :pin => 'SECRET PIN', :version => 2
31
33
 
32
34
  And you're good to go:
33
35
 
34
36
  BlockIo.get_new_address
35
37
  BlockIo.get_my_addresses
36
38
 
37
- For more information, see https://block.io/api
39
+ For more information, see https://block.io/api/simple/ruby
38
40
 
39
41
  ## Contributing
40
42
 
41
- 1. Fork it ( https://github.com/[my-github-username]/block_io/fork )
43
+ 1. Fork it ( https://github.com/BlockIo/gem-block-io/fork )
42
44
  2. Create your feature branch (`git checkout -b my-new-feature`)
43
45
  3. Commit your changes (`git commit -am 'Add some feature'`)
44
46
  4. Push to the branch (`git push origin my-new-feature`)
data/block_io.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["a@block.io"]
11
11
  spec.summary = %q{An easy to use Dogecoin, Bitcoin, Litecoin wallet API by Block.io. Sign up required at Block.io.}
12
12
  spec.description = %q{This Ruby Gem is the official reference client for the Block.io payments API. To use this, you will need the Dogecoin, Bitcoin, or Litecoin API key(s) from Block.io. Go ahead, sign up :)}
13
- spec.homepage = "https://block.io/api/ruby"
13
+ spec.homepage = "https://block.io/api/simple/ruby"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.6"
22
22
  spec.add_development_dependency "rake", "~> 0"
23
+ spec.add_runtime_dependency "ecdsa", "~> 1.2", '>= 1.2.0'
23
24
  spec.add_runtime_dependency "httpclient", "~> 2.4", '>= 2.4.0'
24
25
  spec.add_runtime_dependency "json", "~> 1.8", '>= 1.8.1'
25
26
  spec.add_runtime_dependency "connection_pool", "~> 2.0", '>= 2.0.0'
data/examples/basic.rb ADDED
@@ -0,0 +1,22 @@
1
+ # creates a new destination address, withdraws from the default label to it, gets sent transactions, and the current price
2
+
3
+ require 'block_io'
4
+
5
+ # please use the Dogecoin Testnet API key here
6
+ puts BlockIo.set_options :api_key => 'YOURDOGECOINTESTNETAPIKEY', :pin => 'YOURSECRETPIN', :version => 2
7
+
8
+ begin
9
+ puts BlockIo.get_new_address(:label => 'testDest')
10
+ rescue Exception => e
11
+ # if this failed, we probably created testDest label before
12
+ puts e.to_s
13
+ end
14
+
15
+ puts BlockIo.withdraw_from_labels(:from_labels => 'default', :to_label => 'testDest', :amount => '3.5')
16
+
17
+ puts BlockIo.get_address_by_label(:label => 'default')
18
+
19
+ puts BlockIo.get_transactions(:type => 'sent') # API v2 only
20
+
21
+ puts BlockIo.get_current_price(:base_price => 'BTC')
22
+
@@ -0,0 +1,89 @@
1
+ # creates a new destination address, withdraws from the default label to it, gets sent transactions, and the current price
2
+
3
+ require 'block_io'
4
+
5
+ # please use the Dogecoin Testnet API key here
6
+ puts "*** Initialize BlockIo library: "
7
+ puts JSON.pretty_generate(BlockIo.set_options :api_key => 'YourDogecoinTestnetAPIKey', :pin => 'YourSecretPIN', :version => 2)
8
+
9
+
10
+ # create 4 keys
11
+ keys = [ BlockIo::Key.from_passphrase('alpha1alpha2alpha3alpha4'), BlockIo::Key.from_passphrase('alpha4alpha1alpha2alpha3'), BlockIo::Key.from_passphrase('alpha3alpha4alpha1alpha2'), BlockIo::Key.from_passphrase('alpha2alpha3alpha4alpha1') ]
12
+
13
+ dtrust_address = nil
14
+
15
+ begin
16
+ # let's create a new address with all 4 keys as signers, but only 3 signers required (i.e., 4 of 5 multisig, with 1 signature being Block.io)
17
+
18
+ signers = ""
19
+ keys.each { |key| signers += ',' if signers.length > 0; signers += key.public_key; }
20
+
21
+ response = BlockIo.get_new_dtrust_address(:label => 'dTrust1', :public_keys => signers, :required_signatures => 3)
22
+
23
+ dtrust_address = response['data']['address']
24
+ rescue Exception => e
25
+ # if this failed, we probably created the same label before. let's fetch the address then.
26
+ puts e.to_s
27
+
28
+ response = BlockIo.get_dtrust_address_by_label(:label => 'dTrust1')
29
+
30
+ dtrust_address = response['data']['address']
31
+ end
32
+
33
+ puts "*** Our dTrust Address: #{dtrust_address}"
34
+
35
+ # let's deposit some coins into this new address
36
+ response = BlockIo.withdraw_from_labels(:from_labels => 'default', :to_address => dtrust_address, :amount => '3.5')
37
+
38
+ puts "*** Withdrawal response:"
39
+ puts JSON.pretty_generate(response)
40
+
41
+
42
+ # fetch the dtrust address' balance
43
+ puts "*** dTrust1 Balance:"
44
+ puts JSON.pretty_generate(BlockIo.get_dtrust_address_balance(:label => 'dTrust1'))
45
+
46
+ # withdraw a few coins from dtrust1 to the default label
47
+ normal_address = BlockIo.get_address_by_label(:label => 'default')['data']['address']
48
+
49
+ puts "*** Withdrawing from dTrust1 to the 'default' label in normal multisig"
50
+
51
+ response = BlockIo.withdraw_from_dtrust_address(:from_labels => 'dTrust1', :to_addresses => normal_address, :amounts => '2.1')
52
+
53
+ puts JSON.pretty_generate(response)
54
+
55
+ # let's sign for the public keys specified
56
+
57
+ response['data']['inputs'].each do |input|
58
+ # for each input
59
+
60
+ data_to_sign = input['data_to_sign']
61
+
62
+ input['signers'].each do |signer|
63
+
64
+ # figure out if we have the public key that matches this signer
65
+
66
+ keys.each do |key|
67
+ # iterate over all keys till we've found the one that we need
68
+
69
+ signer['signed_data'] = key.sign(data_to_sign) if key.public_key == signer['signer_public_key']
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ puts "*** Our signed response: "
78
+ puts JSON.pretty_generate(response['data']) #.to_json
79
+
80
+ # let's final the withdrawal
81
+ puts "*** Finalize withdrawal: "
82
+ puts JSON.pretty_generate(BlockIo.sign_and_finalize_withdrawal(:signature_data => response['data'].to_json))
83
+
84
+ # get the sent transactions for this dTrust address
85
+
86
+ puts "*** Get transactions sent by our dTrust1 address: "
87
+
88
+ puts JSON.pretty_generate(BlockIo.get_dtrust_transactions(:type => 'sent', :labels => 'dTrust1'))
89
+
data/lib/block_io.rb CHANGED
@@ -1,204 +1,245 @@
1
- require "block_io/version"
1
+ require 'block_io/version'
2
2
  require 'httpclient'
3
3
  require 'json'
4
4
  require 'connection_pool'
5
+ require 'ecdsa'
6
+ require 'openssl'
7
+ require 'digest'
8
+ require 'securerandom'
9
+ require 'base64'
5
10
 
6
11
  module BlockIo
7
12
 
8
13
  @api_key = nil
9
- @base_url = "https://block.io/api/v1/API_CALL/?api_key="
14
+ @base_url = "https://block.io/api/VERSION/API_CALL/?api_key="
10
15
  @pin = nil
16
+ @encryptionKey = nil
11
17
  @conn_pool = nil
18
+ @version = nil
12
19
 
13
20
  def self.set_options(args = {})
14
21
  # initialize BlockIo
15
22
  @api_key = args[:api_key]
16
23
  @pin = args[:pin]
17
- @conn_pool = ConnectionPool.new(size: 5, timeout: 300) { HTTPClient.new }
24
+ @encryptionKey = Helper.pinToAesKey(@pin) if !@pin.nil?
18
25
 
26
+ @conn_pool = ConnectionPool.new(size: 5, timeout: 300) { HTTPClient.new }
27
+
28
+ @version = args[:version] || 2 # default version is 2
29
+
19
30
  self.api_call(['get_balance',""])
20
31
  end
21
32
 
22
- def self.get_offline_vault_balance
23
- # returns the offline vault's balance
24
- endpoint = ["get_offline_vault_balance",""]
25
- self.api_call(endpoint)
26
- end
27
-
28
- def self.get_offline_vault_address
29
- # returns the offline vault's address and balance info
30
- self.get_offline_vault_balance
31
- end
32
-
33
- def self.get_balance
34
- # returns the balances for your account tied to the API key
35
- endpoint = ["get_balance", ""]
36
- self.api_call(endpoint)
37
- end
38
-
39
- def self.get_user_balance(args)
40
- # returns the specified user's balance
41
-
42
- user_id = args[:user_id]
33
+ def self.method_missing(m, *args, &block)
43
34
 
44
- raise Exception.new("Must provide user_id") if user_id.nil?
35
+ method_name = m.to_s
45
36
 
46
- endpoint = ['get_user_balance',"&user_id=#{user_id}"]
37
+ if ['withdraw', 'withdraw_from_address', 'withdraw_from_addresses', 'withdraw_from_user', 'withdraw_from_users', 'withdraw_from_label', 'withdraw_from_labels'].include?(m.to_s) then
47
38
 
48
- self.api_call(endpoint)
49
- end
39
+ self.withdraw(args.first, m.to_s)
50
40
 
51
- def self.get_address_balance(args)
52
- # returns the specified address or address_label's balance
41
+ else
42
+ params = get_params(args.first)
43
+ self.api_call([method_name, params])
44
+ end
53
45
 
54
- address = args[:address]
55
- address_label = args[:address_label]
56
-
57
- raise Exception.new("Must provide ONE of address or address_label") if (!address.nil? and !address_label.nil?) or (address.nil? and address_label.nil?)
58
-
59
- endpoint = ['get_address_balance',"&address=#{address}"] unless address.nil?
60
- endpoint = ['get_address_balance',"&address_label=#{address_label}"] unless address_label.nil?
46
+ end
61
47
 
62
- self.api_call(endpoint)
63
- end
64
-
65
- def self.get_current_price(args = {})
66
- # returns prices from different exchanges as an array of hashes
67
- price_base = args[:price_base]
68
-
69
- endpoint = ['get_current_price', '']
70
- endpoint = ['get_current_price',"&price_base=#{price_base}"] unless price_base.nil? or price_base.to_s.length == 0
48
+ def self.withdraw(args = {}, method_name = 'withdraw')
49
+ # validate arguments for withdrawal of funds TODO
71
50
 
72
- self.api_call(endpoint)
73
- end
51
+ raise Exception.new("PIN not set. Use BlockIo.set_options(:api_key=>'API KEY',:pin=>'SECRET PIN',:version=>'API VERSION')") if @pin.nil?
74
52
 
75
- def self.withdraw_from_user(args = {})
76
- # withdraws coins from the given user(s)
77
- self.withdraw(args)
78
- end
53
+ params = get_params(args)
79
54
 
80
- def self.withdraw(args = {})
81
- # validate arguments for withdrawal of funds TODO
55
+ params += "&pin=#{@pin}" if @version == 1 # Block.io handles the Secret PIN in the legacy API (v1)
82
56
 
83
- raise Exception.new("PIN not set. Use BlockIo.set_options(:api_key=>'API KEY',:pin=>'SECRET PIN')") if @pin.nil?
57
+ response = self.api_call([method_name, params])
58
+
59
+ if response['data'].has_key?('reference_id') then
60
+ # Block.io's asking us to provide some client-side signatures, let's get to it
84
61
 
85
- # validate argument sets
86
- amount = args[:amount]
87
- to_user_id = args[:to_user_id]
88
- payment_address = args[:payment_address]
89
- from_user_ids = args[:from_user_ids] || args[:from_user_id]
62
+ # extract the passphrase
63
+ encrypted_passphrase = response['data']['encrypted_passphrase']['passphrase']
90
64
 
91
- raise Exception.new("Must provide ONE of payment_address, or to_user_id") if (!to_user_id.nil? and !payment_address.nil?) or (to_user_id.nil? and payment_address.nil?)
92
- raise Exception.new("Must provide amount to withdraw") if amount.nil?
65
+ # let's get our private key
66
+ key = Helper.extractKey(encrypted_passphrase, @encryptionKey)
93
67
 
94
- endpoint = ['withdraw',"&amount=#{amount}&payment_address=#{payment_address}&pin=#{@pin}"] unless payment_address.nil?
95
- endpoint = ['withdraw',"&amount=#{amount}&to_user_id=#{to_user_id}&pin=#{@pin}"] unless to_user_id.nil?
96
- endpoint = ['withdraw',"&amount=#{amount}&from_user_ids=#{from_user_ids}&pin=#{@pin}&payment_address=#{payment_address}"] unless from_user_ids.nil? or payment_address.nil?
97
- endpoint = ['withdraw',"&amount=#{amount}&from_user_ids=#{from_user_ids}&to_user_id=#{to_user_id}&pin=#{@pin}"] unless to_user_id.nil? or from_user_ids.nil?
68
+ raise Exception.new('Public key mismatch for requested signer and ourselves. Invalid Secret PIN detected.') if key.public_key != response['data']['encrypted_passphrase']['signer_public_key']
98
69
 
99
- self.api_call(endpoint)
100
- end
70
+ # let's sign all the inputs we can
71
+ inputs = response['data']['inputs']
101
72
 
102
- def self.get_new_address(args = {})
103
- # validate arguments for getting a new address
104
- address_label = args[:address_label]
73
+ inputs.each do |input|
74
+ # iterate over all signers
75
+
76
+ input['signers'].each do |signer|
77
+ # if our public key matches this signer's public key, sign the data
105
78
 
106
- endpoint = ['get_new_address','']
107
- endpoint = ["get_new_address","&address_label=#{address_label}"] unless address_label.nil?
79
+ signer['signed_data'] = key.sign(input['data_to_sign']) if signer['signer_public_key'] == key.public_key
108
80
 
109
- self.api_call(endpoint)
110
- end
81
+ end
82
+
83
+ end
111
84
 
112
- def self.create_user(args = {})
113
- # validate arguments for getting a new address
114
- address_label = args[:address_label]
85
+ # the response object is now signed, let's stringify it and finalize this withdrawal
115
86
 
116
- endpoint = ['create_user','']
117
- endpoint = ['create_user',"&address_label=#{address_label}"] unless address_label.nil?
87
+ response = self.api_call(['sign_and_finalize_withdrawal',{:signature_data => response['data'].to_json}])
118
88
 
119
- self.api_call(endpoint)
120
- end
89
+ # if we provided all the required signatures, this transaction went through
90
+ # otherwise Block.io responded with data asking for more signatures
91
+ # the latter will be the case for dTrust addresses
92
+ end
121
93
 
122
- def self.get_my_addresses(args = {})
123
- # returns all the addresses in your account tied to the API key
124
- endpoint = ["get_my_addresses",""]
94
+ return response
125
95
 
126
- self.api_call(endpoint)
127
96
  end
128
97
 
129
- def self.get_users(args = {})
130
- # returns all the addresses in your account tied to the API key
131
- endpoint = ['get_users',""]
132
-
133
- self.api_call(endpoint)
134
- end
135
98
 
136
- def self.get_address_received(args = {})
137
- # get coins received, confirmed and unconfirmed, by the given address, address_label, or user_id
138
- address_label = args[:address_label]
139
- user_id = args[:user_id]
140
- address = args[:address]
99
+ private
100
+
101
+ def self.api_call(endpoint)
141
102
 
142
- raise Exception.new("Must provide ONE of address_label, user_id, or address") unless args.keys.length == 1 and (!address_label.nil? or !user_id.nil? or !address.nil?)
103
+ body = nil
143
104
 
144
- endpoint = ['get_address_received','']
145
- endpoint = ["get_address_received","&user_id=#{user_id}"] unless user_id.nil?
146
- endpoint = ['get_address_received',"&address_label=#{address_label}"] unless address_label.nil?
147
- endpoint = ['get_address_received',"&address=#{address}"] unless address.nil?
105
+ @conn_pool.with do |hc|
106
+ # prevent initiation of HTTPClients every time we make this call, use a connection_pool
148
107
 
149
- self.api_call(endpoint)
108
+ hc.ssl_config.ssl_version = :TLSv1
109
+ response = hc.post("#{@base_url.gsub('API_CALL',endpoint[0]).gsub('VERSION', 'v'+@version.to_s) + @api_key}", endpoint[1])
110
+
111
+ begin
112
+ body = JSON.parse(response.body)
113
+ raise Exception.new(body['data']['error_message']) if !body['status'].eql?('success')
114
+ rescue
115
+ raise Exception.new('Unknown error occurred. Please report this.')
116
+ end
117
+ end
118
+
119
+ body
150
120
  end
151
121
 
152
- def self.get_user_received(args = {})
153
- # returns the user's received coins, confirmed and unconfirmed
154
-
155
- user_id = args[:user_id]
122
+ private
156
123
 
157
- raise Exception.new("Must provide user_id") if user_id.nil?
124
+ def self.get_params(args)
125
+ # construct the parameter string
126
+ params = ""
127
+
128
+ args.each do |k,v|
129
+ params += '&' if params.length > 0
130
+ params += "#{k.to_s}=#{v.to_s}"
131
+ end
158
132
 
159
- self.get_address_received(:user_id => user_id)
133
+ return params
160
134
  end
161
135
 
162
- def self.get_address_by_label(args = {})
163
- # get address by label
164
-
165
- address_label = args[:address_label]
166
-
167
- raise Exception.new("Must provide address_label") if address_label.nil?
168
-
169
- endpoint = ["get_address_by_label","&address_label=#{address_label}"]
136
+ public
170
137
 
171
- self.api_call(endpoint)
172
- end
173
-
174
- def self.get_user_address(args = {})
175
- # gets the user's address
138
+ class Key
176
139
 
177
- user_id = args[:user_id]
140
+ def initialize(privkey = nil)
141
+ # the privkey must be in hex if at all provided
178
142
 
179
- raise Exception.new("Must provide user_id") if user_id.nil?
143
+ @group = ECDSA::Group::Secp256k1
144
+ @private_key = privkey.to_i(16) || 1 + SecureRandom.random_number(group.order - 1)
145
+ @public_key = @group.generator.multiply_by_scalar(@private_key)
180
146
 
181
- endpoint = ['get_user_address',"&user_id=#{user_id}"]
147
+ end
148
+
149
+ def private_key
150
+ # returns private key in hex form
151
+ return @private_key.to_s(16)
152
+ end
153
+
154
+ def public_key
155
+ # returns the compressed form of the public key to save network fees (shorter scripts)
182
156
 
183
- self.api_call(endpoint)
184
- end
157
+ return ECDSA::Format::PointOctetString.encode(@public_key, compression: true).unpack("H*")[0]
158
+ end
159
+
160
+ def sign(data)
161
+ # signed the given hexadecimal string
185
162
 
186
- private
163
+ nonce = 1 + SecureRandom.random_number(@group.order - 1) # nonce, can be made deterministic TODO
164
+
165
+ signature = ECDSA.sign(@group, @private_key, [data].pack("H*"), nonce)
187
166
 
188
- def self.api_call(endpoint)
167
+ # DER encode this, and return it in hex form
189
168
 
190
- body = nil
169
+ return ECDSA::Format::SignatureDerString.encode(signature).unpack("H*")[0]
191
170
 
192
- @conn_pool.with do |hc|
193
- # prevent initiation of HTTPClients every time we make this call, use a connection_pool
171
+ end
172
+
173
+ def self.from_passphrase(passphrase)
174
+ # create a private+public key pair from a given passphrase
175
+ # think of this as your brain wallet. be very sure to use a sufficiently long passphrase
176
+ # if you don't want a passphrase, just use Key.new and it will generate a random key for you
177
+
178
+ raise Exception.new('Must provide passphrase at least 8 characters long.') if passphrase.nil? or passphrase.length < 8
179
+
180
+ hashed_key = Helper.sha256([passphrase].pack("H*")) # must pass bytes to sha256
194
181
 
195
- hc.ssl_config.ssl_version = :TLSv1
196
- response = hc.get("#{@base_url.gsub('API_CALL',endpoint[0]) + @api_key + endpoint[1]}")
197
- body = JSON.parse(response.body)
182
+ return Key.new(hashed_key)
183
+ end
184
+
185
+ end
186
+
187
+ module Helper
188
+
189
+ def self.extractKey(encrypted_data, b64_enc_key)
190
+ # passphrase is in plain text
191
+ # encrypted_data is in base64, as it was stored on Block.io
192
+ # returns the private key extracted from the given encrypted data
198
193
 
194
+ decrypted = self.decrypt(encrypted_data, b64_enc_key)
195
+
196
+ return Key.from_passphrase(decrypted)
199
197
  end
200
198
 
201
- body
199
+ def self.sha256(value)
200
+ # returns the hex of the hash of the given value
201
+ hash = Digest::SHA2.new(256)
202
+ hash << value
203
+ hash.hexdigest # return hex
204
+ end
205
+
206
+ def self.pinToAesKey(secret_pin, iterations = 2048)
207
+ # converts the pincode string to PBKDF2
208
+ # returns a base64 version of PBKDF2 pincode
209
+ salt = ""
210
+ aes_key_bin = OpenSSL::PKCS5.pbkdf2_hmac(secret_pin, salt, iterations/2, 16, OpenSSL::Digest::SHA256.new)
211
+ aes_key_bin = OpenSSL::PKCS5.pbkdf2_hmac(aes_key_bin.unpack("H*")[0], salt, iterations/2, 32, OpenSSL::Digest::SHA256.new)
212
+
213
+ return Base64.strict_encode64(aes_key_bin) # the base64 encryption key
214
+ end
215
+
216
+ # Decrypts a block of data (encrypted_data) given an encryption key
217
+ def self.decrypt(encrypted_data, b64_enc_key, iv = nil, cipher_type = 'AES-256-ECB')
218
+
219
+ response = nil
220
+
221
+ begin
222
+ aes = OpenSSL::Cipher::Cipher.new(cipher_type)
223
+ aes.decrypt
224
+ aes.key = Base64.strict_decode64(b64_enc_key)
225
+ aes.iv = iv if iv != nil
226
+ response = aes.update(Base64.strict_decode64(encrypted_data)) + aes.final
227
+ rescue Exception => e
228
+ # decryption failed, must be an invalid Secret PIN
229
+ raise Exception.new('Invalid Secret PIN provided.')
230
+ end
231
+
232
+ return response
233
+ end
234
+
235
+ # Encrypts a block of data given an encryption key
236
+ def self.encrypt(data, b64_enc_key, iv = nil, cipher_type = 'AES-256-ECB')
237
+ aes = OpenSSL::Cipher::Cipher.new(cipher_type)
238
+ aes.encrypt
239
+ aes.key = Base64.strict_decode64(b64_enc_key)
240
+ aes.iv = iv if iv != nil
241
+ Base64.strict_encode64(aes.update(data) + aes.final)
242
+ end
202
243
  end
203
244
 
204
245
  end
@@ -1,3 +1,3 @@
1
1
  module BlockIo
2
- VERSION = "0.1.3"
2
+ VERSION = "1.0.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: block_io
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atif Nazir
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-01 00:00:00.000000000 Z
11
+ date: 2014-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,26 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ecdsa
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.2'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 1.2.0
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.2'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.2.0
41
61
  - !ruby/object:Gem::Dependency
42
62
  name: httpclient
43
63
  requirement: !ruby/object:Gem::Requirement
@@ -109,13 +129,14 @@ extra_rdoc_files: []
109
129
  files:
110
130
  - Gemfile
111
131
  - LICENSE
112
- - LICENSE.txt
113
132
  - README.md
114
133
  - Rakefile
115
134
  - block_io.gemspec
135
+ - examples/basic.rb
136
+ - examples/dtrust.rb
116
137
  - lib/block_io.rb
117
138
  - lib/block_io/version.rb
118
- homepage: https://block.io/api/ruby
139
+ homepage: https://block.io/api/simple/ruby
119
140
  licenses:
120
141
  - MIT
121
142
  metadata: {}
data/LICENSE.txt DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) 2014 Atif Nazir
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.