ci_block_io 1.7.0 → 1.7.1

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
  SHA256:
3
- metadata.gz: 2abd2718e9c87fb33dc7aaecc59c39b475fd2d99c04738fb1f9334bd3e40c861
4
- data.tar.gz: 47a1b5f23851a355378cd89f50e07ef2090585d60653037bee1fbcdf78619ddf
3
+ metadata.gz: 93926bfd4df14d9634d0ea789c86fdd7737e485f129a7b966b52ea110ab96d46
4
+ data.tar.gz: b605c6dc58f4f2eb583691767f1ee2a7c97b8a920675787e4fcc6b46785d5480
5
5
  SHA512:
6
- metadata.gz: ce7c50a375b4ec74ca6ff03714b23fe7cde4a30fb29739f392ecb8423345b989be3f08c7fc3cf552ed4bcb6269098b2b25f617e839b6504ef7d3bb98a8087174
7
- data.tar.gz: e764bb64d1b075e8df6f6a360e952b82d0cb58786a05e6bfe4660e57e080d8c3cae15264a2b5b32914c618a43d82451d7a332170d9f3e249f3790281809394ef
6
+ metadata.gz: a492c73929e34c787b4cb7d4773f3024a0ffbbf0984a49bbccbf3e9c6739697ff70ea1cd04fe6cc39e419c45e2cc56d02c650dc076898cda9ed8187192caa03b
7
+ data.tar.gz: 26e60257ab22e318649b2f741807b591e73e41c4ce377ab6802f83510777f4a92e41bd5af9354e7f61c295b052f188b3279bba309b18685294ea8c9e545dfddd
data/lib/ci_block_io.rb CHANGED
@@ -30,18 +30,18 @@ module CiBlockIo
30
30
  # initialize BlockIo
31
31
  @api_key = args[:api_key]
32
32
  @pin = args[:pin]
33
-
33
+
34
34
  @encryptionKey = Helper.pinToAesKey(@pin) if !@pin.nil?
35
35
 
36
36
  hostname = args[:hostname] || "block.io"
37
37
  @base_url = "https://" << hostname << "/api/VERSION/API_CALL/?api_key="
38
-
38
+
39
39
  @client = HTTPClient.new
40
40
  @client.tcp_keepalive = true
41
41
  @client.ssl_config.ssl_version = :auto
42
-
42
+
43
43
  @version = args[:version] || 2 # default version is 2
44
-
44
+
45
45
  self.api_call(['get_balance',""])
46
46
  end
47
47
 
@@ -59,7 +59,7 @@ module CiBlockIo
59
59
  params = get_params(args.first)
60
60
  self.api_call([method_name, params])
61
61
  end
62
-
62
+
63
63
  end
64
64
 
65
65
  def self.withdraw(args = {}, method_name = 'withdraw')
@@ -72,7 +72,7 @@ module CiBlockIo
72
72
  params << "&pin=" << @pin if @version == 1 # Block.io handles the Secret PIN in the legacy API (v1)
73
73
 
74
74
  response = self.api_call([method_name, params])
75
-
75
+
76
76
  if response['data'].has_key?('reference_id') then
77
77
  # Block.io's asking us to provide some client-side signatures, let's get to it
78
78
 
@@ -114,7 +114,7 @@ module CiBlockIo
114
114
  params = get_params(args)
115
115
 
116
116
  response = self.api_call([method_name, params])
117
-
117
+
118
118
  if response['data'].has_key?('reference_id') then
119
119
  # Block.io's asking us to provide some client-side signatures, let's get to it
120
120
 
@@ -136,7 +136,7 @@ module CiBlockIo
136
136
 
137
137
 
138
138
  private
139
-
139
+
140
140
  def self.api_call(endpoint)
141
141
  return @mock_response[endpoint[0]] if @mock_response.keys.include?(endpoint[0])
142
142
 
@@ -145,21 +145,19 @@ module CiBlockIo
145
145
  return nil if base_url.nil? || @api_key.nil?
146
146
 
147
147
  response = @client.post(base_url + @api_key, endpoint[1])
148
-
148
+
149
149
  begin
150
150
  body = Oj.load(response.body)
151
151
  return unless body['status'].eql?('success')
152
152
  case endpoint[0]
153
- when 'withdraw' then
153
+ when 'withdraw'
154
154
  raise CiBlockIoWithdrawException.new(body['data']['error_message'])
155
155
  else
156
156
  raise Exception.new(body['data']['error_message'])
157
157
  end
158
- end
159
158
  rescue
160
159
  raise Exception.new('Unknown error occurred. Please report this.')
161
160
  end
162
-
163
161
  body
164
162
  end
165
163
 
@@ -169,7 +167,7 @@ module CiBlockIo
169
167
  # construct the parameter string
170
168
  params = ""
171
169
  args = {} if args.nil?
172
-
170
+
173
171
  args.each do |k,v|
174
172
  params += '&' if params.length > 0
175
173
  params += "#{k.to_s}=#{v.to_s}"
@@ -191,23 +189,23 @@ module CiBlockIo
191
189
  @compressed = compressed
192
190
 
193
191
  end
194
-
192
+
195
193
  def private_key
196
194
  # returns private key in hex form
197
195
  return @private_key.to_s(16)
198
196
  end
199
-
197
+
200
198
  def public_key
201
199
  # returns the compressed form of the public key to save network fees (shorter scripts)
202
200
 
203
201
  return ECDSA::Format::PointOctetString.encode(@public_key, compression: @compressed).unpack("H*")[0]
204
202
  end
205
-
203
+
206
204
  def sign(data)
207
205
  # signed the given hexadecimal string
208
206
 
209
207
  nonce = deterministicGenerateK([data].pack("H*"), @private_key) # RFC6979
210
-
208
+
211
209
  signature = ECDSA.sign(@group, @private_key, data.to_i(16), nonce)
212
210
 
213
211
  # BIP0062 -- use lower S values only
@@ -221,14 +219,14 @@ module CiBlockIo
221
219
  # DER encode this, and return it in hex form
222
220
  return ECDSA::Format::SignatureDerString.encode(signature).unpack("H*")[0]
223
221
  end
224
-
222
+
225
223
  def self.from_passphrase(passphrase)
226
224
  # create a private+public key pair from a given passphrase
227
225
  # think of this as your brain wallet. be very sure to use a sufficiently long passphrase
228
226
  # if you don't want a passphrase, just use Key.new and it will generate a random key for you
229
-
227
+
230
228
  raise Exception.new('Must provide passphrase at least 8 characters long.') if passphrase.nil? or passphrase.length < 8
231
-
229
+
232
230
  hashed_key = Helper.sha256([passphrase].pack("H*")) # must pass bytes to sha256
233
231
 
234
232
  return Key.new(hashed_key)
@@ -246,65 +244,65 @@ module CiBlockIo
246
244
  return Key.new(actual_key, compressed)
247
245
 
248
246
  end
249
-
247
+
250
248
  def isPositive(i)
251
249
  sig = "!+-"[i <=> 0]
252
-
250
+
253
251
  return sig.eql?("+")
254
252
  end
255
-
253
+
256
254
  def deterministicGenerateK(data, privkey, group = ECDSA::Group::Secp256k1)
257
255
  # returns a deterministic K -- RFC6979
258
256
 
259
257
  hash = data.bytes.to_a
260
258
 
261
259
  x = [privkey.to_s(16)].pack("H*").bytes.to_a
262
-
260
+
263
261
  k = []
264
262
  32.times { k.insert(0, 0) }
265
-
263
+
266
264
  v = []
267
265
  32.times { v.insert(0, 1) }
268
-
266
+
269
267
  # step D
270
268
  k = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), k.pack("C*"), [].concat(v).concat([0]).concat(x).concat(hash).pack("C*")).bytes.to_a
271
-
269
+
272
270
  # step E
273
271
  v = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), k.pack("C*"), v.pack("C*")).bytes.to_a
274
-
272
+
275
273
  # puts "E: " + v.pack("C*").unpack("H*")[0]
276
-
274
+
277
275
  # step F
278
276
  k = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), k.pack("C*"), [].concat(v).concat([1]).concat(x).concat(hash).pack("C*")).bytes.to_a
279
-
277
+
280
278
  # step G
281
279
  v = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), k.pack("C*"), v.pack("C*")).bytes.to_a
282
-
280
+
283
281
  # step H2b (Step H1/H2a ignored)
284
282
  v = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), k.pack("C*"), v.pack("C*")).bytes.to_a
285
-
283
+
286
284
  h2b = v.pack("C*").unpack("H*")[0]
287
285
  tNum = h2b.to_i(16)
288
-
286
+
289
287
  # step H3
290
288
  while (!isPositive(tNum) or tNum >= group.order) do
291
289
  # k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0])]), k)
292
290
  k = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), k.pack("C*"), [].concat(v).concat([0]).pack("C*")).bytes.to_a
293
-
291
+
294
292
  # v = crypto.HmacSHA256(v, k)
295
293
  v = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), k.pack("C*"), v.pack("C*")).bytes.to_a
296
-
294
+
297
295
  # T = BigInteger.fromBuffer(v)
298
296
  tNum = v.pack("C*").unpack("H*")[0].to_i(16)
299
297
  end
300
-
298
+
301
299
  return tNum
302
300
  end
303
301
 
304
302
  end
305
-
303
+
306
304
  module Helper
307
-
305
+
308
306
  def self.signData(inputs, keys)
309
307
  # sign the given data with the given keys
310
308
  # TODO loop is O(n^3), make it better
@@ -320,7 +318,7 @@ module CiBlockIo
320
318
  while j < input['signers'].size do
321
319
  # if our public key matches this signer's public key, sign the data
322
320
  signer = inputs[i]['signers'][j]
323
-
321
+
324
322
  k = 0
325
323
  while k < keys.size do
326
324
  # sign for each key provided, if we can
@@ -342,19 +340,19 @@ module CiBlockIo
342
340
  # passphrase is in plain text
343
341
  # encrypted_data is in base64, as it was stored on Block.io
344
342
  # returns the private key extracted from the given encrypted data
345
-
343
+
346
344
  decrypted = self.decrypt(encrypted_data, b64_enc_key)
347
-
345
+
348
346
  return Key.from_passphrase(decrypted)
349
347
  end
350
-
348
+
351
349
  def self.sha256(value)
352
350
  # returns the hex of the hash of the given value
353
351
  hash = Digest::SHA2.new(256)
354
352
  hash << value
355
353
  hash.hexdigest # return hex
356
354
  end
357
-
355
+
358
356
  def self.pinToAesKey(secret_pin, iterations = 2048)
359
357
  # converts the pincode string to PBKDF2
360
358
  # returns a base64 version of PBKDF2 pincode
@@ -366,10 +364,10 @@ module CiBlockIo
366
364
 
367
365
  return Base64.strict_encode64(aes_key_bin) # the base64 encryption key
368
366
  end
369
-
367
+
370
368
  # Decrypts a block of data (encrypted_data) given an encryption key
371
369
  def self.decrypt(encrypted_data, b64_enc_key, iv = nil, cipher_type = 'AES-256-ECB')
372
-
370
+
373
371
  response = nil
374
372
 
375
373
  begin
@@ -385,7 +383,7 @@ module CiBlockIo
385
383
 
386
384
  return response
387
385
  end
388
-
386
+
389
387
  # Encrypts a block of data given an encryption key
390
388
  def self.encrypt(data, b64_enc_key, iv = nil, cipher_type = 'AES-256-ECB')
391
389
  aes = OpenSSL::Cipher.new(cipher_type)
@@ -396,7 +394,7 @@ module CiBlockIo
396
394
  end
397
395
 
398
396
  # courtesy bitcoin-ruby
399
-
397
+
400
398
  def self.int_to_base58(int_val, leading_zero_bytes=0)
401
399
  alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
402
400
  base58_val, base = '', alpha.size
@@ -406,7 +404,7 @@ module CiBlockIo
406
404
  end
407
405
  base58_val
408
406
  end
409
-
407
+
410
408
  def self.base58_to_int(base58_val)
411
409
  alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
412
410
  int_val, base = 0, alpha.size
@@ -416,12 +414,12 @@ module CiBlockIo
416
414
  end
417
415
  int_val
418
416
  end
419
-
417
+
420
418
  def self.encode_base58(hex)
421
419
  leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2
422
420
  ("1"*leading_zero_bytes) + Helper.int_to_base58( hex.to_i(16) )
423
421
  end
424
-
422
+
425
423
  def self.decode_base58(base58_val)
426
424
  s = Helper.base58_to_int(base58_val).to_s(16); s = (s.bytesize.odd? ? '0'+s : s)
427
425
  s = '' if s == '00'
@@ -430,5 +428,4 @@ module CiBlockIo
430
428
  s
431
429
  end
432
430
  end
433
-
434
431
  end
@@ -1,3 +1,3 @@
1
1
  module CiBlockIo
2
- VERSION = "1.7.0"
2
+ VERSION = "1.7.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ci_block_io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atsuhiro Tsuruta feat. Atif Nazir