rmega 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -0
  3. data/CHANGELOG.md +16 -0
  4. data/README.md +1 -1
  5. data/TODO.md +3 -5
  6. data/bin/rmega-dl +47 -0
  7. data/bin/rmega-up +31 -0
  8. data/lib/rmega.rb +35 -3
  9. data/lib/rmega/api_response.rb +80 -0
  10. data/lib/rmega/cli.rb +121 -0
  11. data/lib/rmega/crypto.rb +20 -0
  12. data/lib/rmega/crypto/aes_cbc.rb +46 -0
  13. data/lib/rmega/crypto/aes_ctr.rb +15 -84
  14. data/lib/rmega/crypto/aes_ecb.rb +25 -0
  15. data/lib/rmega/crypto/rsa.rb +21 -12
  16. data/lib/rmega/errors.rb +3 -51
  17. data/lib/rmega/loggable.rb +0 -3
  18. data/lib/rmega/net.rb +56 -0
  19. data/lib/rmega/nodes/deletable.rb +0 -3
  20. data/lib/rmega/nodes/downloadable.rb +73 -30
  21. data/lib/rmega/nodes/expandable.rb +14 -10
  22. data/lib/rmega/nodes/factory.rb +30 -17
  23. data/lib/rmega/nodes/file.rb +0 -4
  24. data/lib/rmega/nodes/folder.rb +4 -14
  25. data/lib/rmega/nodes/inbox.rb +0 -2
  26. data/lib/rmega/nodes/node.rb +48 -25
  27. data/lib/rmega/nodes/node_key.rb +44 -0
  28. data/lib/rmega/nodes/root.rb +0 -4
  29. data/lib/rmega/nodes/trash.rb +0 -3
  30. data/lib/rmega/nodes/uploadable.rb +42 -33
  31. data/lib/rmega/not_inspectable.rb +10 -0
  32. data/lib/rmega/options.rb +22 -5
  33. data/lib/rmega/pool.rb +18 -7
  34. data/lib/rmega/progress.rb +53 -13
  35. data/lib/rmega/session.rb +125 -52
  36. data/lib/rmega/storage.rb +25 -21
  37. data/lib/rmega/utils.rb +23 -183
  38. data/lib/rmega/version.rb +2 -1
  39. data/rmega.gemspec +3 -5
  40. data/spec/integration/file_download_spec.rb +14 -32
  41. data/spec/integration/file_integrity_spec.rb +41 -0
  42. data/spec/integration/file_upload_spec.rb +11 -57
  43. data/spec/integration/folder_download_spec.rb +17 -0
  44. data/spec/integration/folder_operations_spec.rb +30 -30
  45. data/spec/integration/login_spec.rb +3 -3
  46. data/spec/integration/resume_download_spec.rb +53 -0
  47. data/spec/integration_spec_helper.rb +9 -4
  48. data/spec/rmega/lib/cli_spec.rb +12 -0
  49. data/spec/rmega/lib/session_spec.rb +31 -0
  50. data/spec/rmega/lib/storage_spec.rb +27 -0
  51. data/spec/rmega/lib/utils_spec.rb +16 -78
  52. data/spec/spec_helper.rb +1 -4
  53. metadata +30 -40
  54. data/lib/rmega/crypto/aes.rb +0 -35
  55. data/lib/rmega/crypto/crypto.rb +0 -107
  56. data/lib/rmega/crypto/rsa_mega.js +0 -455
  57. data/spec/rmega/lib/crypto/aes_spec.rb +0 -12
  58. data/spec/rmega/lib/crypto/crypto_spec.rb +0 -27
@@ -0,0 +1,17 @@
1
+ require 'integration_spec_helper'
2
+
3
+ describe 'Folder download' do
4
+
5
+ context 'given a public mega url (folder)' do
6
+
7
+ let(:url) { 'https://mega.co.nz/#F!IYERlQqa!pvqkX7UUsRGKBs3FWKXzUQ' }
8
+
9
+ it 'downloads the related file' do
10
+ Rmega.download(url, temp_folder)
11
+ list = Dir["#{temp_folder}/test_folder/**/*"].map do |p|
12
+ p.gsub("#{temp_folder}/test_folder/", "")
13
+ end
14
+ expect(list.sort).to eq(["a.txt", "b.txt", "c", "c/c.txt"])
15
+ end
16
+ end
17
+ end
@@ -5,57 +5,57 @@ describe 'Folders operations' do
5
5
  if account_file_exists?
6
6
 
7
7
  before(:all) do
8
- @name = "folder_#{rand.denominator}_#{rand.denominator}"
9
- @sub_folder_name = "folder_#{rand.denominator}_#{rand.denominator}"
10
8
  @storage = login
11
9
  end
12
10
 
13
- # Note: node searching is traversal
14
- def find_folder(name)
15
- @storage.nodes.find { |f| f.type == :folder && f.name == name }
16
- end
11
+ let(:name) { "test_folder" }
17
12
 
18
13
  context 'when #create_folder is called on a node' do
19
14
 
20
- it 'creates a new folder under that node' do
21
- folder = @storage.root.create_folder(@name)
22
- expect(folder.name).to eql @name
23
- expect(folder.parent_handle).to eq @storage.root.handle
15
+ before do
16
+ @folder = @storage.root.create_folder(name)
24
17
  end
25
- end
26
18
 
27
- context 'searching for a folder by its name' do
19
+ it 'creates a new folder under that node' do
20
+ expect(@folder.name).to eql name
21
+ expect(@folder.parent_handle).to eq @storage.root.handle
22
+ end
28
23
 
29
- it 'returns the matching folder' do
30
- expect(find_folder(@name).name).to eql @name
24
+ after do
25
+ @folder.delete
31
26
  end
32
27
  end
33
28
 
34
- context "when #create_folder under created folder" do
35
-
36
- it "creates a new folder under created folder" do
37
- parent_folder = find_folder(@name)
29
+ context 'searching for a folder by its handle' do
30
+ before do
31
+ @folder = @storage.root.create_folder(name)
32
+ end
38
33
 
39
- sub_folder = parent_folder.create_folder(@sub_folder_name)
34
+ it 'returns the matching folder' do
35
+ found_node = @storage.nodes.find { |n| n.handle == @folder.handle }
36
+ expect(found_node).not_to be_nil
37
+ end
40
38
 
41
- expect(parent_folder.folders.first.name).to eql @sub_folder_name
42
- expect(sub_folder.parent_handle).to eql parent_folder.handle
39
+ after do
40
+ @folder.delete
43
41
  end
44
42
  end
45
43
 
46
- context 'when #delete is called on a folder node' do
47
-
48
- it 'deletes sub folder' do
49
- expect(find_folder(@sub_folder_name).delete).to eql 0
44
+ context 'when #create_folder under created folder' do
45
+ before do
46
+ @folder = @storage.root.create_folder(name)
47
+ @sub_folder = @folder.create_folder(name)
50
48
  end
51
49
 
52
- it 'deletes the folder' do
53
- expect(find_folder(@name).delete).to eql 0
50
+ it 'creates a new folder under created folder' do
51
+ found_node = @storage.nodes.find { |n| n.handle == @sub_folder.handle }
52
+ expect(found_node.parent_handle).to eq(@folder.handle)
54
53
  end
55
54
 
56
- it 'does not find the folder (and its subfolder) anymore' do
57
- expect(find_folder(@name)).to be_nil
58
- expect(find_folder(@sub_folder_name)).to be_nil
55
+ after do
56
+ @folder.delete
57
+ found_node = @storage.nodes.find { |n| n.handle == @sub_folder.handle }
58
+ expect(found_node).to be_nil
59
59
  end
60
60
  end
61
61
  end
@@ -5,14 +5,14 @@ describe 'Login' do
5
5
  if account_file_exists?
6
6
 
7
7
  context 'when email and password are correct' do
8
- it 'returns a Storage object' do
9
- expect(login).to respond_to :nodes
8
+ it 'does not raise erorrs' do
9
+ expect { login }.not_to raise_error
10
10
  end
11
11
  end
12
12
 
13
13
  context 'when email and password are invalid' do
14
14
  it 'raises an error' do
15
- expect { Rmega.login('a@apple.com', 'b') }.to raise_error(Rmega::Errors::ServerError)
15
+ expect { Rmega.login('foo', 'bar') }.to raise_error(Rmega::ServerError)
16
16
  end
17
17
  end
18
18
  end
@@ -0,0 +1,53 @@
1
+ require 'integration_spec_helper'
2
+
3
+ module Rmega
4
+ describe 'Resumable download' do
5
+
6
+ let(:download_url) { 'https://mega.co.nz/#!NYVkDaLD!BKyN5SRpOaEtGnTcwiAqcxmJc7p-k0IPWKAW-471KRE' }
7
+
8
+ let(:destination_file) { "#{temp_folder}/temp.txt" }
9
+
10
+ before do
11
+ Thread.abort_on_exception = false
12
+ allow_any_instance_of(Pool).to receive(:threads_raises_exceptions).and_return(nil)
13
+ end
14
+
15
+ it 'resume a download of a file' do
16
+ node = Nodes::Factory.build_from_url(download_url)
17
+ content = nil
18
+
19
+ thread = Thread.new do
20
+ node.download(destination_file)
21
+ end
22
+
23
+ loop do
24
+ next unless File.exists?(destination_file)
25
+ node.file_io_synchronize { content = File.read(destination_file) }
26
+ content.strip!
27
+ break if content.size > 5_000_000
28
+ sleep(1)
29
+ end
30
+
31
+ thread.kill
32
+ sleep(1)
33
+
34
+ thread = Thread.new do
35
+ node.download(destination_file)
36
+ end
37
+
38
+ loop do
39
+ # todo: i saw this failing becausa destination_file was missing :/
40
+ node.file_io_synchronize { content = File.read(destination_file) }
41
+ content.strip!
42
+ expect(content.size).to be > 5_000_000
43
+ break if content.size >= 15_728_640
44
+ sleep(1)
45
+ end
46
+
47
+ thread.join
48
+
49
+ md5 = Digest::MD5.file(destination_file).hexdigest
50
+ expect(md5).to eq("0451dc82ac003dbef703342e40a1b8f6")
51
+ end
52
+ end
53
+ end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'yaml'
3
2
 
4
3
  def account_file_path
5
4
  File.join File.dirname(__FILE__), 'integration/rmega_account.yml'
@@ -18,10 +17,16 @@ def login
18
17
  end
19
18
 
20
19
  def temp_folder
21
- '/tmp/.rmega_spec'
20
+ Dir.tmpdir
22
21
  end
23
22
 
24
23
  RSpec.configure do |config|
25
- config.before(:all) { FileUtils.mkdir_p(temp_folder) }
26
- config.after(:all) { FileUtils.rm_rf(temp_folder) }
24
+ config.before(:all) do
25
+ Rmega.options.show_progress = false
26
+ FileUtils.mkdir_p(temp_folder)
27
+ end
28
+
29
+ config.after(:all) do
30
+ FileUtils.rm_rf(temp_folder)
31
+ end
27
32
  end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'rmega/cli'
3
+
4
+ describe Rmega::CLI::Helpers do
5
+
6
+ let(:subject) do
7
+ Class.new { include(Rmega::CLI::Helpers) }.new
8
+ end
9
+
10
+ # todo
11
+
12
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module Rmega
4
+ describe Session do
5
+ describe '#hash_password' do
6
+ { 1 => "m\xD9\xF7\xEC\xB2F\x89\xC45\xA1O|Q\xDACM",
7
+ 16 => "\x02\xBDXOzW.\x95xB\xF7O]\\\r\xD5",
8
+ 20 => "\x17\x99x\xAF\e\xE3&\xE6\xF7\x8B\f\x92\x1AY\xF9,",
9
+ }.each do |n, r|
10
+ context "when the password is #{n}-bytes long" do
11
+
12
+ let(:password) { 'a'*n }
13
+
14
+ let(:result) { r.force_encoding('BINARY') }
15
+
16
+ it 'returns the expected value' do
17
+ expect(subject.hash_password(password)).to eq(result)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ describe '#user_hash' do
24
+ it 'returns the expected value' do
25
+ string = 'sjobs@apple.com'
26
+ key = "\xCF\x8C\xF1p\xD8\xF4k\xC4\xCD\xAD\xE8M;\xF6}\x96".force_encoding('BINARY')
27
+ expect(subject.user_hash(key, string)).to eq('snWuwnlz45w')
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ module Rmega
4
+ describe Storage do
5
+
6
+ describe '#stats' do
7
+
8
+ let(:session) { Session.new }
9
+
10
+ let(:subject) { Storage.new(session) }
11
+
12
+ let(:nodes) do
13
+ [{'s' => 10, 't' => 0}, {'t' => 1}, {'s' => 5, 't' => 0}].map do |data|
14
+ Nodes::Factory.build(session, data)
15
+ end
16
+ end
17
+
18
+ before do
19
+ allow(subject).to receive(:nodes).and_return(nodes)
20
+ end
21
+
22
+ it 'returns a hash with the number of file nodes and the total size' do
23
+ expect(subject.stats).to eq(files: 2, size: 15)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,83 +1,21 @@
1
- # encoding: utf-8
2
1
  require 'spec_helper'
3
2
 
4
- describe Rmega::Utils do
5
- def random_a32_array
6
- a32_ary = []
7
- rand(0..20).times { |len| a32_ary << rand(0..2**31)*(rand(2).zero? ? 1 : -1) }
8
- a32_ary
9
- end
10
-
11
- describe '#str_to_a32' do
12
- it 'returns the expected value' do
13
- string = 'johnsnow'
14
- a32 = [1785686126, 1936617335]
15
- described_class.str_to_a32(string).should == a32
16
- end
17
-
18
- it 'returns the expected value' do
19
- string = 'sjobs@apple.com'
20
- a32 = [1936355170, 1933599088, 1886151982, 1668246784]
21
- described_class.str_to_a32(string).should == a32
22
- end
23
- end
24
-
25
- describe '#a32_to_str' do
26
- it 'returns the expected value' do
27
- a32 = [1953853537, 1660944384]
28
- string = "tupac" + "\x00\x00\x00"
29
- described_class.a32_to_str(a32).should == string
30
- end
31
-
32
- it 'is the opposite of #str_to_a32' do
33
- a32_ary = random_a32_array
34
- str = described_class.a32_to_str a32_ary
35
- described_class.str_to_a32(str).should == a32_ary
36
- end
37
-
38
- it 'has the same result if len is multiplied by 4' do
39
- a32 = random_a32_array
40
- described_class.a32_to_str(a32).should == described_class.a32_to_str(a32, a32.size*4)
41
- end
42
- end
43
-
44
- describe '#base64urlencode' do
45
- it 'returns the expected value' do
46
- string = 'ice_lord'
47
- result = 'aWNlX2xvcmQ'
48
- described_class.base64urlencode(string).should == result
49
- end
50
- end
51
-
52
- describe '#a32_to_base64' do
53
- it 'returns the expected value' do
54
- a32 = [-24267049, 354638668, -845953520, 1348163508]
55
- result = '_o221xUjW0zNk8YQUFtXtA'
56
- described_class.a32_to_base64(a32).should == result
57
- end
58
- end
59
-
60
- describe '#base64urldecode' do
61
- it 'returns the expected value' do
62
- encoded_value = "c29ycnkgaSBhbSBidXN5"
63
- result = "sorry i am busy"
64
- described_class.base64urldecode(encoded_value).should == result
65
- end
66
- end
67
-
68
- describe '#base64_to_a32' do
69
- it 'returns the expected value' do
70
- encoded_value = "YmF0dGxlc3RhciBnYWxhY3RpY2E"
71
- result = [1650553972, 1818588020, 1634869351, 1634492771, 1953063777]
72
- described_class.base64_to_a32(encoded_value).should == result
73
- end
74
- end
75
-
76
- describe '#b2s' do
77
- it 'returns the expected value' do
78
- value = [123, 213123, 321354, 5435, 4545, 23434, 6665656]
79
- result = [1706407936, 95985664, 297861121, 1404044519, 1241527304, 805306491]
80
- described_class.str_to_a32(described_class.b2s(value)).should == result
3
+ module Rmega
4
+ describe Utils do
5
+ describe '#base64urlencode' do
6
+ it 'returns the expected value' do
7
+ string = 'ice_lord'
8
+ result = 'aWNlX2xvcmQ'
9
+ expect(described_class.base64urlencode(string)).to eq(result)
10
+ end
11
+ end
12
+
13
+ describe '#base64urldecode' do
14
+ it 'returns the expected value' do
15
+ encoded_value = "c29ycnkgaSBhbSBidXN5"
16
+ result = "sorry i am busy"
17
+ expect(described_class.base64urldecode(encoded_value)).to eq(result)
18
+ end
81
19
  end
82
20
  end
83
21
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,2 @@
1
- RMEGA_LIB_PATH = File.expand_path File.join(File.dirname(__FILE__), '../lib')
2
- $: << RMEGA_LIB_PATH
3
-
4
- require 'pry'
5
1
  require 'rmega'
2
+ require 'pry'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rmega
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
- - Daniele Molteni
7
+ - topac
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-23 00:00:00.000000000 Z
11
+ date: 2015-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: httpclient
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - '>='
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: activesupport
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -80,42 +66,36 @@ dependencies:
80
66
  - - '>='
81
67
  - !ruby/object:Gem::Version
82
68
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: execjs
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - '>='
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - '>='
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
69
  description: mega.co.nz ruby api
98
70
  email:
99
71
  - dani.m.mobile@gmail.com
100
- executables: []
72
+ executables:
73
+ - rmega-dl
74
+ - rmega-up
101
75
  extensions: []
102
76
  extra_rdoc_files: []
103
77
  files:
104
78
  - .gitignore
79
+ - .travis.yml
105
80
  - CHANGELOG.md
106
81
  - Gemfile
107
82
  - LICENSE
108
83
  - README.md
109
84
  - Rakefile
110
85
  - TODO.md
86
+ - bin/rmega-dl
87
+ - bin/rmega-up
111
88
  - lib/rmega.rb
112
- - lib/rmega/crypto/aes.rb
89
+ - lib/rmega/api_response.rb
90
+ - lib/rmega/cli.rb
91
+ - lib/rmega/crypto.rb
92
+ - lib/rmega/crypto/aes_cbc.rb
113
93
  - lib/rmega/crypto/aes_ctr.rb
114
- - lib/rmega/crypto/crypto.rb
94
+ - lib/rmega/crypto/aes_ecb.rb
115
95
  - lib/rmega/crypto/rsa.rb
116
- - lib/rmega/crypto/rsa_mega.js
117
96
  - lib/rmega/errors.rb
118
97
  - lib/rmega/loggable.rb
98
+ - lib/rmega/net.rb
119
99
  - lib/rmega/nodes/deletable.rb
120
100
  - lib/rmega/nodes/downloadable.rb
121
101
  - lib/rmega/nodes/expandable.rb
@@ -124,10 +104,12 @@ files:
124
104
  - lib/rmega/nodes/folder.rb
125
105
  - lib/rmega/nodes/inbox.rb
126
106
  - lib/rmega/nodes/node.rb
107
+ - lib/rmega/nodes/node_key.rb
127
108
  - lib/rmega/nodes/root.rb
128
109
  - lib/rmega/nodes/trash.rb
129
110
  - lib/rmega/nodes/traversable.rb
130
111
  - lib/rmega/nodes/uploadable.rb
112
+ - lib/rmega/not_inspectable.rb
131
113
  - lib/rmega/options.rb
132
114
  - lib/rmega/pool.rb
133
115
  - lib/rmega/progress.rb
@@ -137,13 +119,17 @@ files:
137
119
  - lib/rmega/version.rb
138
120
  - rmega.gemspec
139
121
  - spec/integration/file_download_spec.rb
122
+ - spec/integration/file_integrity_spec.rb
140
123
  - spec/integration/file_upload_spec.rb
124
+ - spec/integration/folder_download_spec.rb
141
125
  - spec/integration/folder_operations_spec.rb
142
126
  - spec/integration/login_spec.rb
127
+ - spec/integration/resume_download_spec.rb
143
128
  - spec/integration/rmega_account.yml.example
144
129
  - spec/integration_spec_helper.rb
145
- - spec/rmega/lib/crypto/aes_spec.rb
146
- - spec/rmega/lib/crypto/crypto_spec.rb
130
+ - spec/rmega/lib/cli_spec.rb
131
+ - spec/rmega/lib/session_spec.rb
132
+ - spec/rmega/lib/storage_spec.rb
147
133
  - spec/rmega/lib/utils_spec.rb
148
134
  - spec/spec_helper.rb
149
135
  homepage: https://github.com/topac/rmega
@@ -166,18 +152,22 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
152
  version: '0'
167
153
  requirements: []
168
154
  rubyforge_project:
169
- rubygems_version: 2.0.14
155
+ rubygems_version: 2.4.5
170
156
  signing_key:
171
157
  specification_version: 4
172
158
  summary: mega.co.nz ruby api
173
159
  test_files:
174
160
  - spec/integration/file_download_spec.rb
161
+ - spec/integration/file_integrity_spec.rb
175
162
  - spec/integration/file_upload_spec.rb
163
+ - spec/integration/folder_download_spec.rb
176
164
  - spec/integration/folder_operations_spec.rb
177
165
  - spec/integration/login_spec.rb
166
+ - spec/integration/resume_download_spec.rb
178
167
  - spec/integration/rmega_account.yml.example
179
168
  - spec/integration_spec_helper.rb
180
- - spec/rmega/lib/crypto/aes_spec.rb
181
- - spec/rmega/lib/crypto/crypto_spec.rb
169
+ - spec/rmega/lib/cli_spec.rb
170
+ - spec/rmega/lib/session_spec.rb
171
+ - spec/rmega/lib/storage_spec.rb
182
172
  - spec/rmega/lib/utils_spec.rb
183
173
  - spec/spec_helper.rb