megar 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/README.rdoc +22 -13
- data/lib/megar/adapters/file_downloader.rb +2 -2
- data/lib/megar/adapters/file_uploader.rb +4 -7
- data/lib/megar/connection.rb +19 -8
- data/lib/megar/crypto.rb +5 -1
- data/lib/megar/crypto/aes.rb +60 -0
- data/lib/megar/crypto/aes_ctr.rb +75 -0
- data/lib/megar/crypto/support.rb +12 -55
- data/lib/megar/exception.rb +3 -0
- data/lib/megar/session.rb +1 -1
- data/lib/megar/version.rb +1 -1
- data/spec/fixtures/crypto_expectations/sample_user.json +273 -9
- data/spec/unit/adapters/file_uploader_spec.rb +2 -1
- data/spec/unit/connection_spec.rb +34 -5
- data/spec/unit/crypto/aes_ctr_spec.rb +30 -0
- data/spec/unit/crypto/aes_spec.rb +46 -0
- data/spec/unit/crypto/support_spec.rb +2 -2
- data/spec/unit/exception_spec.rb +2 -1
- metadata +8 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
0.0.4 reduce OpenSSL requirements 17-Mar-2013
|
2
|
+
===========================================================
|
3
|
+
* switch to a native AES CTR implementation so there are no
|
4
|
+
longer any special OpenSSL requirements
|
5
|
+
|
1
6
|
0.0.3 put and get ready 9-Mar-2013
|
2
7
|
===========================================================
|
3
8
|
* basic file upload support added
|
data/README.rdoc
CHANGED
@@ -2,16 +2,23 @@
|
|
2
2
|
|
3
3
|
Megar ("megaargh!" in pirate-speak) is a Ruby wrapper and command-line (CLI) client for the {Mega API}[https://mega.co.nz/#developers].
|
4
4
|
|
5
|
-
|
6
|
-
download files.
|
5
|
+
Megar has coverage of the basic file/folder operations: connect, get file/folder listings and details,
|
6
|
+
upload and download files. Read on - the following sections provide cookbook examples for using Megar within Ruby
|
7
|
+
and from the command-line.
|
8
|
+
|
9
|
+
Your help is greatly appreciated on two fronts:
|
10
|
+
* Use: It needs hammering to make sure we don't have the edge-case crypto bugs.
|
11
|
+
* Code: there's more interesting stuff in the API it would be nice to support. And a lot it would be nice to refactor (the priority so far has been to make it work correctly and testably, not fast or elegantly). Tuck in!
|
12
|
+
|
13
|
+
NOTE: megar no longer requires OpenSSL 1.0.1+. It is quite happy with any version that implements AES-128-CBC
|
14
|
+
(commonly OpenSSL 0.9.8 or greater, which you most likely already have installed).
|
7
15
|
|
8
16
|
|
9
17
|
== Requirements and Known Limitations
|
10
18
|
|
11
19
|
Consider this totally alpha at this point, especially since the Mega API has yet to be formally and fully documented.
|
12
20
|
|
13
|
-
* Currently tested with MRI 1.9.3
|
14
|
-
* Requires OpenSSL 1.0.1+ (and properly linked with ruby)
|
21
|
+
* Currently tested with MRI 1.9.3 with OpenSSL 0.9.8+
|
15
22
|
* MRI 1.9.2 and 2.x, Rubinius and JRuby 1.9 modes not yet tested. No plans to support 1.8 Ruby modes.
|
16
23
|
|
17
24
|
Mega API coverage is far from complete at this point (help appreciated!). Here's the run-down:
|
@@ -316,12 +323,9 @@ commit and distribute credentials. Change the password on the account first.
|
|
316
323
|
The tests will still run as intended with the snapshot of crypto details stored in the expectations file.
|
317
324
|
|
318
325
|
|
319
|
-
===
|
326
|
+
=== Checking my OpenSSL installation
|
320
327
|
|
321
|
-
|
322
|
-
a guide:
|
323
|
-
|
324
|
-
Check the openssl version installed
|
328
|
+
Megar will fail with a warning if suitable OpenSSL support is not available. To manually check the OpenSSL version installed:
|
325
329
|
|
326
330
|
$ irb -r openssl
|
327
331
|
1.9.3p327 :001 > OpenSSL::VERSION
|
@@ -329,16 +333,18 @@ Check the openssl version installed
|
|
329
333
|
1.9.3p327 :002 > OpenSSL::OPENSSL_VERSION
|
330
334
|
=> "OpenSSL 0.9.8r 8 Feb 2011"
|
331
335
|
|
332
|
-
OK, that's
|
333
|
-
|
336
|
+
OK, that's fine. Note that earlier versions of megar required 1.0.1+ but that is no longer the case.
|
337
|
+
|
338
|
+
If you do need or want to install or update OpenSSL, you can install from source or rvm.
|
339
|
+
On MacOSX, it is probably not a good idea to upgrade the OS-installed version (too many unintended consequences),
|
340
|
+
but you can also use brew or macports to install a version in parallel.
|
334
341
|
|
335
|
-
You can install form source, use brew or macports, or use rvm.
|
336
342
|
|
337
343
|
==== Installing OpenSSL Using RVM:
|
338
344
|
|
339
345
|
See the {rvm openssl}[https://rvm.io//packages/openssl/] page for details..
|
340
346
|
|
341
|
-
$
|
347
|
+
$ rvm pkg install openssl
|
342
348
|
Fetching openssl-1.0.1c.tar.gz to ...
|
343
349
|
|
344
350
|
$ rvm reinstall 1.9.3 --with-openssl-dir=$rvm_path/usr
|
@@ -357,6 +363,9 @@ Sweet.
|
|
357
363
|
* {Mega API is documentation}[https://mega.co.nz/#developers]
|
358
364
|
* {Using the Mega API, with Python examples}[http://julien-marchand.fr/blog/using-mega-api-with-python-examples/]
|
359
365
|
* {SpiderOak's Analysis and Recommendations for the Crypto in Kim Dotcom's Mega}[https://spideroak.com/blog/20130123130638-spideroaks-analysis-and-recommendations-for-the-crypto-in-kim-dotcoms-mega-part-one]
|
366
|
+
* {mega.py - a Python library for Mega}[https://github.com/richardasaurus/mega.py]
|
367
|
+
* {My blog post about Megar}[http://tardate.blogspot.sg/2013/03/rolling-mega-api-with-ruby.html]
|
368
|
+
* {rmega - another Ruby implementation}[https://github.com/daniele-m/rmega] - it seems rmega came to life on a similar timeline to megar. Some different implementation decisions have been made under the covers, so I don't think we'll see these projects merge anytime soon. But that means you have more choice;-) My thanks to the rmega folks for inspiring the switch in megar from OpenSSL 1.0.1+ AES CTR implementation to a native version that works with OpenSSL 0.9.8.
|
360
369
|
|
361
370
|
|
362
371
|
== Contributing
|
@@ -5,7 +5,7 @@ require 'open-uri'
|
|
5
5
|
# Javascript reference implementation: function startdownload2(res,ctx)
|
6
6
|
#
|
7
7
|
class Megar::FileDownloader
|
8
|
-
include Megar::
|
8
|
+
include Megar::Crypto::Support
|
9
9
|
|
10
10
|
attr_reader :session
|
11
11
|
attr_reader :file
|
@@ -31,7 +31,7 @@ class Megar::FileDownloader
|
|
31
31
|
decoded_content = ''
|
32
32
|
calculated_mac = [0, 0, 0, 0]
|
33
33
|
|
34
|
-
decryptor =
|
34
|
+
decryptor = get_file_cipher(decomposed_key,iv)
|
35
35
|
|
36
36
|
get_chunks(download_size).each do |chunk_start, chunk_size|
|
37
37
|
chunk = stream.readpartial(chunk_size)
|
@@ -10,7 +10,7 @@ require 'pathname'
|
|
10
10
|
# Javascript reference implementation: function initupload3()
|
11
11
|
#
|
12
12
|
class Megar::FileUploader
|
13
|
-
include Megar::
|
13
|
+
include Megar::Crypto::Support
|
14
14
|
|
15
15
|
attr_reader :folder
|
16
16
|
attr_reader :session
|
@@ -62,7 +62,7 @@ class Megar::FileUploader
|
|
62
62
|
calculated_mac = [0, 0, 0, 0]
|
63
63
|
completion_file_handle = ''
|
64
64
|
|
65
|
-
encryptor =
|
65
|
+
encryptor = get_file_cipher(upload_key,iv)
|
66
66
|
|
67
67
|
get_chunks(upload_size).each do |chunk_start, chunk_size|
|
68
68
|
chunk = stream.readpartial(chunk_size)
|
@@ -121,11 +121,8 @@ class Megar::FileUploader
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def iv
|
124
|
-
((upload_key[4]<<32)+upload_key[5])<<64
|
125
|
-
|
126
|
-
|
127
|
-
def iv_str
|
128
|
-
hexstr_to_bstr( iv.to_s(16) )
|
124
|
+
# ((upload_key[4]<<32)+upload_key[5])<<64
|
125
|
+
[upload_key[4], upload_key[5], 0, 0]
|
129
126
|
end
|
130
127
|
|
131
128
|
# Returns and caches a file upload response
|
data/lib/megar/connection.rb
CHANGED
@@ -51,14 +51,11 @@ module Megar::Connection
|
|
51
51
|
params['sid'] = sid if sid
|
52
52
|
json_data = [data].to_json
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
raise Megar::MegaRequestError.new(response_data) if response_data.is_a?(Fixnum)
|
57
|
-
|
58
|
-
response_data
|
54
|
+
response_body = get_api_response(params,json_data)
|
55
|
+
parse_json_response(response_body)
|
59
56
|
end
|
60
57
|
|
61
|
-
# Command: low-level method to actually perform the API request and return the
|
58
|
+
# Command: low-level method to actually perform the API request and return the response body.
|
62
59
|
# Given +params+ Hash of query string parameters, and +data+ JSON data structure.
|
63
60
|
# Note: there is no handling of network errors or timeouts - any exceptions will bubble up.
|
64
61
|
def get_api_response(params,data)
|
@@ -66,11 +63,25 @@ module Megar::Connection
|
|
66
63
|
http.use_ssl = (api_uri.scheme == 'https')
|
67
64
|
uri_path = api_uri.path.empty? ? '/' : api_uri.path
|
68
65
|
uri_path << hash_to_query_string(params)
|
69
|
-
|
70
|
-
JSON.parse(response.body)
|
66
|
+
http.post(uri_path,data).body
|
71
67
|
end
|
72
68
|
protected :get_api_response
|
73
69
|
|
70
|
+
# Returns the first response as JSON from response +body+, raising Mega error if present.
|
71
|
+
# Note: expects and currently only handles a single response in the data
|
72
|
+
def parse_json_response(body)
|
73
|
+
begin
|
74
|
+
response_data = JSON.parse(body)
|
75
|
+
response_data = response_data.first if response_data.is_a?(Array)
|
76
|
+
rescue => e
|
77
|
+
raise Megar::MegaRequestError.new(body.to_i) if body =~ /^[-\d]+$/
|
78
|
+
raise Megar::BadApiResponseError.new(e)
|
79
|
+
end
|
80
|
+
raise Megar::MegaRequestError.new(response_data) if response_data.is_a?(Fixnum)
|
81
|
+
response_data
|
82
|
+
end
|
83
|
+
protected :parse_json_response
|
84
|
+
|
74
85
|
# Returns Hash +h+ as an encoded query string '?a=b&c=d...'
|
75
86
|
def hash_to_query_string(h)
|
76
87
|
if qs = URI.escape(h.to_a.map{|e| e.join('=') }.join('&'))
|
data/lib/megar/crypto.rb
CHANGED
@@ -0,0 +1,60 @@
|
|
1
|
+
# A convenience wrapper for AES CBC implementation provided by OpenSSL
|
2
|
+
class Megar::Crypto::Aes
|
3
|
+
|
4
|
+
attr_accessor :key
|
5
|
+
attr_accessor :iv
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
self.key = options[:key]
|
9
|
+
self.iv = options[:iv]
|
10
|
+
end
|
11
|
+
|
12
|
+
def key=(value)
|
13
|
+
@key = value.is_a?(Array) ? value.pack(packing) : value
|
14
|
+
end
|
15
|
+
|
16
|
+
def iv=(value)
|
17
|
+
@iv = value || "\x0" * 16
|
18
|
+
end
|
19
|
+
|
20
|
+
def packing
|
21
|
+
'l>*'
|
22
|
+
end
|
23
|
+
|
24
|
+
def mode
|
25
|
+
'AES-128-CBC'
|
26
|
+
end
|
27
|
+
|
28
|
+
def cipher
|
29
|
+
@cipher ||= OpenSSL::Cipher::Cipher.new(mode)
|
30
|
+
end
|
31
|
+
|
32
|
+
def encrypt(data)
|
33
|
+
a32_mode = data.is_a?(Array)
|
34
|
+
d = a32_mode ? data.pack(packing) : data
|
35
|
+
|
36
|
+
cipher.reset
|
37
|
+
cipher.encrypt
|
38
|
+
cipher.padding = 0
|
39
|
+
cipher.iv = iv
|
40
|
+
cipher.key = key
|
41
|
+
result = cipher.update d
|
42
|
+
|
43
|
+
a32_mode ? result.unpack(packing) : result
|
44
|
+
end
|
45
|
+
|
46
|
+
def decrypt(data)
|
47
|
+
a32_mode = data.is_a?(Array)
|
48
|
+
d = a32_mode ? data.pack(packing) : data
|
49
|
+
|
50
|
+
cipher.reset
|
51
|
+
cipher.decrypt
|
52
|
+
cipher.padding = 0
|
53
|
+
cipher.iv = iv
|
54
|
+
cipher.key = key
|
55
|
+
result = cipher.update d
|
56
|
+
|
57
|
+
a32_mode ? result.unpack(packing) : result
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Implements AES COUNTER mode using base AES CBC implementation provided by OpenSSL
|
2
|
+
class Megar::Crypto::AesCtr
|
3
|
+
|
4
|
+
attr_accessor :key
|
5
|
+
attr_accessor :iv
|
6
|
+
|
7
|
+
# Consturcts a new AES CTR-mode object give +options+
|
8
|
+
# options[:key] = encryption key as binary string or array of 32-bit integer (required)
|
9
|
+
# options[:iv] = initialisation vector as array of 32-bit integer (nulled by default)
|
10
|
+
def initialize(options={})
|
11
|
+
self.key = options[:key]
|
12
|
+
self.iv = options[:iv]
|
13
|
+
end
|
14
|
+
|
15
|
+
def packing
|
16
|
+
'l>*'
|
17
|
+
end
|
18
|
+
|
19
|
+
def key=(value)
|
20
|
+
@key = value.is_a?(Array) ? value.pack(packing) : value
|
21
|
+
end
|
22
|
+
|
23
|
+
def iv=(value)
|
24
|
+
@iv = value ? value.dup : [0,0,0,0]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the encrypted binary string of +chunk+ (provided as binary string).
|
28
|
+
# Repeated calls will continue the counter sequence.
|
29
|
+
def update(chunk)
|
30
|
+
a32 = str_to_a32(chunk)
|
31
|
+
last_i = 0
|
32
|
+
|
33
|
+
(0..a32.size - 3).step(4) do |i|
|
34
|
+
enc = Megar::Crypto::Aes.new(key: key).encrypt(iv)
|
35
|
+
4.times do |m|
|
36
|
+
a32[i+m] = (a32[i+m] || 0) ^ (enc[m] || 0)
|
37
|
+
end
|
38
|
+
iv[3] += 1
|
39
|
+
iv[2] += 1 if iv[3] == 0
|
40
|
+
last_i = i + 4
|
41
|
+
end
|
42
|
+
|
43
|
+
remainder = a32.size % 4
|
44
|
+
|
45
|
+
if remainder > 0
|
46
|
+
v = [0, 0, 0, 0]
|
47
|
+
(last_i..a32.size - 1).step(1) { |m| v[m-last_i] = a32[m] || 0 }
|
48
|
+
enc = Megar::Crypto::Aes.new(key: key).encrypt(iv)
|
49
|
+
4.times { |m| v[m] = v[m] ^ enc[m] }
|
50
|
+
|
51
|
+
(last_i..a32.size - 1).step(1) { |j| a32[j] = v[j - last_i] || 0 }
|
52
|
+
end
|
53
|
+
|
54
|
+
a32_to_str(a32)[0..chunk.size - 1]
|
55
|
+
end
|
56
|
+
|
57
|
+
# TODO: refactor to pull this method from a shared lib.
|
58
|
+
def str_to_a32(b,signed=true)
|
59
|
+
a = Array.new((b.length+3) >> 2,0)
|
60
|
+
b.length.times { |i| a[i>>2] |= (b.getbyte(i) << (24-(i & 3)*8)) }
|
61
|
+
if signed
|
62
|
+
a.pack('l>*').unpack('l>*')
|
63
|
+
else
|
64
|
+
a
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# TODO: refactor to pull this method from a shared lib.
|
69
|
+
def a32_to_str(a)
|
70
|
+
b = ''
|
71
|
+
(a.size * 4).times { |i| b << ((a[i>>2] >> (24-(i & 3)*8)) & 255).chr }
|
72
|
+
b
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/lib/megar/crypto/support.rb
CHANGED
@@ -9,11 +9,11 @@ require 'base64'
|
|
9
9
|
#
|
10
10
|
# Javascript reference implementations quoted here are taken from the Mega javascript source.
|
11
11
|
#
|
12
|
-
module Megar::
|
12
|
+
module Megar::Crypto::Support
|
13
13
|
|
14
14
|
# Verifies that the required crypto support is available from ruby/openssl
|
15
15
|
def crypto_requirements_met?
|
16
|
-
OpenSSL::Cipher.ciphers.include?("AES-128-
|
16
|
+
OpenSSL::Cipher.ciphers.include?("AES-128-CBC")
|
17
17
|
end
|
18
18
|
|
19
19
|
# Returns encrypted key given an array +a+ of 32-bit integers
|
@@ -72,17 +72,14 @@ module Megar::CryptoSupport
|
|
72
72
|
a32_to_str(decrypt_base64_to_a32(data, key))
|
73
73
|
end
|
74
74
|
|
75
|
+
# Returns AES-128 CBC encrypted given +key+ and +data+ (String)
|
76
|
+
def aes_cbc_encrypt(data, key)
|
77
|
+
Megar::Crypto::Aes.new(key: key).encrypt(data)
|
78
|
+
end
|
75
79
|
|
76
80
|
# Returns AES-128 encrypted given +key+ and +data+ (arrays of 32-bit signed integers)
|
77
81
|
def aes_encrypt_a32(data, key)
|
78
|
-
|
79
|
-
aes.encrypt
|
80
|
-
aes.padding = 0
|
81
|
-
aes.key = key.pack('l>*')
|
82
|
-
aes.update(data.pack('l>*')).unpack('l>*')
|
83
|
-
# e = aes.update(data.pack('l>*')).unpack('l>*')
|
84
|
-
# e << aes.final
|
85
|
-
# e.unpack('l>*')
|
82
|
+
Megar::Crypto::Aes.new(key: key).encrypt(data)
|
86
83
|
end
|
87
84
|
|
88
85
|
# Returns AES-128 CBC decrypted given +key+ and +data+ (arrays of 32-bit signed integers)
|
@@ -92,14 +89,7 @@ module Megar::CryptoSupport
|
|
92
89
|
|
93
90
|
# Returns AES-128 CBC decrypted given +key+ and +data+ (String)
|
94
91
|
def aes_cbc_decrypt(data, key)
|
95
|
-
|
96
|
-
aes.decrypt
|
97
|
-
aes.padding = 0
|
98
|
-
aes.key = key
|
99
|
-
aes.iv = "\0" * 16
|
100
|
-
d = aes.update(data)
|
101
|
-
d = aes.final if d.empty?
|
102
|
-
d
|
92
|
+
Megar::Crypto::Aes.new(key: key).decrypt(data)
|
103
93
|
end
|
104
94
|
|
105
95
|
# Returns AES-128 CBC decrypted given +key+ and +data+ (arrays of 32-bit signed integers)
|
@@ -107,18 +97,6 @@ module Megar::CryptoSupport
|
|
107
97
|
str_to_a32(aes_cbc_encrypt(a32_to_str(data), a32_to_str(key)),signed)
|
108
98
|
end
|
109
99
|
|
110
|
-
# Returns AES-128 CBC encrypted given +key+ and +data+ (String)
|
111
|
-
def aes_cbc_encrypt(data, key)
|
112
|
-
aes = OpenSSL::Cipher::Cipher.new('AES-128-CBC')
|
113
|
-
aes.encrypt
|
114
|
-
aes.padding = 0
|
115
|
-
aes.key = key
|
116
|
-
aes.iv = "\0" * 16
|
117
|
-
d = aes.update(data)
|
118
|
-
d = aes.final if d.empty?
|
119
|
-
d
|
120
|
-
end
|
121
|
-
|
122
100
|
# Returns an array of 32-bit signed integers representing the string +b+
|
123
101
|
#
|
124
102
|
# Javascript reference implementation: function str_to_a32(b)
|
@@ -127,7 +105,6 @@ module Megar::CryptoSupport
|
|
127
105
|
a = Array.new((b.length+3) >> 2,0)
|
128
106
|
b.length.times { |i| a[i>>2] |= (b.getbyte(i) << (24-(i & 3)*8)) }
|
129
107
|
if signed
|
130
|
-
# hack to force to signed 32-bit ... I don't think we really need to do this, but it makes comparison with
|
131
108
|
a.pack('l>*').unpack('l>*')
|
132
109
|
else
|
133
110
|
a
|
@@ -152,7 +129,7 @@ module Megar::CryptoSupport
|
|
152
129
|
s32 = str_to_a32(s)
|
153
130
|
h32 = [0,0,0,0]
|
154
131
|
s32.length.times {|i| h32[i&3] ^= s32[i] }
|
155
|
-
|
132
|
+
0x4000.times {|i| h32 = aes_encrypt_a32(h32, aeskey) }
|
156
133
|
a32_to_base64([h32[0],h32[2]])
|
157
134
|
end
|
158
135
|
|
@@ -278,10 +255,8 @@ module Megar::CryptoSupport
|
|
278
255
|
4.times do
|
279
256
|
len = ((privk[0].ord * 256 + privk[1].ord + 7) / 8) + 2
|
280
257
|
privk_part = privk[0,len]
|
281
|
-
# puts "\nprivk_part #{base64urlencode(privk_part)}"
|
282
258
|
privk_part_a32 = mpi_to_a32(privk_part)
|
283
259
|
decomposed_key << privk_part_a32
|
284
|
-
# puts "decomp: len:#{len} privk_part_a32:#{privk_part_a32.length} first:#{privk_part_a32.first} last:#{privk_part_a32.last}"
|
285
260
|
privk.slice!(0,len)
|
286
261
|
end
|
287
262
|
decomposed_key
|
@@ -303,8 +278,6 @@ module Megar::CryptoSupport
|
|
303
278
|
4.times do |i|
|
304
279
|
len = ((privk[0].ord * 256 + privk[1].ord + 7) / 8) + 2
|
305
280
|
privk_part = privk[0,len]
|
306
|
-
# puts "\nl: ", len
|
307
|
-
# puts "decrypted rsa part hex: \n", privk_part.unpack('H*').first
|
308
281
|
decomposed_key << privk_part[2,privk_part.length].unpack('H*').first.to_i(16)
|
309
282
|
privk.slice!(0,len)
|
310
283
|
end
|
@@ -482,26 +455,10 @@ module Megar::CryptoSupport
|
|
482
455
|
chunks
|
483
456
|
end
|
484
457
|
|
485
|
-
# Returns AES CTR-mode decryption cipher given +key+ and +iv+ as array of
|
486
|
-
#
|
487
|
-
def get_file_decrypter(key,iv)
|
488
|
-
aes = OpenSSL::Cipher::Cipher.new('AES-128-CTR')
|
489
|
-
aes.decrypt
|
490
|
-
aes.padding = 0
|
491
|
-
aes.key = a32_to_str(key)
|
492
|
-
aes.iv = a32_to_str(iv)
|
493
|
-
aes
|
494
|
-
end
|
495
|
-
|
496
|
-
# Returns AES CTR-mode encryption cipher given +key+ as array of int and +iv+ as binary string
|
458
|
+
# Returns AES CTR-mode decryption cipher given +key+ and +iv+ as array of 32-bit integer
|
497
459
|
#
|
498
|
-
def
|
499
|
-
|
500
|
-
aes.encrypt
|
501
|
-
aes.padding = 0
|
502
|
-
aes.key = a32_to_str(key)
|
503
|
-
aes.iv = iv
|
504
|
-
aes
|
460
|
+
def get_file_cipher(key,iv)
|
461
|
+
Megar::Crypto::AesCtr.new(key: key, iv: iv)
|
505
462
|
end
|
506
463
|
|
507
464
|
# Returns the +chunk+ mac (array of unsigned int)
|
data/lib/megar/exception.rb
CHANGED
@@ -15,6 +15,9 @@ module Megar
|
|
15
15
|
# Raised on non-API related file upload errors
|
16
16
|
class FileUploadError < Error; end
|
17
17
|
|
18
|
+
# Raised on non-mega API related request errors
|
19
|
+
class BadApiResponseError < Error; end
|
20
|
+
|
18
21
|
class MegaRequestError < Error
|
19
22
|
|
20
23
|
# Initialise with +error_code+ returned from Mega
|
data/lib/megar/session.rb
CHANGED
data/lib/megar/version.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"email": "megartest@gmail.com",
|
3
3
|
"email_mixed_case": "Megartest@gmail.com",
|
4
|
-
"password": "
|
4
|
+
"password": "arDGGNCVPQEZKqasmfjQSvOmgOPdLhBX",
|
5
5
|
"autoconnect": false,
|
6
6
|
"login_response_data": {
|
7
|
-
"csid": "
|
7
|
+
"csid": "CAArCWzdn3ohzX_8-CYamVViQnGwY3j0tAp35lqN02lOCJM3cdQP42UpVWWcB0Q901XaMf2LtQh94QK9Y-llhC9ktJCjVH7Da_kAy9FpQb46si1nVg1cAjRyXUQqQgyo62r-ooluHxE7gq98JCwH3pmfM7998A7YDKKhfaNpL-TghE6yhhbnCLg_qPy2u4HNIBbYbooOFVSUn1jPmPeLhUbnafHMACygftUXlymocYcbTJRfBxU-gVSLlrHJTw7dm96_nGAfoaOqfr_-IR2yU0Td8Y5XMFMDFcBue_5iE2f1EuZ5tJK_zTz2nDyQPciuf7RKvMLcJQimbwEwEJLujr9o",
|
8
8
|
"privk": "4Iurk4vQ0BlLEEvEyaRUX8QnYzJFIedm0RVKe2pLh4wTzBBtgmafnszD_dP3Y40P-DSNLEGfWghL-0_BIW4XP8tfGNFkMg7mnYgQYC91ccz58BbhGEDf7-j97dstckf3OSSsT9D9H-cocXzyt1m231w9d7YLX23c3KAGz3vxdnl66F4jsFGO9AdIyb1KTEEt7NHkljtbz3WgWlk6W6wBawuEbJvLPHPx2L16i0iacbbkQi8ZF4pmddswMa9yWOSXwUribGDbdgx_jDGjBoKJUJI-7Aa-aOaRPEoVUTft2R2lNAVErvYwD_GIsIhQiCcJWul-KqPhI3vquvzUHd2rHHvKyTLyvXKyIDeVdBGXTaqFA2ni9xsjUNMOX14ftBZ4_fgDce0jvrZzYRs5IuOMt3K9gKMpBpUWtnlaBYbnYdL2zJuFlrM77PlcYab2uLLqlSe4hh-FxMAc_p_8tDAoU4dPgpgOpU3GRR8i7oszu_MKibzNpRBeAX1UtwKwQepjPnipu9aQlPy9OtgB-5KmGi34EcMKBPg8BN6vHRYg0Za_lk_TtTQ4WbkllAqR3Fla5-RBjzB7f3dWae4ES3VX4f-dI-UYrrKDQkqaS0R_xLaMPNG6_GQMDM7L5Fsa8I3hFjdgfs9rV4Xf_uIFrhUjm25EuT5JCdobNmwBi9VU5nCbk0LQJdrXDNYV3fmD-Y_p_KV8x_-opRnXUV03SCopOD6DhitsFtpv065QXcG1SNDu0mM-kgDh9E-QddtQQtXLLPuKFyX5o1ts08EqXTxHsZo5tIsevbExZoz9hxSRrr-V5swEDcJXoV78_k6sR3iniZ_m77JVo9QU572av2MvNhyu5YeTXyc0m6Me7cPGiO0",
|
9
|
-
"k": "
|
9
|
+
"k": "8FS4LRVtEpzQXKZNUyGBwg"
|
10
10
|
},
|
11
11
|
"master_key": [
|
12
12
|
384287193,
|
@@ -14,8 +14,8 @@
|
|
14
14
|
554881366,
|
15
15
|
530403344
|
16
16
|
],
|
17
|
-
"expected_uh": "
|
18
|
-
"sid": "
|
17
|
+
"expected_uh": "rMkG_yo0TCw",
|
18
|
+
"sid": "WhJ1kiw0-YORXrdnSr8qJnpBOEN6Q2Y5dFp37MVSDV1V6EpwGECdQtgW0Q",
|
19
19
|
"rsa_private_key_b64": "BACOQ7VCjwkiwYCKhqRRvPTMBaQ5Yx2_sszj6ILrxrTBOJ2bu-9LsOSvaGz0HpnM2lXpJg3h6QWJdlQBOhwvfeafHg7rcEaaDuUWONifv5ABpQgeoAij6cgARMvFiOdjarMvu954Eduup8PHcgfjsBSu76qpu3UqkZCpBpByAYU1oQQA1i5oxuA9i7qsXxhJRsBeceI7hZSnNYAQzsWfFD0kDW8GsJBuK-CST6oNNp0z7MQ5Qof6DZ8x9wt5ZJR43HFmD2VtTQUZLvIeemC4URuR74UWn25CETyzQdIhdNSEibaCRvi0sNwb-ikCZVxxo4-O7ZBQPw0egrQOJW06HlCQUykH_00EIoiBRcbJLS6W3nJ8KhddDf_4glZYPz6fBpqu1jIdIBGOGQf4Ttn_DmdAgkLxWF7AF6k59D45J9kxfANRJIBGSWUsI1bQBlrwFtois4O14uQkQ40Jh_d5BCrLPe599zrliGH1SsECx_xYGWcWY_GPsPa99d_St56BB9oUtDW3A1clEx2uVS8OWqRPgVimu6MXs_TEEnjWGRFofHpl_8qGeAoPbNkXsTMQb6uUK4NCYq3UzVfreByEnOqxuQcu2jlF4Ey0UH9w_KjkRyT8xu--kyZAbktYaw4EZmGUxZIlkZLk_OAGaW8KWPZhdGxjfi8K7WeZK2HtLe4At48DC_ED_20pNtkTCrB6-FQlMj6a4O2C1sE6pSdrIPofcK-HpaefOXqYKWpRM-Wnp_qHnuJgEtgodQ-pw74nXkOsVFZoJzVGCepZKoa2xhevAu3CfXMfR97LIski17PPwWV9n7yQ7onSKDmJP-q4mO7PG7LICE22WkgJkk_T1W4UkDTkCxZE_t64F6JOryg",
|
20
20
|
"decomposed_rsa_private_key": [
|
21
21
|
99901518447147034909201847419097315968297147437151469508360346463543063455874100243913856315732601845631262435262260706834732781343251117295631282035669718956849603873760427510697419513879951677293141811802298231979984193675329310799949319780256427743430868153430092107435691279045586737323088097814348379553,
|
@@ -52,6 +52,16 @@
|
|
52
52
|
"k": "",
|
53
53
|
"ts": 1361694312
|
54
54
|
},
|
55
|
+
{
|
56
|
+
"h": "Ot5xDCTI",
|
57
|
+
"p": "ewZ1GAqT",
|
58
|
+
"u": "zA8CzCf9tZw",
|
59
|
+
"t": 0,
|
60
|
+
"a": "JKLTa3pcvxf3ICsFHc0aa4JDQt7Dn9ODBZ9S7szZV-4aWMnKoUORIpWxvsTsV4oC",
|
61
|
+
"k": "zA8CzCf9tZw:dFvviPw8ljp8cKeEq1sIdVusWdY56kXZKdBQVQeK4qk",
|
62
|
+
"s": 5482930,
|
63
|
+
"ts": 1363505767
|
64
|
+
},
|
55
65
|
{
|
56
66
|
"h": "jtwkAQaK",
|
57
67
|
"p": "ywJVFBKB",
|
@@ -119,6 +129,258 @@
|
|
119
129
|
"k": "zA8CzCf9tZw:bLCHGilxhwBlxkZs8uptY87wZf_WNCR6RefwEgtbRmo",
|
120
130
|
"s": 8920445,
|
121
131
|
"ts": 1362235380
|
132
|
+
},
|
133
|
+
{
|
134
|
+
"h": "vxpUhLKT",
|
135
|
+
"p": "ywJVFBKB",
|
136
|
+
"u": "zA8CzCf9tZw",
|
137
|
+
"t": 0,
|
138
|
+
"a": "-MsEWITGkFl-E_aM7qWXZLSOpfi9p_mwjGy47IrSLvk",
|
139
|
+
"k": "zA8CzCf9tZw:1kZ1iNJoSjwf-X5DtmtIc6rjNouau0CgPANnaPmGCEw",
|
140
|
+
"s": 137080,
|
141
|
+
"fa": "113:0*DW1HZGACejc",
|
142
|
+
"ts": 1362778998
|
143
|
+
},
|
144
|
+
{
|
145
|
+
"h": "ahozjYba",
|
146
|
+
"p": "ywJVFBKB",
|
147
|
+
"u": "zA8CzCf9tZw",
|
148
|
+
"t": 0,
|
149
|
+
"a": "2poE9RKoqBfWeK71Vnv8YKyUAKzUqaUcGDhcToD-Brk",
|
150
|
+
"k": "zA8CzCf9tZw:-FjfHWTpg9u48DsPNKxjlrslIZXqenC4CeCTkk_aoek",
|
151
|
+
"s": 137080,
|
152
|
+
"ts": 1362779516
|
153
|
+
},
|
154
|
+
{
|
155
|
+
"h": "asY3gbSa",
|
156
|
+
"p": "ywJVFBKB",
|
157
|
+
"u": "zA8CzCf9tZw",
|
158
|
+
"t": 0,
|
159
|
+
"a": "JYggnUiEG4yQ6KeMi7uYVb1Hd20qfpcE_kgt74-WtW8",
|
160
|
+
"k": "zA8CzCf9tZw:jqHCYoJVoHSjbfCoaafcStGQhbzG7YlnKaovknUnMhI",
|
161
|
+
"s": 137080,
|
162
|
+
"ts": 1362793600
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"h": "Wk4nWISA",
|
166
|
+
"p": "ywJVFBKB",
|
167
|
+
"u": "zA8CzCf9tZw",
|
168
|
+
"t": 0,
|
169
|
+
"a": "k11jsEyjmBDwbb0nLO8lJq_BZC0-o8lCnvKy4dHTWAM",
|
170
|
+
"k": "zA8CzCf9tZw:jLbBi09Xuh4_EkBKojzXRvmAjRiRdMnq6FTpxLraSJs",
|
171
|
+
"s": 39,
|
172
|
+
"ts": 1362798430
|
173
|
+
},
|
174
|
+
{
|
175
|
+
"h": "2hBgHbAQ",
|
176
|
+
"p": "ywJVFBKB",
|
177
|
+
"u": "zA8CzCf9tZw",
|
178
|
+
"t": 0,
|
179
|
+
"a": "HX1V3cQKT7j3U0tc8UWF-FPOoacebme0wJto2kjOIFr_o4rss15XYMibUpHx1kzd",
|
180
|
+
"k": "zA8CzCf9tZw:n2E2YxruJFeifhcSM8pxd8D7wOSoOuQcaAsjip_UmMI",
|
181
|
+
"s": 7622058,
|
182
|
+
"ts": 1362798784
|
183
|
+
},
|
184
|
+
{
|
185
|
+
"h": "LtZE3YKY",
|
186
|
+
"p": "ywJVFBKB",
|
187
|
+
"u": "zA8CzCf9tZw",
|
188
|
+
"t": 0,
|
189
|
+
"a": "81ADi8A0sb761XNa7qQ9qYgT7MO8-3n6ctcZq71PHDs",
|
190
|
+
"k": "zA8CzCf9tZw:xffmeXDkLZ0WWzioEaMJAEzdLqB53rSEkY1XzR8aR_A",
|
191
|
+
"s": 39,
|
192
|
+
"ts": 1362801884
|
193
|
+
},
|
194
|
+
{
|
195
|
+
"h": "X5oiVQKa",
|
196
|
+
"p": "ywJVFBKB",
|
197
|
+
"u": "zA8CzCf9tZw",
|
198
|
+
"t": 0,
|
199
|
+
"a": "dyvg4y1uxduQCBPxjtANaQ7tse9DAOk_MUeiIZ_Woxs",
|
200
|
+
"k": "zA8CzCf9tZw:ECSKwEkyAvS6lWAQJFWZcH3P48eeAQNQxGYAJQFr9_o",
|
201
|
+
"s": 39,
|
202
|
+
"ts": 1362802310
|
203
|
+
},
|
204
|
+
{
|
205
|
+
"h": "zl5WEBZL",
|
206
|
+
"p": "ywJVFBKB",
|
207
|
+
"u": "zA8CzCf9tZw",
|
208
|
+
"t": 0,
|
209
|
+
"a": "WyFR2PQ1HPCdi5X7GUR98o7Posh_gAtwKcgvGI0wPiA",
|
210
|
+
"k": "zA8CzCf9tZw:h4OAIIuQ38G41RMhYTro92JZEuzuuo_Ei0ZSiNNe6nY",
|
211
|
+
"s": 39,
|
212
|
+
"ts": 1362802849
|
213
|
+
},
|
214
|
+
{
|
215
|
+
"h": "H9BwDLRa",
|
216
|
+
"p": "ywJVFBKB",
|
217
|
+
"u": "zA8CzCf9tZw",
|
218
|
+
"t": 0,
|
219
|
+
"a": "qHhpeU0sTjxsIWMCnT7zDXjLChHXt_lPmg42bxn93SI",
|
220
|
+
"k": "zA8CzCf9tZw:0t8RnutgNVAJrZCCLv9QJGCBZSRC9zG6SGecIvW4rGE",
|
221
|
+
"s": 39,
|
222
|
+
"ts": 1362803888
|
223
|
+
},
|
224
|
+
{
|
225
|
+
"h": "79gjRRZa",
|
226
|
+
"p": "ywJVFBKB",
|
227
|
+
"u": "zA8CzCf9tZw",
|
228
|
+
"t": 0,
|
229
|
+
"a": "MB1tbC7R_H2_fTQZslTfrwI1guKfw6FJrxUzC1yXFeA",
|
230
|
+
"k": "zA8CzCf9tZw:UyN77tmMdhv3OIAi64JEf9OwWIMu11nYv1SNNG1orVs",
|
231
|
+
"s": 39,
|
232
|
+
"ts": 1362803938
|
233
|
+
},
|
234
|
+
{
|
235
|
+
"h": "f4BCSDRa",
|
236
|
+
"p": "ywJVFBKB",
|
237
|
+
"u": "zA8CzCf9tZw",
|
238
|
+
"t": 0,
|
239
|
+
"a": "K1lKkodz26q9BnRpoNbuV6QdEBFx1EYSDGlHgbRIUfA",
|
240
|
+
"k": "zA8CzCf9tZw:g_-SqiuxXreNze5_g9ZShPBYpZQ1nxKpyNb85P_7N4s",
|
241
|
+
"s": 39,
|
242
|
+
"ts": 1362804274
|
243
|
+
},
|
244
|
+
{
|
245
|
+
"h": "q9oRUJhI",
|
246
|
+
"p": "ywJVFBKB",
|
247
|
+
"u": "zA8CzCf9tZw",
|
248
|
+
"t": 0,
|
249
|
+
"a": "CrTfHaSw2ueOZoVlCynDL8f-f10gKkuurMrXXRsWnZE",
|
250
|
+
"k": "zA8CzCf9tZw:rIgbLqS3Fq3acmFZaN6pNa-ArrjCi2gB0k-ngIeHoUA",
|
251
|
+
"s": 117,
|
252
|
+
"ts": 1362810737
|
253
|
+
},
|
254
|
+
{
|
255
|
+
"h": "r8RynQzR",
|
256
|
+
"p": "ywJVFBKB",
|
257
|
+
"u": "zA8CzCf9tZw",
|
258
|
+
"t": 0,
|
259
|
+
"a": "O2kUBPVRHHnNm42hzp9-0-8_rGH4Ym_bTM8APDA9zsU",
|
260
|
+
"k": "zA8CzCf9tZw:cNPzHLkA0NTVAys3esnj9QWNXF34nikUt1NhKK_c1Q8",
|
261
|
+
"s": 195,
|
262
|
+
"ts": 1362810989
|
263
|
+
},
|
264
|
+
{
|
265
|
+
"h": "P8RT0KgS",
|
266
|
+
"p": "ywJVFBKB",
|
267
|
+
"u": "zA8CzCf9tZw",
|
268
|
+
"t": 0,
|
269
|
+
"a": "AJNkLW7wKTziPYvxwkTwQx0a9p8CM-lxEIeR5RZu4R4",
|
270
|
+
"k": "zA8CzCf9tZw:LbMSMY5HNMeDjdSU3q0nYGmAOt_WerTU_DO3v7iQdkE",
|
271
|
+
"s": 39,
|
272
|
+
"ts": 1362811065
|
273
|
+
},
|
274
|
+
{
|
275
|
+
"h": "axwRVSzY",
|
276
|
+
"p": "ywJVFBKB",
|
277
|
+
"u": "zA8CzCf9tZw",
|
278
|
+
"t": 0,
|
279
|
+
"a": "HRZtXiNle4qhocTLMYW2mmmCV0j_B9bEvK27yD9xQK8",
|
280
|
+
"k": "zA8CzCf9tZw:UYpuIGPDzALgy_1CbvLPSA5Sr6Dv6Et2E4EM3Uw0moI",
|
281
|
+
"s": 39,
|
282
|
+
"ts": 1363516600
|
283
|
+
},
|
284
|
+
{
|
285
|
+
"h": "btpXFCxR",
|
286
|
+
"p": "ywJVFBKB",
|
287
|
+
"u": "zA8CzCf9tZw",
|
288
|
+
"t": 0,
|
289
|
+
"a": "_jTsbHtJPR7fjbmqUK8Wsm7yw-d6nryNO7SPw4NO9TM",
|
290
|
+
"k": "zA8CzCf9tZw:IxMuRPVCFh-thywK1acaMjRKp3RerDi1-NEpKp59Uh0",
|
291
|
+
"s": 137080,
|
292
|
+
"fa": "115:0*qOMemq7l9jY",
|
293
|
+
"ts": 1363516781
|
294
|
+
},
|
295
|
+
{
|
296
|
+
"h": "boQCiQiT",
|
297
|
+
"p": "ywJVFBKB",
|
298
|
+
"u": "zA8CzCf9tZw",
|
299
|
+
"t": 0,
|
300
|
+
"a": "hmWiu5RHYoCKpiQqPx8hkd5t8g_Qcs_mUlDWsUclBct9HRuCUp_L3mEAwd4l0rD5",
|
301
|
+
"k": "zA8CzCf9tZw:4QCgBoj9bYA40I_vq8E6-j3TlEUkfAdW_sW4meyoAvQ",
|
302
|
+
"s": 5482930,
|
303
|
+
"ts": 1363516963
|
304
|
+
},
|
305
|
+
{
|
306
|
+
"h": "zh5hhBAI",
|
307
|
+
"p": "ywJVFBKB",
|
308
|
+
"u": "zA8CzCf9tZw",
|
309
|
+
"t": 0,
|
310
|
+
"a": "m1TCrq-Btvsp4ckHFRHuzaaZFiJKeA1f4wD5s2rFvvs",
|
311
|
+
"k": "zA8CzCf9tZw:5sushWWIFZAfDLq1ZKNIVu8P2JryHAiWgKkkUl05k6g",
|
312
|
+
"s": 5482930,
|
313
|
+
"ts": 1363517214
|
314
|
+
},
|
315
|
+
{
|
316
|
+
"h": "ep4XnTxQ",
|
317
|
+
"p": "jtwkAQaK",
|
318
|
+
"u": "zA8CzCf9tZw",
|
319
|
+
"t": 0,
|
320
|
+
"a": "Cs1l7Rew5I2GGbyzw8VePAhoPyMkMHTVXoa2-SN4-uo",
|
321
|
+
"k": "zA8CzCf9tZw:09CaiWPvTBrPQhxWxKoIgUbkZNKNJRSQmJ0hHzw3JvI",
|
322
|
+
"s": 39,
|
323
|
+
"ts": 1362803268
|
324
|
+
},
|
325
|
+
{
|
326
|
+
"h": "b4IiHZII",
|
327
|
+
"p": "jtwkAQaK",
|
328
|
+
"u": "zA8CzCf9tZw",
|
329
|
+
"t": 0,
|
330
|
+
"a": "uazdd2xapOTa5p_WMSVtav2hytWZw9eYyqTOzUAFpDc",
|
331
|
+
"k": "zA8CzCf9tZw:cI9G4pGAAExuZlPILGyqudknvWxh9rse00yWWC7pgp8",
|
332
|
+
"s": 78,
|
333
|
+
"ts": 1362805795
|
334
|
+
},
|
335
|
+
{
|
336
|
+
"h": "jgQg3ALZ",
|
337
|
+
"p": "jtwkAQaK",
|
338
|
+
"u": "zA8CzCf9tZw",
|
339
|
+
"t": 0,
|
340
|
+
"a": "veRpCzk5S22KWwlnOqdgtqt3rWFM76XztTygOevPp34",
|
341
|
+
"k": "zA8CzCf9tZw:esxiNRkxr1KscaCsJuxg19qu7mXrgTB5tLwbtHMZoAs",
|
342
|
+
"s": 156,
|
343
|
+
"ts": 1362805852
|
344
|
+
},
|
345
|
+
{
|
346
|
+
"h": "fkQ0wZjZ",
|
347
|
+
"p": "jtwkAQaK",
|
348
|
+
"u": "zA8CzCf9tZw",
|
349
|
+
"t": 0,
|
350
|
+
"a": "cPDFcFwRVTaCB-DxBAGCUxwD8qrgt1B2OMBGK-VNPME",
|
351
|
+
"k": "zA8CzCf9tZw:32zJUYIXo4uF-wgbHj-tlCxkKl4pYvs2gP0YIajuWdQ",
|
352
|
+
"s": 117,
|
353
|
+
"ts": 1362805994
|
354
|
+
},
|
355
|
+
{
|
356
|
+
"h": "DsJClQSZ",
|
357
|
+
"p": "jtwkAQaK",
|
358
|
+
"u": "zA8CzCf9tZw",
|
359
|
+
"t": 0,
|
360
|
+
"a": "-oN7uRxlI-WrKsT03Zju5luB7z3Lg7uKVWSRczZsf7k",
|
361
|
+
"k": "zA8CzCf9tZw:Ut4_ESCi5yk71HroPJidRIqwPwyy3ZWsjz3NcgdPfBM",
|
362
|
+
"s": 195,
|
363
|
+
"ts": 1362810877
|
364
|
+
},
|
365
|
+
{
|
366
|
+
"h": "j9RWXTqC",
|
367
|
+
"p": "jtwkAQaK",
|
368
|
+
"u": "zA8CzCf9tZw",
|
369
|
+
"t": 0,
|
370
|
+
"a": "h2ekShHqJMnbjk3uvW9n8hTGF07UySjFYvfTo5ktcCk",
|
371
|
+
"k": "zA8CzCf9tZw:4Q-l3ygtVC8-0p5CtWVWZkMc0G49aYKxCjx6vWO8Wvw",
|
372
|
+
"s": 195,
|
373
|
+
"ts": 1362810882
|
374
|
+
},
|
375
|
+
{
|
376
|
+
"h": "jopGGDJZ",
|
377
|
+
"p": "jtwkAQaK",
|
378
|
+
"u": "zA8CzCf9tZw",
|
379
|
+
"t": 0,
|
380
|
+
"a": "oJlWwnaj_tjQf__zDiqQm3zKhemldlfH-boZb7Cjri8",
|
381
|
+
"k": "zA8CzCf9tZw:Xol_vUW-InH4GMae5dZahrj2noOdLwibtgyGdzNSEvM",
|
382
|
+
"s": 195,
|
383
|
+
"ts": 1362810883
|
122
384
|
}
|
123
385
|
],
|
124
386
|
"ok": [
|
@@ -134,17 +396,18 @@
|
|
134
396
|
"m": "megartest@gmail.com"
|
135
397
|
}
|
136
398
|
],
|
137
|
-
"sn": "
|
399
|
+
"sn": "71k37B8iTRY"
|
138
400
|
},
|
139
401
|
"file_upload_url_response": {
|
140
|
-
"p": "http://
|
402
|
+
"p": "http://gfs262n153.userstorage.mega.co.nz/ul/m8ZGZ_6t5WZHlQIlxfoPJjq3g31KcumFhIJiDoWrmTo1UNjleDcbzk0T8aGIsYX10KZccP08iFlTBGXWF79Jnw"
|
141
403
|
},
|
142
404
|
"sample_files": {
|
143
405
|
"megar_test_sample_1.txt": {
|
144
406
|
"file_download_url_response": {
|
145
407
|
"s": 39,
|
146
408
|
"at": "lv-LcMAl0dvpdxQFWNVZ7m9-mFT79mS0Mi_fH9InTqtBgcpe8kRVDGQ5Hj4BrXrc",
|
147
|
-
"g": "http://gfs262n164.userstorage.mega.co.nz/dl/
|
409
|
+
"g": "http://gfs262n164.userstorage.mega.co.nz/dl/nZUYBF_XMjz2fQKIdUQ8jsNYgY_Rucr3ykY900Mow4DtWWYq0wt-jt0tBC2cIQTOR6Modf11n-ekN4FZb01mgq2TSPcRDGy2-X_6uumuN0c-n83KZw",
|
410
|
+
"pfa": 1
|
148
411
|
},
|
149
412
|
"key": [
|
150
413
|
2080156050,
|
@@ -179,7 +442,8 @@
|
|
179
442
|
"file_download_url_response": {
|
180
443
|
"s": 137080,
|
181
444
|
"at": "OFTM18eQGxUTcJP2BQWXBo23vnjqs4b9QzmNZtDqekz4GZESVNiYlqKtasZqdVHN",
|
182
|
-
"g": "http://gfs262n170.userstorage.mega.co.nz/dl/
|
445
|
+
"g": "http://gfs262n170.userstorage.mega.co.nz/dl/RAS3RZCZPTWLCwLef5jWLhfjdHgnQYLqpQLb0xODrKWGcc5Og31zTYWov4dQ1xq65UUrAxOgwUvejHZshD3pBl6zybqiubp0cz_FX4FpsOuHsXVhTg",
|
446
|
+
"pfa": 1
|
183
447
|
},
|
184
448
|
"key": [
|
185
449
|
1029178532,
|
@@ -18,7 +18,8 @@ describe Megar::FileUploader do
|
|
18
18
|
[
|
19
19
|
{
|
20
20
|
upload_key: [3230625094, 2656764682, 1008836587, 1082599785, 1919494632, 3993726968],
|
21
|
-
expected_iv: 152078032723025278718811426614033776640,
|
21
|
+
# expected_iv: 152078032723025278718811426614033776640,
|
22
|
+
expected_iv: [1919494632, 3993726968, 0, 0],
|
22
23
|
expected_mac_iv: [1919494632, 3993726968,1919494632, 3993726968],
|
23
24
|
expected_mac_encryption_key: [3230625094, 2656764682, 1008836587, 1082599785]
|
24
25
|
}
|
@@ -36,11 +36,40 @@ describe Megar::Connection do
|
|
36
36
|
describe "#api_request" do
|
37
37
|
let(:data) { {} }
|
38
38
|
subject { harness.api_request(data) }
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
|
40
|
+
{
|
41
|
+
as_json: "[-15,-15,-15]",
|
42
|
+
as_error_code: "-15"
|
43
|
+
}.each do |test_name,given_response|
|
44
|
+
context "when mega error response (#{given_response})" do
|
45
|
+
it "should raise associated error" do
|
46
|
+
harness.stub(:get_api_response).and_return(given_response)
|
47
|
+
expect { subject }.to raise_error(Megar::MegaRequestError)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
{
|
53
|
+
as_broken_json: "[{,{},{}]"
|
54
|
+
}.each do |test_name,given_response|
|
55
|
+
context "when invalid JSON response (#{given_response})" do
|
56
|
+
it "should raise associated error" do
|
57
|
+
harness.stub(:get_api_response).and_return(given_response)
|
58
|
+
expect { subject }.to raise_error(Megar::BadApiResponseError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
{
|
64
|
+
as_json: { given: '[{"a":1},{"b":2}]', expect: {'a' => 1} },
|
65
|
+
as_unarray: { given: '{"a":1}', expect: {'a' => 1} }
|
66
|
+
}.each do |test_name,expectations|
|
67
|
+
context "when valid response (#{expectations[:given]})" do
|
68
|
+
before { harness.stub(:get_api_response).and_return(expectations[:given]) }
|
69
|
+
it "should not raise error" do
|
70
|
+
expect { subject }.to_not raise_error
|
71
|
+
end
|
72
|
+
it { should eql(expectations[:expect]) }
|
44
73
|
end
|
45
74
|
end
|
46
75
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Megar::Crypto::AesCtr do
|
4
|
+
let(:harness) { Megar::Crypto::AesCtr.new(options) }
|
5
|
+
let(:options) { {} }
|
6
|
+
|
7
|
+
describe "#key" do
|
8
|
+
subject { harness.key }
|
9
|
+
context "when provided as array of int" do
|
10
|
+
let(:options) { { key: [0x40404040,0x40404040,0x40404040,0x40404040] } }
|
11
|
+
it { should eql('@@@@@@@@@@@@@@@@') }
|
12
|
+
end
|
13
|
+
context "when provided as a binary string" do
|
14
|
+
let(:options) { { key: 'abcd' } }
|
15
|
+
it { should eql('abcd') }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#iv" do
|
20
|
+
subject { harness.iv }
|
21
|
+
context "when not provided" do
|
22
|
+
it { should eql([0,0,0,0]) }
|
23
|
+
end
|
24
|
+
context "when provided as array of int" do
|
25
|
+
let(:options) { { iv: [1,2,3,4] } }
|
26
|
+
it { should eql([1,2,3,4]) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Megar::Crypto::Aes do
|
4
|
+
let(:harness) { Megar::Crypto::Aes.new(options) }
|
5
|
+
let(:options) { { key: key } }
|
6
|
+
|
7
|
+
describe "#encrypt" do
|
8
|
+
subject { harness.encrypt(data) }
|
9
|
+
# expectation generation in Javascript:
|
10
|
+
# key = [0,0,0,0]
|
11
|
+
# data = [-1965633819,-2121597728,1547823083,-1677263149]
|
12
|
+
# cipher = new sjcl.cipher.aes(key)
|
13
|
+
# cipher.encrypt(data)
|
14
|
+
[
|
15
|
+
{ data: [0x93C467E3,0x7DB0C7A4,0xD1BE3F81,0x0152CB56], key: [0,0,0,0], expect: [887729479,-1472906423,407560426,1302943674] },
|
16
|
+
{ data: [887729479,-1472906423,407560426,1302943674], key: [602974403,-1330001938,-1976634718,-894142530], expect: [-19364982,-598654435,1840800477,-1490065331] }
|
17
|
+
].each do |test_case|
|
18
|
+
context "given #{test_case[:data]}" do
|
19
|
+
let(:key) { test_case[:key] }
|
20
|
+
let(:data) { test_case[:data] }
|
21
|
+
it { should eql(test_case[:expect]) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#encrypt" do
|
27
|
+
subject { harness.decrypt(data) }
|
28
|
+
# expectation generation in Javascript:
|
29
|
+
# key = prepare_key_pw('NS7j8OKCfGeEEaUK') // [1258112910,-1520042757,-243943422,-1960187198]
|
30
|
+
# data = [887729479,-1472906423,407560426,1302943674]
|
31
|
+
# cipher = new sjcl.cipher.aes(key)
|
32
|
+
# cipher.decrypt(data) // [480935216,755335218,-883525214,599824580]
|
33
|
+
[
|
34
|
+
{ data: [887729479,-1472906423,407560426,1302943674], key: [1258112910,-1520042757,-243943422,-1960187198], expect: [480935216,755335218,-883525214,599824580] },
|
35
|
+
{ data: [887729479,-1472906423,407560426,1302943674], key: [0,0,0,0], expect: [-1815844893,2108737444,-776061055,22203222] },
|
36
|
+
{ data: [-19364982,-598654435,1840800477,-1490065331], key: [602974403,-1330001938,-1976634718,-894142530], expect: [887729479,-1472906423,407560426,1302943674] },
|
37
|
+
{ data: [0x93C467E3,0x7DB0C7A4,0xD1BE3F81,0x0152CB56], key: [0,0,0,0], expect: [-1965633819,-2121597728,1547823083,-1677263149] }
|
38
|
+
].each do |test_case|
|
39
|
+
context "given #{test_case[:data]}" do
|
40
|
+
let(:key) { test_case[:key] }
|
41
|
+
let(:data) { test_case[:data] }
|
42
|
+
it { should eql(test_case[:expect]) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
class CryptoSupportTestHarness
|
4
|
-
include Megar::
|
4
|
+
include Megar::Crypto::Support
|
5
5
|
end
|
6
6
|
|
7
|
-
describe Megar::
|
7
|
+
describe Megar::Crypto::Support do
|
8
8
|
let(:harness) { CryptoSupportTestHarness.new }
|
9
9
|
|
10
10
|
describe "#crypto_requirements_met?" do
|
data/spec/unit/exception_spec.rb
CHANGED
@@ -7,7 +7,8 @@ describe "Megar Exceptions" do
|
|
7
7
|
Megar::CryptoSupportRequirementsError,
|
8
8
|
Megar::MacVerificationError,
|
9
9
|
Megar::UnsupportedFileHandleTypeError,
|
10
|
-
Megar::FileUploadError
|
10
|
+
Megar::FileUploadError,
|
11
|
+
Megar::BadApiResponseError
|
11
12
|
].each do |exception_class|
|
12
13
|
describe exception_class do
|
13
14
|
subject { raise exception_class.new("test") }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: megar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: getoptions
|
@@ -181,6 +181,8 @@ files:
|
|
181
181
|
- lib/megar/catalog/folders.rb
|
182
182
|
- lib/megar/connection.rb
|
183
183
|
- lib/megar/crypto.rb
|
184
|
+
- lib/megar/crypto/aes.rb
|
185
|
+
- lib/megar/crypto/aes_ctr.rb
|
184
186
|
- lib/megar/crypto/support.rb
|
185
187
|
- lib/megar/exception.rb
|
186
188
|
- lib/megar/session.rb
|
@@ -202,6 +204,8 @@ files:
|
|
202
204
|
- spec/unit/catalog/folder_spec.rb
|
203
205
|
- spec/unit/catalog/folders_spec.rb
|
204
206
|
- spec/unit/connection_spec.rb
|
207
|
+
- spec/unit/crypto/aes_ctr_spec.rb
|
208
|
+
- spec/unit/crypto/aes_spec.rb
|
205
209
|
- spec/unit/crypto/support_spec.rb
|
206
210
|
- spec/unit/exception_spec.rb
|
207
211
|
- spec/unit/extensions/math_spec.rb
|
@@ -247,6 +251,8 @@ test_files:
|
|
247
251
|
- spec/unit/catalog/folder_spec.rb
|
248
252
|
- spec/unit/catalog/folders_spec.rb
|
249
253
|
- spec/unit/connection_spec.rb
|
254
|
+
- spec/unit/crypto/aes_ctr_spec.rb
|
255
|
+
- spec/unit/crypto/aes_spec.rb
|
250
256
|
- spec/unit/crypto/support_spec.rb
|
251
257
|
- spec/unit/exception_spec.rb
|
252
258
|
- spec/unit/extensions/math_spec.rb
|