rmega 0.2.0 → 0.2.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
  SHA1:
3
- metadata.gz: 6a223b72cd508e47946e1420769a7246fbeb0d5d
4
- data.tar.gz: 2ee6197d9a398cb44adce16f0c19aead89bbc4f2
3
+ metadata.gz: 137fdede22cdd2e053dea69f98b227700a8b606f
4
+ data.tar.gz: 49ed20b4c7b0aa5419861c59f842f5a35a2a883d
5
5
  SHA512:
6
- metadata.gz: c40f1ab57edec730541e3fe060f1f5352724a72fcff7f526ae5813ef45e53dffc08fb3d39d8b6ff393fcc233429d10232efae42fbde19c9b8081e061c0789dfc
7
- data.tar.gz: 269f261bb5d5d787540e21094c3252dff07edface5a0d899bc9c4c67a6bc9dc52fe830bd75023b456f5cf697872f77f8c0149922f939e2c9df8083ca55ffa78e
6
+ metadata.gz: 0de9a225767de5aeacb5a82629a10df8e8017bd2f49c2514904a9bb59b451d300c554ae990512644b064aa16e24a085989a16aa16a400094b1d8ef3a3c3ff652
7
+ data.tar.gz: 75d935e07f6957227d87800831efa7e07a5966cb134324798e6f5b37b4780e726f97e094d984ab5f137e002a19475fd167bb8142c5af0b4556ee6152907f7531
data/.gitignore CHANGED
@@ -22,5 +22,6 @@ tmp
22
22
  # RVM
23
23
  .rvmrc
24
24
 
25
- # Required to run integration specs
26
- spec/integration/rmega_account.yml
25
+ # Required to run some specs
26
+ account.yaml
27
+ account.yml
data/.travis.yml CHANGED
@@ -1,6 +1,9 @@
1
1
  language: ruby
2
+ sudo: false
3
+ cache: bundler
2
4
  rvm:
3
5
  - 1.9.3
4
- - 2.0.0
5
- - 2.1.2
6
- - 2.2.0
6
+ - 2.0
7
+ - 2.1
8
+ - 2.2
9
+ - ruby-head
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 0.2.1
2
+
3
+ ### New Features
4
+ * \#14 Files and folders can now be renamed with `Node#rename`
5
+
6
+ ### Changes
7
+ * `rmega-dl`, `rmega-up` commands now properly traverse the cloud storage when searching for a file/folder to download/upload
8
+ * `rmega-dl`: fixed scan for Mega links in a webpage
9
+ * The configuration file (~/.rmega) format is changed (from JSON to YAML)
10
+ * Dropped dependency to ActiveSupport
11
+
1
12
  ## 0.2.0
2
13
 
3
14
  ### New Features
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Daniele Molteni
1
+ Copyright (c) 2015 topac
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,27 +1,36 @@
1
1
  # Rmega
2
2
 
3
- A ruby library for MEGA ([https://mega.co.nz/](https://mega.co.nz/))
4
- Requirements: Ruby 1.9.3+ and OpenSSL 0.9.8r+
3
+ Pure ruby library for <img src="https://mega.co.nz/favicon.ico" alt=""/> **MEGA** [https://mega.nz/](https://mega.nz/).
4
+ Works on Linux and OSX with Ruby 1.9.3+.
5
5
 
6
+ ## Installation
6
7
 
7
- This is the result of a reverse engineering of the MEGA javascript code.
8
+ ```
9
+ gem install rmega
10
+ ```
8
11
 
12
+ ## Command line usage
9
13
 
10
- ## Installation
14
+ Since version 0.2.0 you can use the commands `rmega-dl` and `rmega-up` to easily download and upload files to MEGA.
11
15
 
12
- **Rmega** is distributed via [rubygems.org](https://rubygems.org/).
13
- If you have ruby installed system wide, just type `gem install rmega`.
16
+ * Downloads are resumable
17
+ * HTTP proxy support
18
+ * See the CHANGELOG file for more info
14
19
 
15
- ## Usage
20
+ <img src="https://i.imgur.com/VVl55wj.gif"/>
16
21
 
17
- ```ruby
18
- require 'rmega'
19
- ```
22
+ *Pro tips:*
23
+
24
+ * Streaming: you can use a video player (e.g. VLC) to play videos while downloading them.
25
+ * Super privacy: you can use it combined with [torsocks](https://github.com/dgoulet/torsocks/) to download and upload files through the Tor network (very slow).
26
+
27
+ ## DSL usage
20
28
 
21
29
  ### Login
22
30
 
23
31
  ```ruby
24
- storage = Rmega.login('your@email.com', 'your_p4ssw0rd')
32
+ require "rmega"
33
+ storage = Rmega.login("your@email.com", "your_password")
25
34
  ```
26
35
 
27
36
  ### Browsing
@@ -139,9 +148,3 @@ end
139
148
  3. Commit your changes (`git commit -am 'Added some feature'`)
140
149
  4. Push to the branch (`git push origin my-new-feature`)
141
150
  5. Create new Pull Request
142
-
143
-
144
- ## Copyright
145
-
146
- Copyright (c) 2013 Daniele Molteni
147
- MIT License
data/TODO.md CHANGED
@@ -1,5 +1,3 @@
1
1
  ## TODO
2
2
 
3
3
  * Add an option to skip mac verification and calculation (upon downloads)
4
-
5
- * Show this gif (https://i.imgur.com/VVl55wj.gif) in the readme?
data/bin/rmega-dl CHANGED
@@ -14,6 +14,11 @@ end
14
14
  OptionParser.new do |opts|
15
15
  opts.banner = "Usage:\n"
16
16
  opts.banner << "\t#{File.basename(__FILE__)} url [options]\n"
17
+ opts.banner << "\t#{File.basename(__FILE__)} path [options]\n"
18
+ opts.banner << "Examples:\n"
19
+ opts.banner << "\t#{File.basename(__FILE__)} 'https://mega.nz/#!aBkHBKLX!n4kqzbJooqc3o_s96PZjN1tEJzQ4QQwskHf7YqKa'\n"
20
+ opts.banner << "\t#{File.basename(__FILE__)} https://www.reddit.com/r/megalinks\n"
21
+ opts.banner << "\t#{File.basename(__FILE__)} /remote/docs/myfile.txt -u email@localhost\n"
17
22
  opts.banner << "Options:"
18
23
 
19
24
  opts.on("-o PATH", "--output", "Local destination path") { |path|
@@ -23,25 +28,26 @@ OptionParser.new do |opts|
23
28
  apply_opt_parser_options(opts)
24
29
  end.parse!
25
30
 
26
- rescue_errors_and_inerrupt do
27
- urls = [cli_options[:url]]
28
-
29
- unless mega_url?(cli_options[:url])
30
- urls = scan_mega_urls(Session.new.http_get_content(cli_options[:url])).uniq
31
- raise("Nothing to download") if urls.empty?
32
- end
33
-
34
- urls.each_with_index do |url, index|
35
- node = Rmega::Nodes::Factory.build_from_url(url)
36
-
37
- info = if node.type == :folder
38
- stats = node.storage.stats
39
- "(#{stats[:files]} file#{'s' if stats[:files] > 1}, #{humanize_bytes(stats[:size])})"
31
+ cli_rescue do
32
+ if cli_options[:user]
33
+ session = Rmega::Session.new.login(cli_options[:user], cli_options[:pass] || cli_prompt_password)
34
+ root = session.storage.root
35
+ node = traverse_storage(root, cli_options[:url].dup)
36
+ raise("Node not found - #{cli_options[:url]}") unless node
37
+ node.download(cli_options[:output] || Dir.pwd)
38
+ else
39
+ urls = [cli_options[:url]]
40
+
41
+ unless mega_url?(cli_options[:url])
42
+ html = Rmega::Session.new.http_get_content(cli_options[:url])
43
+ urls = html.scan(Rmega::Nodes::Factory::URL_REGEXP).flatten.uniq
44
+ raise("Nothing to download") if urls.empty?
40
45
  end
41
46
 
42
- puts "[#{index+1}/#{urls.count}] #{node.name} #{info}"
43
-
44
- path = cli_options[:output] || Dir.pwd
45
- node.download(path)
47
+ urls.each_with_index do |url, index|
48
+ node = Rmega::Nodes::Factory.build_from_url(url)
49
+ print "[#{index+1}/#{urls.size}] " if urls.size > 1
50
+ node.download(cli_options[:output] || Dir.pwd)
51
+ end
46
52
  end
47
53
  end
data/bin/rmega-up CHANGED
@@ -14,18 +14,28 @@ end
14
14
  OptionParser.new do |opts|
15
15
  opts.banner = "Usage:\n"
16
16
  opts.banner << "\t#{File.basename(__FILE__)} path [options]\n"
17
+ opts.banner << "Examples:\n"
18
+ opts.banner << "\t#{File.basename(__FILE__)} /local/file.txt -u email@localhost -r /remote/docs\n"
17
19
  opts.banner << "Options:"
18
20
 
21
+ opts.on("-r PATH", "--remote-path", "Remote path") { |path|
22
+ cli_options[:remote_path] = path
23
+ }
24
+
19
25
  apply_opt_parser_options(opts)
20
26
  end.parse!
21
27
 
22
- rescue_errors_and_inerrupt do
28
+ cli_rescue do
23
29
  raise("File not found - #{cli_options[:path]}") unless File.exists?(cli_options[:path])
24
30
 
25
31
  user = cli_options[:user] || raise("User email is required")
26
- pass = cli_options[:pass] ||= cli_prompt_password
32
+ session = Rmega::Session.new.login(user, cli_options[:pass] ||= cli_prompt_password)
27
33
 
28
- session = Rmega::Session.new.login(user, pass)
29
34
  root = session.storage.root
30
- root.upload(cli_options[:path])
35
+ node = traverse_storage(root, cli_options[:remote_path].to_s.dup, :only_folders => true)
36
+
37
+ raise("Node not found - #{cli_options[:remote_path]}") unless node
38
+ raise("Node cannot be a file - #{cli_options[:remote_path]}") if node.type == :file
39
+
40
+ node.upload(cli_options[:path])
31
41
  end
data/lib/rmega/cli.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require 'optparse'
2
2
  require 'io/console'
3
- require 'active_support/core_ext/hash'
3
+ require 'yaml'
4
4
 
5
5
  module Rmega
6
6
  module CLI
7
7
  module Helpers
8
8
  def cli_options
9
- $cli_options ||= {options: {}}
9
+ $cli_options ||= {}
10
10
  end
11
11
 
12
12
  def cli_prompt_password
@@ -18,10 +18,6 @@ module Rmega
18
18
  return password
19
19
  end
20
20
 
21
- def scan_mega_urls(text)
22
- text.to_s.scan(Nodes::Factory::URL_REGEXP).flatten.map { |s| "https://mega.co.nz/##{s}" }
23
- end
24
-
25
21
  def mega_url?(url)
26
22
  Nodes::Factory.url?(url)
27
23
  end
@@ -30,46 +26,34 @@ module Rmega
30
26
  File.expand_path('~/.rmega')
31
27
  end
32
28
 
33
- def write_configuration_file
34
- opts = {options: cli_options[:options]}
35
- if cli_options[:user]
36
- opts[:user] = cli_options[:user]
37
- opts[:pass] = cli_options[:pass] || cli_prompt_password
38
- end
39
- File.open(configuration_filepath, 'wb') { |file| file.write(opts.to_json) }
40
- FileUtils.chmod(0600, configuration_filepath)
41
- puts "Options saved into #{configuration_filepath}"
42
- end
43
-
44
29
  def read_configuration_file
45
- if File.exists?(configuration_filepath)
46
- opts = JSON.parse(File.read(configuration_filepath))
47
- $cli_options = opts.deep_symbolize_keys.deep_merge(cli_options)
48
- puts "Loaded configuration file #{configuration_filepath}" if cli_options[:debug]
49
- end
30
+ return unless File.exists?(configuration_filepath)
31
+ cli_options = YAML.load_file(configuration_filepath)
32
+ cli_options.keys.each { |k| cli_options[k.to_sym] = cli_options.delete(k) }
33
+ puts "Loaded configuration file #{configuration_filepath}" if cli_options[:debug]
50
34
  rescue Exception => ex
51
35
  raise(ex) if cli_options[:debug]
52
36
  end
53
37
 
54
38
  def apply_cli_options
55
- Rmega.logger.level = ::Logger::DEBUG if cli_options[:debug]
56
-
57
- cli_options[:options].each do |key, value|
39
+ cli_options.each do |key, value|
58
40
  Rmega.options.__send__("#{key}=", value)
59
41
  end
42
+ Rmega.logger.level = ::Logger::DEBUG if cli_options[:debug]
43
+ Rmega.options.show_progress = true
60
44
  end
61
45
 
62
46
  def apply_opt_parser_options(opts)
63
47
  opts.on("-t NUM", "--thread_pool_size", "Number of threads to use") { |n|
64
- cli_options[:options][:thread_pool_size] = n.to_i
48
+ cli_options[:thread_pool_size] = n.to_i
65
49
  }
66
50
 
67
51
  opts.on("--proxy-addr ADDRESS", "Http proxy address") { |value|
68
- cli_options[:options][:http_proxy_address] = value
52
+ cli_options[:http_proxy_address] = value
69
53
  }
70
54
 
71
55
  opts.on("--proxy-port PORT", "Http proxy port") { |value|
72
- cli_options[:options][:http_proxy_port] = value.to_i
56
+ cli_options[:http_proxy_port] = value.to_i
73
57
  }
74
58
 
75
59
  opts.on("-u", "--user USER_EMAIL", "User email address") { |value|
@@ -80,10 +64,6 @@ module Rmega
80
64
  cli_options[:pass] = value
81
65
  }
82
66
 
83
- opts.on("--write-cfg", "Write a configuration file with the given options") {
84
- cli_options[:write_cfg] = true
85
- }
86
-
87
67
  opts.on("--debug", "Debug mode") {
88
68
  cli_options[:debug] = true
89
69
  }
@@ -91,29 +71,44 @@ module Rmega
91
71
  opts.on("-v", "--version", "Print the version number") {
92
72
  puts Rmega::VERSION
93
73
  puts Rmega::HOMEPAGE
94
- exit
74
+ exit!(0)
95
75
  }
96
76
  end
97
77
 
98
- def humanize_bytes(*args)
99
- Progress.humanize_bytes(*args)
100
- end
101
-
102
- def rescue_errors_and_inerrupt(&block)
103
- if cli_options[:write_cfg]
104
- write_configuration_file
78
+ def traverse_storage(node, path, opts = {})
79
+ path.gsub!(/^\/|\/$/, "")
80
+ curr_part = path.split("/")[0] || ""
81
+ last_part = (path.split("/")[1..-1] || []).join("/")
82
+
83
+ if curr_part.empty?
84
+ if node.type == :root or node.type == :folder
85
+ return node
86
+ else
87
+ return nil
88
+ end
105
89
  else
106
- read_configuration_file
107
- apply_cli_options
108
- yield
90
+ n = node.folders.find { |n| n.name.casecmp(curr_part).zero? }
91
+ n ||= node.files.find { |n| n.name.casecmp(curr_part).zero? } unless opts[:only_folders]
92
+
93
+ if last_part.empty?
94
+ return n
95
+ else
96
+ return traverse_storage(n, last_part)
97
+ end
109
98
  end
99
+ end
100
+
101
+ def cli_rescue
102
+ read_configuration_file
103
+ apply_cli_options
104
+ yield
110
105
  rescue Interrupt
111
106
  puts "\nInterrupted"
112
107
  rescue Exception => ex
113
108
  if cli_options[:debug]
114
109
  raise(ex)
115
110
  else
116
- puts "\nError: #{ex.message}"
111
+ $stderr.puts "\nERROR: #{ex.message}"
117
112
  end
118
113
  end
119
114
  end
@@ -8,7 +8,9 @@ module Rmega
8
8
  end
9
9
 
10
10
  module Loggable
11
- extend ActiveSupport::Concern
11
+ def self.included(base)
12
+ base.__send__(:extend, ClassMethods)
13
+ end
12
14
 
13
15
  def logger
14
16
  Rmega.logger
@@ -69,7 +69,7 @@ module Rmega
69
69
  path = ::File.expand_path(path)
70
70
  path = Dir.exists?(path) ? ::File.join(path, name) : path
71
71
 
72
- progress = Progress.new(filesize, caption: 'Download')
72
+ progress = Progress.new(filesize, caption: 'Download', filename: self.name)
73
73
  pool = Pool.new
74
74
 
75
75
  @resumed_download = allocated?(path)
@@ -7,15 +7,13 @@ module Rmega
7
7
  node_key = NodeKey.random
8
8
 
9
9
  # encrypt attributes
10
- attributes_str = "MEGA"
11
- attributes_str << {n: name.strip}.to_json
12
- attributes_str << ("\x00" * (16 - (attributes_str.size % 16)))
13
- encrypted_attributes = aes_cbc_encrypt(node_key.aes_key, attributes_str)
10
+ _attr = serialize_attributes(:n => name.strip)
11
+ _attr = aes_cbc_encrypt(node_key.aes_key, _attr)
14
12
 
15
13
  # Encrypt node key
16
14
  encrypted_key = aes_ecb_encrypt(session.master_key, node_key.aes_key)
17
15
 
18
- n = [{h: 'xxxxxxxx', t: 1, a: Utils.base64urlencode(encrypted_attributes), k: Utils.base64urlencode(encrypted_key)}]
16
+ n = [{h: 'xxxxxxxx', t: 1, a: Utils.base64urlencode(_attr), k: Utils.base64urlencode(encrypted_key)}]
19
17
  data = session.request(a: 'p', t: handle, n: n)
20
18
  return Folder.new(session, data['f'][0])
21
19
  end
@@ -16,9 +16,9 @@ module Rmega
16
16
  module Factory
17
17
  extend self
18
18
 
19
- URL_REGEXP = /mega\..+\/\#([A-Z0-9\_\-\!\=]+)/i
19
+ URL_REGEXP = /(http.:\/\/[w\.]*mega\.[a-z\.]+\/\#[A-Z0-9\_\-\!\=]+)/i
20
20
 
21
- FOLDER_URL_REGEXP = /mega\..+\/\#\F([A-Z0-9\_\-\!\=]+)/i
21
+ FOLDER_URL_REGEXP = /\#\F/
22
22
 
23
23
  def url?(string)
24
24
  string.to_s =~ URL_REGEXP
@@ -8,7 +8,10 @@ module Rmega
8
8
 
9
9
  attr_reader :data, :session
10
10
 
11
- delegate :request, :shared_keys, :rsa_privk, :master_key, :storage, :to => :session
11
+ # Delegate to :session
12
+ [:request, :shared_keys, :rsa_privk, :master_key, :storage].each do |name|
13
+ __send__(:define_method, name) { |*args| session.__send__(name, *args) }
14
+ end
12
15
 
13
16
  TYPES = {0 => :file, 1 => :folder, 2 => :root, 3 => :inbox, 4 => :trash}
14
17
 
@@ -25,6 +28,30 @@ module Rmega
25
28
  @public_handle ||= request(a: 'l', n: handle)
26
29
  end
27
30
 
31
+ def serialize_attributes(hash)
32
+ str = "MEGA"
33
+ str << hash.to_json
34
+ str << ("\x00" * (16 - (str.size % 16)))
35
+ return str
36
+ end
37
+
38
+ def rename(new_name)
39
+ node_key = NodeKey.load(decrypted_file_key)
40
+
41
+ _attr = serialize_attributes(attributes.merge("n" => new_name))
42
+ _attr = aes_cbc_encrypt(node_key.aes_key, _attr)
43
+ _attr = Utils.base64urlencode(_attr)
44
+
45
+ resp = request(:a => "a", :attr => _attr, :key => Utils.base64urlencode(node_key.aes_key), :n => handle)
46
+
47
+ if resp != 0
48
+ raise("Rename failed")
49
+ else
50
+ @data['a'] = _attr
51
+ return self
52
+ end
53
+ end
54
+
28
55
  def handle
29
56
  data['h']
30
57
  end
@@ -122,7 +149,10 @@ module Rmega
122
149
  encrypted = Utils.base64urldecode(encrypted)
123
150
  encrypted.strip! if encrypted.size % 16 != 0 # Fix possible errors
124
151
  json = aes_cbc_decrypt(node_key.aes_key, encrypted)
125
- JSON.parse json.gsub(/^MEGA/, '').rstrip
152
+ # Remove invalid bytes at the end of the string
153
+ json.strip!
154
+ json.gsub!(/^MEGA\{(.+)\}.*/, '{\1}')
155
+ return JSON.parse(json)
126
156
  end
127
157
 
128
158
  def type
@@ -3,6 +3,12 @@ module Rmega
3
3
  class Root < Node
4
4
  include Expandable
5
5
  include Traversable
6
+
7
+ def download(path)
8
+ children.each do |node|
9
+ node.download(path)
10
+ end
11
+ end
6
12
  end
7
13
  end
8
14
  end
@@ -46,7 +46,7 @@ module Rmega
46
46
  pool = Pool.new
47
47
  read_mutex = Mutex.new
48
48
 
49
- progress = Progress.new(filesize, caption: 'Upload')
49
+ progress = Progress.new(filesize, caption: 'Upload', filename: ::File.basename(path))
50
50
 
51
51
  chunk_macs = {}
52
52
 
@@ -69,10 +69,8 @@ module Rmega
69
69
  pool.shutdown
70
70
 
71
71
  # encrypt attributes
72
- attributes_str = "MEGA"
73
- attributes_str << {n: ::File.basename(path)}.to_json
74
- attributes_str << ("\x00" * (16 - (attributes_str.size % 16)))
75
- encrypted_attributes = aes_cbc_encrypt(rnd_node_key.aes_key, attributes_str)
72
+ _attr = serialize_attributes(:n => ::File.basename(path))
73
+ _attr = aes_cbc_encrypt(rnd_node_key.aes_key, _attr)
76
74
 
77
75
  # Calculate meta_mac
78
76
  file_mac = aes_cbc_mac(rnd_node_key.aes_key, chunk_macs.sort.map(&:last).join, "\x0"*16)
@@ -80,7 +78,7 @@ module Rmega
80
78
  encrypted_key = aes_ecb_encrypt(session.master_key, rnd_node_key.generate)
81
79
 
82
80
  resp = request(a: 'p', t: handle, n: [
83
- {h: file_handle, t: 0, a: Utils.base64urlencode(encrypted_attributes), k: Utils.base64urlencode(encrypted_key)}
81
+ {h: file_handle, t: 0, a: Utils.base64urlencode(_attr), k: Utils.base64urlencode(encrypted_key)}
84
82
  ])
85
83
 
86
84
  return Nodes::Factory.build(session, resp['f'][0])
data/lib/rmega/options.rb CHANGED
@@ -8,7 +8,7 @@ module Rmega
8
8
  http_read_timeout: 180,
9
9
  # http_proxy_address: '127.0.0.1',
10
10
  # http_proxy_port: 8080,
11
- show_progress: true,
11
+ show_progress: false,
12
12
  file_integrity_check: true,
13
13
  api_url: 'https://eu.api.mega.co.nz/cs'
14
14
  }
@@ -19,7 +19,9 @@ module Rmega
19
19
  end
20
20
 
21
21
  module Options
22
- extend ActiveSupport::Concern
22
+ def self.included(base)
23
+ base.__send__(:extend, ClassMethods)
24
+ end
23
25
 
24
26
  def options
25
27
  Rmega.options
@@ -10,6 +10,10 @@ module Rmega
10
10
  @mutex = Mutex.new
11
11
  @start_time = Time.now
12
12
 
13
+ if show? and options[:filename]
14
+ puts options[:filename]
15
+ end
16
+
13
17
  show
14
18
  end
15
19
 
data/lib/rmega/storage.rb CHANGED
@@ -6,7 +6,10 @@ module Rmega
6
6
 
7
7
  attr_reader :session
8
8
 
9
- delegate :master_key, :shared_keys, to: :session
9
+ # Delegate to :session
10
+ [:master_key, :shared_keys].each do |name|
11
+ __send__(:define_method, name) { |*args| session.__send__(name, *args) }
12
+ end
10
13
 
11
14
  def initialize(session)
12
15
  @session = session
data/lib/rmega/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Rmega
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  HOMEPAGE = "https://github.com/topac/rmega"
4
4
  end
data/lib/rmega.rb CHANGED
@@ -6,10 +6,12 @@ require 'net/http'
6
6
  require 'base64'
7
7
  require 'openssl'
8
8
  require 'digest/md5'
9
+ require 'json'
9
10
 
10
- require 'active_support/json'
11
- require 'active_support/concern'
12
- require 'active_support/core_ext/module/delegation'
11
+ # Used only in specs
12
+ require 'yaml'
13
+ require 'tmpdir'
14
+ require 'fileutils'
13
15
 
14
16
  require 'rmega/version'
15
17
  require 'rmega/loggable'
@@ -26,11 +28,6 @@ require 'rmega/session'
26
28
  require 'rmega/storage'
27
29
  require 'rmega/nodes/factory'
28
30
 
29
- # Used only in specs
30
- require 'yaml'
31
- require 'tmpdir'
32
- require 'fileutils'
33
-
34
31
  module Rmega
35
32
  def self.login(email, password)
36
33
  Session.new.login(email, password).storage
data/rmega.gemspec CHANGED
@@ -20,6 +20,4 @@ Gem::Specification.new do |gem|
20
20
  gem.add_development_dependency "pry"
21
21
  gem.add_development_dependency "rspec"
22
22
  gem.add_development_dependency "rake"
23
-
24
- gem.add_dependency "activesupport"
25
23
  end
@@ -4,7 +4,7 @@ describe 'File download' do
4
4
 
5
5
  context 'given a public mega url (a small file)' do
6
6
 
7
- let(:url) { 'https://mega.co.nz/#!MAkg2Iab!bc9Y2U6d93IlRRKVYpcC9hLZjS4G278OPdH6nTFPDNQ' }
7
+ let(:url) { 'https://mega.nz/#!QQhADCbL!vUY_phwxvkC004t5NKx7vynL16SvFfHYFkiX5vUlgjQ' }
8
8
 
9
9
  it 'downloads the related file' do
10
10
  Rmega.download(url, temp_folder)
@@ -15,7 +15,7 @@ describe 'File download' do
15
15
 
16
16
  context 'given a public mega url (a big file)' do
17
17
 
18
- let(:url) { 'https://mega.co.nz/#!NYVkDaLD!BKyN5SRpOaEtGnTcwiAqcxmJc7p-k0IPWKAW-471KRE' }
18
+ let(:url) { 'https://mega.nz/#!oAhCnBKR!CPeG8X92nBjvFsBF9EprZNW_TqIUwItHMkF9G2IZEIo' }
19
19
 
20
20
  it 'downloads the related file' do
21
21
  Rmega.download(url, temp_folder)
@@ -1,39 +1,46 @@
1
1
  require 'integration_spec_helper'
2
2
 
3
- describe 'File integrity over upload/download operations' do
3
+ describe 'File integrity' do
4
4
 
5
- if account_file_exists?
5
+ if account?
6
6
 
7
7
  before(:all) do
8
8
  @storage = login
9
9
  end
10
10
 
11
- let(:name) { "test_file" }
11
+ context "when a file is renamed" do
12
12
 
13
- let(:path) { File.join(temp_folder, name)}
13
+ let(:path) { "#{temp_folder}/testfile_#{SecureRandom.hex(6)}" }
14
14
 
15
- [12, 1_024_000].each do |size|
15
+ let(:new_name) { "testfile_#{SecureRandom.hex(6)}" }
16
+
17
+ it 'it does not get corrupted' do
18
+ File.write(path, SecureRandom.hex(24))
19
+ file = @storage.root.upload(path)
20
+ file.rename(new_name)
21
+ expect(file.name).to eq(new_name)
22
+ file = @storage.nodes.find { |n| n.handle == file.handle }
23
+ file.delete
24
+ expect(file.name).to eq(new_name)
25
+ end
26
+ end
27
+
28
+ [12, 6_000].each do |size|
16
29
 
17
30
  context "when a file (#{size} bytes) is uploaded and then downloaded" do
18
31
 
19
- let(:content) { OpenSSL::Random.random_bytes(size) }
32
+ let(:path) { "#{temp_folder}/testfile_#{SecureRandom.hex(6)}" }
20
33
 
21
- let(:content_hash) { Digest::MD5.hexdigest(content) }
34
+ let(:content) { SecureRandom.random_bytes(size) }
22
35
 
23
- before do
24
- File.open(path, 'wb') { |f| f.write(content) }
25
- file = @storage.root.upload(path)
26
- @file = @storage.nodes.find { |n| n.handle == file.handle }
27
- expect(@file.name).to eq(name)
28
- @file.download(path+".downloaded")
29
- end
36
+ let(:content_hash) { Digest::MD5.hexdigest(content) }
30
37
 
31
38
  it 'it does not get corrupted' do
32
- expect(Digest::MD5.file(path+".downloaded").hexdigest).to eq(content_hash)
33
- end
34
-
35
- after do
36
- @file.delete if @file
39
+ File.write(path, content)
40
+ file = @storage.root.upload(path)
41
+ file.download("#{path}.downloaded")
42
+ file.delete
43
+ expect(Digest::MD5.file("#{path}.downloaded").hexdigest).to eq(content_hash)
37
44
  end
38
45
  end
39
46
  end
@@ -2,29 +2,26 @@ require 'integration_spec_helper'
2
2
 
3
3
  describe 'File upload' do
4
4
 
5
- if account_file_exists?
5
+ if account?
6
6
 
7
- before(:all) { @storage = login }
8
-
9
- let(:name) { "test_file" }
7
+ before(:all) do
8
+ @storage = login
9
+ end
10
10
 
11
- let(:path) { File.join(temp_folder, name)}
11
+ [12, 6_000].each do |size|
12
12
 
13
- [12, 1_024_000].each do |size|
14
13
  context "when a file (#{size} bytes) is uploaded" do
15
14
 
16
- before do
17
- File.open(path, 'wb') { |f| f.write(OpenSSL::Random.random_bytes(size)) }
18
- @file = @storage.root.upload(path)
19
- end
15
+ let(:path) { "#{temp_folder}/testfile_#{SecureRandom.hex(6)}" }
20
16
 
21
- it 'it can be found as a file node' do
22
- found_node = @storage.root.files.find { |f| f.handle == @file.handle }
23
- expect(found_node).not_to be_nil
24
- end
17
+ let(:content) { SecureRandom.random_bytes(size) }
25
18
 
26
- after do
27
- @file.delete if @file
19
+ it 'is found' do
20
+ File.write(path, content)
21
+ file = @storage.root.upload(path)
22
+ file = @storage.root.files.find { |f| f.handle == file.handle }
23
+ file.delete
24
+ expect(file).not_to be_nil
28
25
  end
29
26
  end
30
27
  end
@@ -4,7 +4,7 @@ describe 'Folder download' do
4
4
 
5
5
  context 'given a public mega url (folder)' do
6
6
 
7
- let(:url) { 'https://mega.co.nz/#F!IYERlQqa!pvqkX7UUsRGKBs3FWKXzUQ' }
7
+ let(:url) { 'https://mega.nz/#F!oQYEUaBD!QtYCjQDbBzefFeIM994FIg' }
8
8
 
9
9
  it 'downloads the related file' do
10
10
  Rmega.download(url, temp_folder)
@@ -2,16 +2,16 @@ require 'integration_spec_helper'
2
2
 
3
3
  describe 'Folders operations' do
4
4
 
5
- if account_file_exists?
5
+ if account?
6
6
 
7
7
  before(:all) do
8
8
  @storage = login
9
9
  end
10
10
 
11
- let(:name) { "test_folder" }
12
-
13
11
  context 'when #create_folder is called on a node' do
14
12
 
13
+ let(:name) { "testfolder_#{SecureRandom.hex(5)}" }
14
+
15
15
  before do
16
16
  @folder = @storage.root.create_folder(name)
17
17
  end
@@ -27,6 +27,9 @@ describe 'Folders operations' do
27
27
  end
28
28
 
29
29
  context 'searching for a folder by its handle' do
30
+
31
+ let(:name) { "testfolder_#{SecureRandom.hex(5)}" }
32
+
30
33
  before do
31
34
  @folder = @storage.root.create_folder(name)
32
35
  end
@@ -42,6 +45,9 @@ describe 'Folders operations' do
42
45
  end
43
46
 
44
47
  context 'when #create_folder under created folder' do
48
+
49
+ let(:name) { "testfolder_#{SecureRandom.hex(5)}" }
50
+
45
51
  before do
46
52
  @folder = @storage.root.create_folder(name)
47
53
  @sub_folder = @folder.create_folder(name)
@@ -2,7 +2,7 @@ require 'integration_spec_helper'
2
2
 
3
3
  describe 'Login' do
4
4
 
5
- if account_file_exists?
5
+ if account?
6
6
 
7
7
  context 'when email and password are correct' do
8
8
  it 'does not raise erorrs' do
@@ -3,7 +3,7 @@ require 'integration_spec_helper'
3
3
  module Rmega
4
4
  describe 'Resumable download' do
5
5
 
6
- let(:download_url) { 'https://mega.co.nz/#!NYVkDaLD!BKyN5SRpOaEtGnTcwiAqcxmJc7p-k0IPWKAW-471KRE' }
6
+ let(:download_url) { 'https://mega.nz/#!oAhCnBKR!CPeG8X92nBjvFsBF9EprZNW_TqIUwItHMkF9G2IZEIo' }
7
7
 
8
8
  let(:destination_file) { "#{temp_folder}/temp.txt" }
9
9
 
@@ -25,26 +25,14 @@ module Rmega
25
25
  node.file_io_synchronize { content = File.read(destination_file) }
26
26
  content.strip!
27
27
  break if content.size > 5_000_000
28
- sleep(1)
28
+ sleep(0.5)
29
29
  end
30
30
 
31
31
  thread.kill
32
- sleep(1)
33
32
 
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
33
+ sleep(2)
46
34
 
47
- thread.join
35
+ node.download(destination_file)
48
36
 
49
37
  md5 = Digest::MD5.file(destination_file).hexdigest
50
38
  expect(md5).to eq("0451dc82ac003dbef703342e40a1b8f6")
@@ -0,0 +1,35 @@
1
+ require 'integration_spec_helper'
2
+
3
+ describe "rmega-dl" do
4
+
5
+ let(:url) { 'https://mega.nz/#!QQhADCbL!vUY_phwxvkC004t5NKx7vynL16SvFfHYFkiX5vUlgjQ' }
6
+
7
+ def call(*args)
8
+ `bundle exec ./bin/rmega-dl #{args.join(' ')}`
9
+ end
10
+
11
+ context "without args" do
12
+
13
+ it "shows the help" do
14
+ expect(call).to match(/usage/i)
15
+ end
16
+ end
17
+
18
+ context "given a public link" do
19
+ it "downloads a file" do
20
+ call("'#{url}' -o #{temp_folder}")
21
+ downloaded_file = "#{temp_folder}/testfile.txt"
22
+ expect(File.read(downloaded_file)).to eq "helloworld!\n"
23
+ end
24
+ end
25
+
26
+ if account?
27
+ context "given an account and a path" do
28
+ it "downloads a file" do
29
+ call("/test_folder/a.txt -u #{account['email']} --pass #{account['password']} -o #{temp_folder}")
30
+ downloaded_file = "#{temp_folder}/a.txt"
31
+ expect(File.read(downloaded_file)).to eq "hello\n"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,67 @@
1
+ require 'integration_spec_helper'
2
+ require 'open3'
3
+
4
+ describe "rmega-up" do
5
+ def call(*args)
6
+ Open3.capture2e("bundle exec ./bin/rmega-up #{args.join(' ')}").join("\n")
7
+ end
8
+
9
+ let(:file_content) { SecureRandom.hex(10) }
10
+
11
+ let(:filename) { "testfile_"+SecureRandom.hex(5)+".txt" }
12
+
13
+ let(:filepath) { "#{temp_folder}/#{filename}" }
14
+
15
+ before do
16
+ File.write(filepath, file_content)
17
+ end
18
+
19
+ context "without args" do
20
+
21
+ it "shows the help" do
22
+ expect(call).to match(/usage/i)
23
+ end
24
+ end
25
+
26
+ context "without username" do
27
+ it "fails" do
28
+ expect(call(filepath)).to match(/require/i)
29
+ end
30
+ end
31
+
32
+ context "when the local file is missing" do
33
+ it "fails" do
34
+ expect(call("foobar.txt")).to match(/missing|not found/i)
35
+ end
36
+ end
37
+
38
+ if account?
39
+ context "when the remote path is missing" do
40
+ it "fails" do
41
+ resp = call("#{filepath} -u #{account['email']} --pass #{account['password']} -r /foobar")
42
+ expect(resp).to match(/error/i)
43
+ end
44
+ end
45
+
46
+ context "without specifying a remote folder" do
47
+ it "uploads a file to the root node" do
48
+ call("#{filepath} -u #{account['email']} --pass #{account['password']}")
49
+ storage = login
50
+ node = storage.root.files.find { |f| f.name == filename }
51
+ node.delete if node
52
+ expect(node).not_to be_nil
53
+ end
54
+ end
55
+
56
+ context "when specifying a remote folder" do
57
+ it "uploads a file into that folder" do
58
+ call("#{filepath} -u #{account['email']} --pass #{account['password']} -r test_folder2")
59
+ storage = login
60
+ node = storage.root.folders.find { |f| f.name == "test_folder2" }
61
+ node = node.files.find { |f| f.name == filename }
62
+ node.delete if node
63
+ expect(node).not_to be_nil
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,15 +1,21 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  def account_file_path
4
- File.join File.dirname(__FILE__), 'integration/rmega_account.yml'
4
+ File.join(File.dirname(__FILE__), "account.yaml")
5
5
  end
6
6
 
7
- def account_file_exists?
8
- File.exists? account_file_path
7
+ def account?
8
+ account
9
9
  end
10
10
 
11
11
  def account
12
- @account ||= YAML.load_file account_file_path
12
+ if ENV["MEGA_EMAIL"] and ENV["MEGA_PASSWORD"]
13
+ {'email' => ENV["MEGA_EMAIL"], 'password' => ENV["MEGA_PASSWORD"]}
14
+ elsif File.exists?(account_file_path)
15
+ YAML.load_file(account_file_path)
16
+ else
17
+ nil
18
+ end
13
19
  end
14
20
 
15
21
  def login
@@ -22,7 +28,6 @@ end
22
28
 
23
29
  RSpec.configure do |config|
24
30
  config.before(:all) do
25
- Rmega.options.show_progress = false
26
31
  FileUtils.mkdir_p(temp_folder)
27
32
  end
28
33
 
metadata CHANGED
@@ -1,69 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rmega
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - topac
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-08 00:00:00.000000000 Z
11
+ date: 2015-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: activesupport
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
- - - '>='
52
+ - - ">="
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
55
  description: mega.co.nz ruby api
@@ -75,8 +61,8 @@ executables:
75
61
  extensions: []
76
62
  extra_rdoc_files: []
77
63
  files:
78
- - .gitignore
79
- - .travis.yml
64
+ - ".gitignore"
65
+ - ".travis.yml"
80
66
  - CHANGELOG.md
81
67
  - Gemfile
82
68
  - LICENSE
@@ -125,7 +111,8 @@ files:
125
111
  - spec/integration/folder_operations_spec.rb
126
112
  - spec/integration/login_spec.rb
127
113
  - spec/integration/resume_download_spec.rb
128
- - spec/integration/rmega_account.yml.example
114
+ - spec/integration/rmega-dl_spec.rb
115
+ - spec/integration/rmega-up_spec.rb
129
116
  - spec/integration_spec_helper.rb
130
117
  - spec/rmega/lib/cli_spec.rb
131
118
  - spec/rmega/lib/session_spec.rb
@@ -142,17 +129,17 @@ require_paths:
142
129
  - lib
143
130
  required_ruby_version: !ruby/object:Gem::Requirement
144
131
  requirements:
145
- - - '>='
132
+ - - ">="
146
133
  - !ruby/object:Gem::Version
147
134
  version: 1.9.3
148
135
  required_rubygems_version: !ruby/object:Gem::Requirement
149
136
  requirements:
150
- - - '>='
137
+ - - ">="
151
138
  - !ruby/object:Gem::Version
152
139
  version: '0'
153
140
  requirements: []
154
141
  rubyforge_project:
155
- rubygems_version: 2.4.5
142
+ rubygems_version: 2.4.6
156
143
  signing_key:
157
144
  specification_version: 4
158
145
  summary: mega.co.nz ruby api
@@ -164,7 +151,8 @@ test_files:
164
151
  - spec/integration/folder_operations_spec.rb
165
152
  - spec/integration/login_spec.rb
166
153
  - spec/integration/resume_download_spec.rb
167
- - spec/integration/rmega_account.yml.example
154
+ - spec/integration/rmega-dl_spec.rb
155
+ - spec/integration/rmega-up_spec.rb
168
156
  - spec/integration_spec_helper.rb
169
157
  - spec/rmega/lib/cli_spec.rb
170
158
  - spec/rmega/lib/session_spec.rb
@@ -1,2 +0,0 @@
1
- email: insert_email_here
2
- password: insert_pass_here