rmega 0.1.7 → 0.2.0

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