rmega 0.2.1 → 0.2.7
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 +5 -5
- data/.travis.yml +2 -0
- data/CHANGELOG.md +40 -0
- data/Dockerfile +14 -0
- data/README.md +14 -13
- data/bin/rmega-dl +35 -8
- data/bin/rmega-up +9 -1
- data/lib/rmega.rb +2 -0
- data/lib/rmega/api_response.rb +4 -1
- data/lib/rmega/cli.rb +23 -10
- data/lib/rmega/crypto/aes_cbc.rb +13 -10
- data/lib/rmega/errors.rb +10 -0
- data/lib/rmega/net.rb +19 -7
- data/lib/rmega/nodes/downloadable.rb +3 -3
- data/lib/rmega/nodes/expandable.rb +1 -1
- data/lib/rmega/nodes/factory.rb +22 -6
- data/lib/rmega/nodes/file.rb +4 -1
- data/lib/rmega/nodes/node.rb +5 -4
- data/lib/rmega/nodes/uploadable.rb +1 -1
- data/lib/rmega/progress.rb +1 -0
- data/lib/rmega/session.rb +23 -4
- data/lib/rmega/utils.rb +7 -0
- data/lib/rmega/version.rb +1 -1
- data/rmega.gemspec +5 -3
- data/spec/integration/file_upload_spec.rb +1 -1
- data/spec/integration/resume_download_spec.rb +2 -1
- data/spec/integration_spec_helper.rb +1 -1
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 48d1cd2037a5511fdc9adc693fbd1b6e74331327a3e46a93e2326a3c9aef7f42
|
4
|
+
data.tar.gz: 159cd701d79d5fdb8d903a562f01fff6a439fedb2d6efff926acf8df772182f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74c4ac1a15aeafeea21aed3dce4f17e8bdc7f82bf50608d776bc3c9df27e57ece398e8b8cf1b77d6dcd34114a020b7b1bcbcf3bdeca398da80b0ab80c3e72f39
|
7
|
+
data.tar.gz: 48a51f07da3be0c88619068afa1fc93a42d4f77dc008ddf6a5504a66aa536584e46af9e3c799fcf8f70fec44c6d31c5aabdaf74bd13257fa4910df9418c793b9
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,43 @@
|
|
1
|
+
## 0.2.7
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
* Add support for login ver. 2 (newer accounts only)
|
5
|
+
* Add new error codes
|
6
|
+
* Fixed crash when uploading file with invalid UTF-8 characters
|
7
|
+
|
8
|
+
## 0.2.6
|
9
|
+
|
10
|
+
### New Features
|
11
|
+
* Support new links format, e.g. `https://mega.nz/#!foo!bar` is now `https://mega.nz/file/foo#bar`
|
12
|
+
* Add `--get-link` flag to `rmega-up`: generate and print the sharable link of the new file
|
13
|
+
|
14
|
+
## 0.2.5
|
15
|
+
|
16
|
+
### Changes
|
17
|
+
* \#27 The error raised when the free quota is exceeded is now properly handled
|
18
|
+
* \#27 Improved detection of mega link when a generic url is given to ```rmega-dl``` (see cmd line usage)
|
19
|
+
|
20
|
+
## 0.2.4
|
21
|
+
|
22
|
+
### Changes
|
23
|
+
* \#25 Fix connection reset on file upload
|
24
|
+
* \#24 Speed up aes_cbc_mac func
|
25
|
+
|
26
|
+
## 0.2.3
|
27
|
+
|
28
|
+
### Changes
|
29
|
+
* Fixed reading options from the configuration file (~/.rmega)
|
30
|
+
* The max number of parallel threads is now 8
|
31
|
+
|
32
|
+
### New Features
|
33
|
+
* If `rmega-dl` receive a local file as the main args, that file is treated as a text file that must contains a list of mega links
|
34
|
+
* The download progress bar now distinguishes between allocate, verify and download phase
|
35
|
+
|
36
|
+
## 0.2.2
|
37
|
+
|
38
|
+
### Changes
|
39
|
+
* \#17 Fixed download of shared folders
|
40
|
+
|
1
41
|
## 0.2.1
|
2
42
|
|
3
43
|
### New Features
|
data/Dockerfile
ADDED
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
[](https://badge.fury.io/rb/rmega)
|
2
|
+
[](https://travis-ci.org/topac/rmega)
|
3
|
+
|
4
|
+
# rmega
|
2
5
|
|
3
6
|
Pure ruby library for <img src="https://mega.co.nz/favicon.ico" alt=""/> **MEGA** [https://mega.nz/](https://mega.nz/).
|
4
7
|
Works on Linux and OSX with Ruby 1.9.3+.
|
@@ -9,22 +12,20 @@ Works on Linux and OSX with Ruby 1.9.3+.
|
|
9
12
|
gem install rmega
|
10
13
|
```
|
11
14
|
|
12
|
-
## Command
|
15
|
+
## Command Line Usage
|
16
|
+
|
17
|
+
<img src="https://i.imgur.com/3cjgp4g.gif"/>
|
13
18
|
|
14
|
-
Since version 0.2.0 you can use the commands `rmega-dl` and `rmega-up` to
|
19
|
+
Since version 0.2.0 you can use the commands `rmega-dl` and `rmega-up` to download and upload files to MEGA.
|
15
20
|
|
16
21
|
* Downloads are resumable
|
22
|
+
* You can download all the links in a given file, e.g. `rmega-dl my_links.txt`
|
23
|
+
* Scrape a web page and download all the MEGA links, e.g. `rmega-dl https://www.reddit.com/r/megalinks/foobar`
|
17
24
|
* HTTP proxy support
|
18
|
-
*
|
19
|
-
|
20
|
-
<img src="https://i.imgur.com/VVl55wj.gif"/>
|
21
|
-
|
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).
|
25
|
+
* Streaming! :beer: You can use a video player (VLC works perfectly) to play videos while downloading them
|
26
|
+
* You can use it combined with [torsocks](https://github.com/dgoulet/torsocks/) to download and upload files through the Tor network (slower)
|
26
27
|
|
27
|
-
## DSL
|
28
|
+
## DSL Usage
|
28
29
|
|
29
30
|
### Login
|
30
31
|
|
@@ -88,7 +89,7 @@ end
|
|
88
89
|
folder.download("~/Downloads/my_folder")
|
89
90
|
|
90
91
|
# Download a file by url
|
91
|
-
|
92
|
+
public_url = 'https://mega.nz/file/MAkg2Iab#bc9Y2U6d93IlRRKVYpcC9hLZjS4G278OPdH6nTFPDNQ'
|
92
93
|
Rmega.download(public_url, '~/Downloads')
|
93
94
|
```
|
94
95
|
|
data/bin/rmega-dl
CHANGED
@@ -16,8 +16,11 @@ OptionParser.new do |opts|
|
|
16
16
|
opts.banner << "\t#{File.basename(__FILE__)} url [options]\n"
|
17
17
|
opts.banner << "\t#{File.basename(__FILE__)} path [options]\n"
|
18
18
|
opts.banner << "Examples:\n"
|
19
|
-
opts.banner << "\t#{File.basename(__FILE__)} 'https://mega.nz/#!aBkHBKLX!
|
20
|
-
opts.banner << "\t#{File.basename(__FILE__)} https://
|
19
|
+
opts.banner << "\t#{File.basename(__FILE__)} 'https://mega.nz/#!aBkHBKLX!n4kqzbJooqcPZjN1tEJzQ4QQwskHf7YqKa'\n"
|
20
|
+
opts.banner << "\t#{File.basename(__FILE__)} https://mega.nz/file/aBkHBKLX#n4kqzbJooqcPZjN1tEJzQ4QQwskHf7YqKa\n"
|
21
|
+
opts.banner << "\t#{File.basename(__FILE__)} https://mega.nz/folder/aBkHBKLX#n4kqzbJooqcPZjN1tEJzQ4QQwskHf7YqKa\n"
|
22
|
+
opts.banner << "\t#{File.basename(__FILE__)} https://www.reddit.com/r/megalinks3\n"
|
23
|
+
opts.banner << "\t#{File.basename(__FILE__)} mylinks.txt\n"
|
21
24
|
opts.banner << "\t#{File.basename(__FILE__)} /remote/docs/myfile.txt -u email@localhost\n"
|
22
25
|
opts.banner << "Options:"
|
23
26
|
|
@@ -36,17 +39,41 @@ cli_rescue do
|
|
36
39
|
raise("Node not found - #{cli_options[:url]}") unless node
|
37
40
|
node.download(cli_options[:output] || Dir.pwd)
|
38
41
|
else
|
39
|
-
urls = [
|
42
|
+
urls = []
|
40
43
|
|
41
|
-
|
42
|
-
|
43
|
-
urls =
|
44
|
-
|
44
|
+
if mega_url?(cli_options[:url])
|
45
|
+
# a valid MEGA urls
|
46
|
+
urls = [cli_options[:url]]
|
47
|
+
else
|
48
|
+
# A text file with a list of MEGA urls (considering only files < 1 Mb)
|
49
|
+
if File.exists?(cli_options[:url])
|
50
|
+
if File.size(cli_options[:url]) < 1_000_000
|
51
|
+
File.open(cli_options[:url], "rb") do |file|
|
52
|
+
file.each_line do |line|
|
53
|
+
line.strip!
|
54
|
+
urls << line if mega_url?(line)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
else
|
59
|
+
# A link to a web page with some MEGA urls in its body
|
60
|
+
html = Rmega::Session.new.http_get_content(cli_options[:url])
|
61
|
+
|
62
|
+
urls = html.scan(Rmega::Nodes::Factory::URL_REGEXP)
|
63
|
+
urls << html.scan(Rmega::Nodes::Factory::URL_REGEXP_NEW)
|
64
|
+
urls = urls.flatten.select { |u| Rmega::Nodes::Factory.url?(u) }.uniq
|
65
|
+
|
66
|
+
if cli_options[:debug] and urls.any?
|
67
|
+
Rmega.logger.debug("#{urls.size} URL(s) founded:\n" + urls.join("\n"))
|
68
|
+
end
|
69
|
+
end
|
45
70
|
end
|
46
71
|
|
72
|
+
raise("Nothing to download") if urls.empty?
|
73
|
+
|
47
74
|
urls.each_with_index do |url, index|
|
48
75
|
node = Rmega::Nodes::Factory.build_from_url(url)
|
49
|
-
|
76
|
+
puts "[#{index+1}/#{urls.size}] #{url}" if urls.size > 1
|
50
77
|
node.download(cli_options[:output] || Dir.pwd)
|
51
78
|
end
|
52
79
|
end
|
data/bin/rmega-up
CHANGED
@@ -22,6 +22,10 @@ OptionParser.new do |opts|
|
|
22
22
|
cli_options[:remote_path] = path
|
23
23
|
}
|
24
24
|
|
25
|
+
opts.on("-l", "--get-link", "Generate and print the sharable link (witk key)") {
|
26
|
+
cli_options[:get_link] = true
|
27
|
+
}
|
28
|
+
|
25
29
|
apply_opt_parser_options(opts)
|
26
30
|
end.parse!
|
27
31
|
|
@@ -37,5 +41,9 @@ cli_rescue do
|
|
37
41
|
raise("Node not found - #{cli_options[:remote_path]}") unless node
|
38
42
|
raise("Node cannot be a file - #{cli_options[:remote_path]}") if node.type == :file
|
39
43
|
|
40
|
-
node.upload(cli_options[:path])
|
44
|
+
file = node.upload(cli_options[:path])
|
45
|
+
|
46
|
+
if cli_options[:get_link]
|
47
|
+
puts file.public_url
|
48
|
+
end
|
41
49
|
end
|
data/lib/rmega.rb
CHANGED
data/lib/rmega/api_response.rb
CHANGED
@@ -2,7 +2,7 @@ module Rmega
|
|
2
2
|
class APIResponse
|
3
3
|
attr_reader :body, :code
|
4
4
|
|
5
|
-
# Check out the error codes list at https://mega.
|
5
|
+
# Check out the error codes list at https://mega.nz/#doc (section 11)
|
6
6
|
ERRORS = {
|
7
7
|
-1 => 'An internal error has occurred. Please submit a bug report, detailing the exact circumstances in which this error occurred.',
|
8
8
|
-2 => 'You have passed invalid arguments to this command.',
|
@@ -26,6 +26,9 @@ module Rmega
|
|
26
26
|
-20 => 'Write failed',
|
27
27
|
-21 => 'Read failed',
|
28
28
|
-22 => 'Invalid application key; request not processed',
|
29
|
+
-23 => 'SSL verification failed',
|
30
|
+
-24 => 'Not enough quota',
|
31
|
+
-26 => '2FA required',
|
29
32
|
}.freeze
|
30
33
|
|
31
34
|
def initialize(http_response)
|
data/lib/rmega/cli.rb
CHANGED
@@ -6,7 +6,7 @@ module Rmega
|
|
6
6
|
module CLI
|
7
7
|
module Helpers
|
8
8
|
def cli_options
|
9
|
-
$cli_options ||=
|
9
|
+
$cli_options ||= read_configuration_file
|
10
10
|
end
|
11
11
|
|
12
12
|
def cli_prompt_password
|
@@ -27,12 +27,14 @@ module Rmega
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def read_configuration_file
|
30
|
-
return unless File.exists?(configuration_filepath)
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
return {} unless File.exists?(configuration_filepath)
|
31
|
+
|
32
|
+
opts = YAML.load_file(configuration_filepath)
|
33
|
+
opts.keys.each { |k| opts[k.to_sym] = opts.delete(k) } # symbolize_keys!
|
34
|
+
|
35
|
+
return opts
|
34
36
|
rescue Exception => ex
|
35
|
-
raise(ex)
|
37
|
+
raise(ex)
|
36
38
|
end
|
37
39
|
|
38
40
|
def apply_cli_options
|
@@ -41,11 +43,23 @@ module Rmega
|
|
41
43
|
end
|
42
44
|
Rmega.logger.level = ::Logger::DEBUG if cli_options[:debug]
|
43
45
|
Rmega.options.show_progress = true
|
46
|
+
|
47
|
+
if Thread.respond_to?(:report_on_exception) and !cli_options[:debug]
|
48
|
+
Thread.report_on_exception = false
|
49
|
+
end
|
44
50
|
end
|
45
51
|
|
46
52
|
def apply_opt_parser_options(opts)
|
47
|
-
opts.on("-t NUM", "--thread_pool_size", "Number of threads to use") { |
|
48
|
-
|
53
|
+
opts.on("-t NUM", "--thread_pool_size", "Number of threads to use [1-8], default and recommended is #{Rmega.options.thread_pool_size}") { |num|
|
54
|
+
num = num.to_i
|
55
|
+
|
56
|
+
if num <= 0
|
57
|
+
num = 1
|
58
|
+
elsif num > 8
|
59
|
+
num = 8
|
60
|
+
end
|
61
|
+
|
62
|
+
cli_options[:thread_pool_size] = num
|
49
63
|
}
|
50
64
|
|
51
65
|
opts.on("--proxy-addr ADDRESS", "Http proxy address") { |value|
|
@@ -71,7 +85,7 @@ module Rmega
|
|
71
85
|
opts.on("-v", "--version", "Print the version number") {
|
72
86
|
puts Rmega::VERSION
|
73
87
|
puts Rmega::HOMEPAGE
|
74
|
-
exit
|
88
|
+
exit(0)
|
75
89
|
}
|
76
90
|
end
|
77
91
|
|
@@ -99,7 +113,6 @@ module Rmega
|
|
99
113
|
end
|
100
114
|
|
101
115
|
def cli_rescue
|
102
|
-
read_configuration_file
|
103
116
|
apply_cli_options
|
104
117
|
yield
|
105
118
|
rescue Interrupt
|
data/lib/rmega/crypto/aes_cbc.rb
CHANGED
@@ -28,18 +28,21 @@ module Rmega
|
|
28
28
|
cipher.iv = iv if iv
|
29
29
|
cipher.key = key
|
30
30
|
|
31
|
-
n = 0
|
32
|
-
mac = nil
|
31
|
+
# n = 0
|
32
|
+
# mac = nil
|
33
33
|
|
34
|
-
loop do
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
34
|
+
# loop do
|
35
|
+
# block = data[n..n+15]
|
36
|
+
# break if !block or block.empty?
|
37
|
+
# block << "\x0"*(16-block.size) if block.size < 16
|
38
|
+
# n += 16
|
39
|
+
# mac = cipher.update(block)
|
40
|
+
# end
|
41
41
|
|
42
|
-
return mac
|
42
|
+
# return mac
|
43
|
+
|
44
|
+
block = data + "\x0" * ((16 - data.bytesize % 16) % 16)
|
45
|
+
return cipher.update(block)[-16..-1]
|
43
46
|
end
|
44
47
|
end
|
45
48
|
end
|
data/lib/rmega/errors.rb
CHANGED
data/lib/rmega/net.rb
CHANGED
@@ -18,7 +18,13 @@ module Rmega
|
|
18
18
|
def http_get_content(url)
|
19
19
|
uri = URI(url)
|
20
20
|
req = ::Net::HTTP::Get.new(uri.request_uri)
|
21
|
-
|
21
|
+
resp = net_http(uri).request(req)
|
22
|
+
|
23
|
+
if resp.code.to_i == 509 and resp.body.to_s.empty?
|
24
|
+
raise BandwidthLimitExceeded.new
|
25
|
+
end
|
26
|
+
|
27
|
+
return resp.body
|
22
28
|
end
|
23
29
|
|
24
30
|
def http_post(url, data)
|
@@ -26,30 +32,36 @@ module Rmega
|
|
26
32
|
req = ::Net::HTTP::Post.new(uri.request_uri)
|
27
33
|
req.body = data
|
28
34
|
logger.debug("REQ POST #{url} #{cut_string(data)}")
|
29
|
-
|
35
|
+
|
36
|
+
# if you don't use Net::Http#start it will not keep the socket open even if you set
|
37
|
+
# the connection header BUT setting the connection header to 'keep-alive' its enough
|
38
|
+
# to fool MEGA servers and don't let them reset your connection!
|
39
|
+
req['Connection'] = 'keep-alive'
|
40
|
+
|
41
|
+
response = net_http(uri).request(req)
|
30
42
|
logger.debug("REP #{response.code} #{cut_string(response.body)}")
|
31
43
|
return response
|
32
44
|
end
|
33
45
|
|
34
46
|
private
|
35
47
|
|
36
|
-
def
|
48
|
+
def net_http(uri)
|
37
49
|
http = ::Net::HTTP.new(uri.host, uri.port)
|
38
50
|
http.use_ssl = true if uri.scheme == 'https'
|
39
|
-
apply_http_options(http)
|
40
|
-
return http.request(req)
|
41
|
-
end
|
42
51
|
|
43
|
-
|
52
|
+
# apply common http options
|
44
53
|
http.proxy_from_env = false if options.http_proxy_address
|
45
54
|
|
46
55
|
options.marshal_dump.each do |name, value|
|
47
56
|
setter_method = name.to_s.split('http_')[1]
|
48
57
|
http.__send__("#{setter_method}=", value) if setter_method and value
|
49
58
|
end
|
59
|
+
|
60
|
+
return http
|
50
61
|
end
|
51
62
|
|
52
63
|
def cut_string(string, max = 50)
|
64
|
+
return "<binary data, #{string.size} bytes>" if string.encoding == ::Encoding::ASCII_8BIT
|
53
65
|
string.size <= max ? string : string[0..max-1]+"..."
|
54
66
|
end
|
55
67
|
end
|
@@ -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: '
|
72
|
+
progress = Progress.new(filesize, caption: 'Allocate', filename: self.name)
|
73
73
|
pool = Pool.new
|
74
74
|
|
75
75
|
@resumed_download = allocated?(path)
|
@@ -84,12 +84,12 @@ module Rmega
|
|
84
84
|
|
85
85
|
if data
|
86
86
|
chunk_macs[start] = calculate_chunck_mac(data) if options.file_integrity_check
|
87
|
-
progress.increment(size, real: false)
|
87
|
+
progress.increment(size, real: false, caption: "Verify")
|
88
88
|
else
|
89
89
|
data = decrypt_chunk(start, download_chunk(start, size))
|
90
90
|
chunk_macs[start] = calculate_chunck_mac(data) if options.file_integrity_check
|
91
91
|
write_chunk(start, data)
|
92
|
-
progress.increment(size)
|
92
|
+
progress.increment(size, caption: "Download")
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
data/lib/rmega/nodes/factory.rb
CHANGED
@@ -16,12 +16,25 @@ module Rmega
|
|
16
16
|
module Factory
|
17
17
|
extend self
|
18
18
|
|
19
|
-
URL_REGEXP = /(
|
19
|
+
URL_REGEXP = /(https{0,1}:\/\/[w\.]*mega\.[a-z\.]+\/\#[A-Z0-9\_\-\!\=]+)/i
|
20
|
+
URL_REGEXP_NEW = /(https{0,1}:\/\/[w\.]*mega\.[a-z\.]+\/[a-z]{4,6}\/[a-z0-9\_\-\=]+\#[a-z0-9\_\-\=]+)/i
|
20
21
|
|
21
|
-
|
22
|
+
def public_handle_and_key_from_url(string)
|
23
|
+
if string.to_s =~ URL_REGEXP
|
24
|
+
public_handle, key = string.strip.split('!')[1, 2]
|
25
|
+
return [] if key and (Utils.base64urldecode(key) rescue nil).nil?
|
26
|
+
return [public_handle, key]
|
27
|
+
elsif string.to_s =~ URL_REGEXP_NEW
|
28
|
+
public_handle, key = *string.scan(/\/([^\/]+)\#(.+)$/).flatten
|
29
|
+
return [] if key and (Utils.base64urldecode(key) rescue nil).nil?
|
30
|
+
return [public_handle, key]
|
31
|
+
else
|
32
|
+
return []
|
33
|
+
end
|
34
|
+
end
|
22
35
|
|
23
36
|
def url?(string)
|
24
|
-
string.
|
37
|
+
public_handle_and_key_from_url(string).any?
|
25
38
|
end
|
26
39
|
|
27
40
|
def build(session, data)
|
@@ -30,14 +43,17 @@ module Rmega
|
|
30
43
|
end
|
31
44
|
|
32
45
|
def build_from_url(url, session = Session.new)
|
33
|
-
public_handle, key = url
|
46
|
+
public_handle, key = *public_handle_and_key_from_url(url)
|
34
47
|
|
35
48
|
raise "Invalid url or missing file key" unless key
|
36
49
|
|
37
|
-
node = if url
|
50
|
+
node = if url.include?("/folder/") or url.include?("/#F!")
|
38
51
|
nodes_data = session.request({a: 'f', c: 1, r: 1}, {n: public_handle})
|
39
52
|
session.master_key = Utils.base64urldecode(key)
|
40
|
-
session.storage.nodes = nodes_data['f'].map
|
53
|
+
session.storage.nodes = nodes_data['f'].map do |data|
|
54
|
+
data["__n"] = public_handle
|
55
|
+
Nodes::Factory.build(session, data)
|
56
|
+
end
|
41
57
|
session.storage.nodes[0]
|
42
58
|
else
|
43
59
|
data = session.request(a: 'g', g: 1, p: public_handle)
|
data/lib/rmega/nodes/file.rb
CHANGED
@@ -5,7 +5,10 @@ module Rmega
|
|
5
5
|
include Downloadable
|
6
6
|
|
7
7
|
def storage_url
|
8
|
-
@storage_url ||=
|
8
|
+
@storage_url ||= begin
|
9
|
+
query_params = data["__n"] ? {n: data["__n"]} : {}
|
10
|
+
data['g'] || request({a: 'g', g: 1, n: handle}, query_params)['g']
|
11
|
+
end
|
9
12
|
end
|
10
13
|
|
11
14
|
def size
|
data/lib/rmega/nodes/node.rb
CHANGED
@@ -21,7 +21,7 @@ module Rmega
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def public_url
|
24
|
-
@public_url ||= "https://mega.
|
24
|
+
@public_url ||= "https://mega.nz/file/#{public_handle}\##{Utils.base64urlencode(decrypted_file_key)}"
|
25
25
|
end
|
26
26
|
|
27
27
|
def public_handle
|
@@ -31,14 +31,14 @@ module Rmega
|
|
31
31
|
def serialize_attributes(hash)
|
32
32
|
str = "MEGA"
|
33
33
|
str << hash.to_json
|
34
|
-
str << ("\x00" * (16 - (str.
|
34
|
+
str << ("\x00" * (16 - (str.bytesize % 16)))
|
35
35
|
return str
|
36
36
|
end
|
37
37
|
|
38
38
|
def rename(new_name)
|
39
39
|
node_key = NodeKey.load(decrypted_file_key)
|
40
40
|
|
41
|
-
_attr = serialize_attributes(attributes.merge("n" => new_name))
|
41
|
+
_attr = serialize_attributes(attributes.merge("n" => Utils.utf8(new_name)))
|
42
42
|
_attr = aes_cbc_encrypt(node_key.aes_key, _attr)
|
43
43
|
_attr = Utils.base64urlencode(_attr)
|
44
44
|
|
@@ -138,7 +138,8 @@ module Rmega
|
|
138
138
|
elsif file_key
|
139
139
|
aes_ecb_decrypt(master_key, file_key)
|
140
140
|
else
|
141
|
-
|
141
|
+
ary = Rmega::Nodes::Factory.public_handle_and_key_from_url(public_url)
|
142
|
+
Utils.base64urldecode(ary[1])
|
142
143
|
end
|
143
144
|
end
|
144
145
|
|
@@ -69,7 +69,7 @@ module Rmega
|
|
69
69
|
pool.shutdown
|
70
70
|
|
71
71
|
# encrypt attributes
|
72
|
-
_attr = serialize_attributes(:n => ::File.basename(path))
|
72
|
+
_attr = serialize_attributes(:n => Utils.utf8(::File.basename(path)))
|
73
73
|
_attr = aes_cbc_encrypt(rnd_node_key.aes_key, _attr)
|
74
74
|
|
75
75
|
# Calculate meta_mac
|
data/lib/rmega/progress.rb
CHANGED
data/lib/rmega/session.rb
CHANGED
@@ -86,12 +86,31 @@ module Rmega
|
|
86
86
|
# * The user master_key (128 bit for AES) encrypted with the password_hash
|
87
87
|
# * The RSA private key ecrypted with the master_key
|
88
88
|
# * A brand new session_id encrypted with the RSA private key
|
89
|
-
def login(email, password)
|
89
|
+
def login(email, password)
|
90
|
+
# discover the version of the account (1: old accounts, >=2: newer accouts)
|
91
|
+
resp = request(a: 'us0', user: email.strip)
|
92
|
+
account_version = resp["v"].to_i
|
93
|
+
|
90
94
|
# Derive an hash from the user password
|
91
|
-
|
92
|
-
|
95
|
+
if account_version == 1
|
96
|
+
password_hash = hash_password(password)
|
97
|
+
u_hash = user_hash(password_hash, email.strip.downcase)
|
98
|
+
else
|
99
|
+
df2 = PBKDF2.new(
|
100
|
+
:password => password,
|
101
|
+
:salt => Utils.base64urldecode(resp['s']),
|
102
|
+
:iterations => 100000,
|
103
|
+
:hash_function => :sha512,
|
104
|
+
:key_length => 16 * 2,
|
105
|
+
).bin_string
|
106
|
+
password_hash = df2[0,16]
|
107
|
+
u_hash = Utils.base64urlencode(df2[16,32])
|
108
|
+
end
|
93
109
|
|
94
|
-
|
110
|
+
# Send the login request
|
111
|
+
req = {a: 'us', user: email.strip, uh: u_hash}
|
112
|
+
req[:sek] = Utils.base64urlencode(SecureRandom.random_bytes(16)) if account_version != 1
|
113
|
+
resp = request(req)
|
95
114
|
|
96
115
|
@master_key = aes_cbc_decrypt(password_hash, Utils.base64urldecode(resp['k']))
|
97
116
|
@rsa_privk = decrypt_rsa_private_key(resp['privk'])
|
data/lib/rmega/utils.rb
CHANGED
data/lib/rmega/version.rb
CHANGED
data/rmega.gemspec
CHANGED
@@ -3,9 +3,9 @@ require File.expand_path('../lib/rmega/version', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["topac"]
|
6
|
-
gem.email = ["
|
7
|
-
gem.description = %q{mega.
|
8
|
-
gem.summary = %q{mega.
|
6
|
+
gem.email = ["topac@users.noreply.github.com"]
|
7
|
+
gem.description = %q{mega.nz ruby api}
|
8
|
+
gem.summary = %q{mega.nz ruby api}
|
9
9
|
gem.homepage = Rmega::HOMEPAGE
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
@@ -17,6 +17,8 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.license = 'MIT'
|
18
18
|
gem.required_ruby_version = '>= 1.9.3'
|
19
19
|
|
20
|
+
gem.add_dependency "pbkdf2-ruby"
|
21
|
+
|
20
22
|
gem.add_development_dependency "pry"
|
21
23
|
gem.add_development_dependency "rspec"
|
22
24
|
gem.add_development_dependency "rake"
|
@@ -8,7 +8,8 @@ module Rmega
|
|
8
8
|
let(:destination_file) { "#{temp_folder}/temp.txt" }
|
9
9
|
|
10
10
|
before do
|
11
|
-
Thread.abort_on_exception = false
|
11
|
+
Thread.abort_on_exception = false if Thread.respond_to?(:abort_on_exception)
|
12
|
+
Thread.report_on_exception = false if Thread.respond_to?(:report_on_exception)
|
12
13
|
allow_any_instance_of(Pool).to receive(:threads_raises_exceptions).and_return(nil)
|
13
14
|
end
|
14
15
|
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rmega
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- topac
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pbkdf2-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: pry
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,9 +66,9 @@ dependencies:
|
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
55
|
-
description: mega.
|
69
|
+
description: mega.nz ruby api
|
56
70
|
email:
|
57
|
-
-
|
71
|
+
- topac@users.noreply.github.com
|
58
72
|
executables:
|
59
73
|
- rmega-dl
|
60
74
|
- rmega-up
|
@@ -64,6 +78,7 @@ files:
|
|
64
78
|
- ".gitignore"
|
65
79
|
- ".travis.yml"
|
66
80
|
- CHANGELOG.md
|
81
|
+
- Dockerfile
|
67
82
|
- Gemfile
|
68
83
|
- LICENSE
|
69
84
|
- README.md
|
@@ -138,11 +153,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
153
|
- !ruby/object:Gem::Version
|
139
154
|
version: '0'
|
140
155
|
requirements: []
|
141
|
-
|
142
|
-
rubygems_version: 2.4.6
|
156
|
+
rubygems_version: 3.1.2
|
143
157
|
signing_key:
|
144
158
|
specification_version: 4
|
145
|
-
summary: mega.
|
159
|
+
summary: mega.nz ruby api
|
146
160
|
test_files:
|
147
161
|
- spec/integration/file_download_spec.rb
|
148
162
|
- spec/integration/file_integrity_spec.rb
|