Megar (“megaargh!” in pirate-speak) is a Ruby wrapper and command-line (CLI) client for the Mega API.
Megar has coverage of the basic file/folder operations: connect, get file/folder listings and details, upload and download files. Read on - the following sections provide cookbook examples for using Megar within Ruby and from the command-line.
Your help is greatly appreciated on two fronts:
Use: It needs hammering to make sure we don't have the edge-case crypto bugs.
Code: there's more interesting stuff in the API it would be nice to support. And a lot it would be nice to refactor (the priority so far has been to make it work correctly and testably, not fast or elegantly). Tuck in!
NOTE: megar no longer requires OpenSSL 1.0.1+. It is quite happy with any version that implements AES-128-CBC (commonly OpenSSL 0.9.8 or greater, which you most likely already have installed).
Requirements and Known Limitations
Consider this totally alpha at this point, especially since the Mega API has yet to be formally and fully documented.
Currently tested with MRI 1.9.3 with OpenSSL 0.9.8+
MRI 1.9.2 and 2.x, Rubinius and JRuby 1.9 modes not yet tested. No plans to support 1.8 Ruby modes.
Mega API coverage is far from complete at this point (help appreciated!). Here's the run-down:
Supported API functions:
User/session management: Complete accounts
Login session challenge/response
Retrieve file and folder nodes
Request download URL
Download file message authentication codes (MAC)
Request upload URL
Currently unsupported API functions:
User/session management: Ephemeral accounts
User/session management: Confirming accounts
Retrieve user nodes
Set node attributes
Create/delete public handle
Create/modify/delete outgoing share
Key handling - Set or request share/node keys
Retrieve user's public key
Send confirmation e-mail
Obtain user details by invitation code
Verify e-mailed confirmation code
List user sessions
User quota details
… and any other API features not explicitly listed above
The Megar Cookbook
How do I install it for normal use?
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
$ gem install megar
If you want to do a little hacking around, you can also use megar_rt to bootstrap an isolated environment and be up and running super fast.
How to start an authenticated session
The Megar::Session object is the main entry point for the library. All requests on the Mega API are made in the context of an established session.
# create a session with immediate authentication session = Megar::Session.new(email: 'email@example.com', password: 'my_password')
It's possible to delay the authentication
# create a session with deferred authentication session = Megar::Session.new(email: 'firstname.lastname@example.org', password: 'my_password', autoconnect: false ) # then explicitly login: session.connect!
How to get a listing of all folders
Folders are accessed through an authenticated Megar::Session object.
all_folders = session.folders
folders is an Enumerable collection, so you can iterate as you would expect:
puts session.folders.count session.folders.each do |folder| puts folder.name if parent_folder = folder.parent_folder puts parent_folder.name end end
The find_all_by_type can be used to find specific node types (1 == normal folder), and find_by_id method will find the first id match:
session.folders.find_all_by_type(1).first.id => "jtwkAQaK" session.folders.find_by_id("jtwkAQaK").id => "74ZTXbyR"
How to get a handle to the special Mega folders
In addition to any folders you create yourself, Mega provides three standard folders: root (“Cloud Drive”), inbox and trash. Shortcuts are available on the folders collection to grab a handle on these directly:
my_folders = session.folders my_folders.root my_folders.inbox my_folders.trash
What are all the attributes of a folder?
Once you have a folder object (e.g. session.folders.first), the following are the primary attributes it exposes:
id: the unique ID, corresponds to the Mega node handle
name: the name of the folder
parent_folder: handle to the parent folder (if one is assigned)
folders: collection of any child folders available
files: collection of any child files available
How to get a listing of all sub-folders of a folder
Folders are hierarchical, and a given folder may have a collection of sub-folders
a_folder = session.folders.first a_folder.folders.each do |folder| puts folder.name folder.parent_folder == a_folder # true! end
How to get a listing of all files in a folder
A folder node provides a files collection
session.folders.first.files.each do |file| puts file.name end
How to get a listing of all files
All files can be accessed directly without needing to navigate via a folder object.
all_files = session.files
files is an Enumerable collection, so you can iterate as you would expect:
puts session.files.count session.files.each do |file| puts file.id puts file.name puts file.size puts file.parent_folder.name end
The find_by_id method will find the first id match:
session.files.first.id => "74ZTXbyR" session.files.find_by_id("74ZTXbyR").id => "74ZTXbyR"
What are all the attributes of a file?
Once you have a file object (e.g. session.files.first), the following are the primary attributes it exposes:
id: the unique ID, corresponds to the Mega node handle
name: the name of the file
size: the size of the file content (in bytes)
parent_folder: handle to the parent folder
body: get (download) the body content of the file
How to download a file
Once you have a file object (e.g. session.files.first):
file = session.files.first file.body # returns the full decrypted body content
How to upload a file
Uploading a new file is performed using the create method of a folder of the files collection. For example:
# get a handle to the file you want to upload e.g. file_handle = Pathname.new('../path/to/my_file.png') # create the file in the root (Cloud Drive) folder: session.root.create( body: file_handle ) # or this also implicitly creates the file in the root folder: session.files.create( body: file_handle ) # or to create the file in a specific folder (e.g. 'My Images'): session.folders.find_by_name('My Images').create( body: file_handle )
The file_handle can actually be any suitable file name, Pathname or File object.
If you want to change the name of the file as stored in Mega, you can also provide a name parameter:
session.files.create( name: 'with a new name.png', body: file_handle )
Once a file has been uploaded successfully, it will also be available in the local files catalog:
session.files.create( body: file_handle, name: 'new_file.png' ) => true session.files.find_by_name('new_file.png') => returns new file catalog entry
CLI: How to use the command-line client
The gem installation includes a command-line tool. Call it without parameters and it will show help:
All operations require credentials to ba passed on the command line (email and password arguments):
$ megar --email@example.com --password=mypassword Connecting to mega as firstname.lastname@example.org.. Connected!
Note: If you just want to do a little hacking around, megar_rt is an easy way to bootstrap an isolated environment and be up and running super fast.
CLI: How to get a file listing
Use the ls command:
$ megar --email@example.com --password=mypassword ls Connecting to mega as firstname.lastname@example.org.. 39 bytes 74ZTXbyR hello_mega.txt 137080 bytes L0xHwayA mega.png
CLI: How to download a file
Use the get command:
$ megar --email@example.com --password=mypassword get L0xHwayA Connecting to mega as firstname.lastname@example.org.. Downloading L0xHwayA to mega.png..
Note: this is very simple interface at the moment:
you can only identify the file by the ID (not name)
it downloads and saves using the same name as on the server
and it doesn't check if you are overwriting a local file
CLI: How to upload a file
Use the put command:
$ megar --email@example.com --password=mypassword put ../path/to/my_file.png Connecting to mega as firstname.lastname@example.org.. Uploading my_file.png..
This uploads a file into the root folder by default, and keeps the same file name.
Standard command-line expansions work, so to upload multiple files, you can do this:
$ megar --email@example.com --password=mypassword put *.png Connecting to mega as firstname.lastname@example.org.. Uploading my_file_1.png.. Uploading my_file_2.png.. (etc for all files matching *.png)
How to run tests
Test are implemented using rspec. Run tests with rake or rake spec.
Guard is installed as part of the development dependencies, so to start continuous test execution on file change, start it up with bundle exec guard.
How to refresh unit test expectations
Unit tests make liberal use of expected responses from the actual Mega API. In order to enable good unit tests without hitting the Mega API for real, test expectations are stored as JSON under 'spec/fixtures/crypto_expectations'.
A rake task is available to re-generate the expectations:
$ rake gen:crypto_expectations email@example.com password=mypassword Generating crypto_expectations for firstname.lastname@example.org... Done! New crypto_expectations for unit test written to: /.../megar/spec/fixtures/crypto_expectations/sample_user.json
NOTE: the email and password are stored in the expectations file, so be careful not to commit and distribute credentials. Change the password on the account first. The tests will still run as intended with the snapshot of crypto details stored in the expectations file.
Checking my OpenSSL installation
Megar will fail with a warning if suitable OpenSSL support is not available. To manually check the OpenSSL version installed:
$ irb -r openssl 1.9.3p327 :001 > OpenSSL::VERSION => "1.1.0" 1.9.3p327 :002 > OpenSSL::OPENSSL_VERSION => "OpenSSL 0.9.8r 8 Feb 2011"
OK, that's fine. Note that earlier versions of megar required 1.0.1+ but that is no longer the case.
If you do need or want to install or update OpenSSL, you can install from source or rvm. On MacOSX, it is probably not a good idea to upgrade the OS-installed version (too many unintended consequences), but you can also use brew or macports to install a version in parallel.
Installing OpenSSL Using RVM:
See the rvm openssl page for details..
$ rvm pkg install openssl Fetching openssl-1.0.1c.tar.gz to ... $ rvm reinstall 1.9.3 --with-openssl-dir=$rvm_path/usr $ irb -r openssl irb(main):001:0> OpenSSL::VERSION => "1.1.0" irb(main):002:0> OpenSSL::OPENSSL_VERSION => "OpenSSL 1.0.1c 10 May 2012"
What do I do if I get an SSL certificate verification error?
Megar uses SSL to connect to mega.co.nz, and it possible you may see an SSL error like the following when you try to use it:
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
There are lots of discussion and workarounds for this problem ( google it! ) but fundamentally it is telling you that the CA certificates available to your Ruby installation are out of date. How you fix it depends on the operating system.
Here's an example of updating the CA certs for CentOS that fixes this problem for megar:
$ ls /etc/pki/tls/certs $ sudo cp /etc/pki/tls/certs/ca-bundle.crt /etc/pki/tls/certs/ca-bundle.crt.backup $ sudo curl http://curl.haxx.se/ca/cacert.pem -o /etc/pki/tls/certs/ca-bundle.crt $ sudo cp /etc/pki/tls/certs/ca-bundle.crt $rvm_path/usr/ssl/cert.pem # required location for rvm ruby
rmega - another Ruby implementation - it seems rmega came to life on a similar timeline to megar. Some different implementation decisions have been made under the covers, so I don't think we'll see these projects merge anytime soon. But that means you have more choice;-) My thanks to the rmega folks for inspiring the switch in megar from OpenSSL 1.0.1+ AES CTR implementation to a native version that works with OpenSSL 0.9.8.
Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
Fork the project
Start a feature/bugfix branch
Commit and push until you are happy with your contribution
Make sure to add tests for it. This is important so it doesn't get broken in a future version unintentionally.
Please try not to mess with the gemspec, Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so it can be cherry-picked around.
Copyright © 2013 Paul Gallagher. See LICENSE for further details.