megar 0.0.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.
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +11 -0
- data/CHANGELOG +5 -0
- data/Gemfile +4 -0
- data/Guardfile +11 -0
- data/LICENSE +22 -0
- data/README.rdoc +218 -0
- data/Rakefile +33 -0
- data/bin/megar +16 -0
- data/lib/extensions/math.rb +13 -0
- data/lib/js_ref_impl/_README +9 -0
- data/lib/js_ref_impl/base64_1.js +83 -0
- data/lib/js_ref_impl/crypto_5.js +1795 -0
- data/lib/js_ref_impl/download_8.js +867 -0
- data/lib/js_ref_impl/hex_1.js +76 -0
- data/lib/js_ref_impl/index_9.js +666 -0
- data/lib/js_ref_impl/js.manifest +115 -0
- data/lib/js_ref_impl/rsa_1.js +456 -0
- data/lib/js_ref_impl/sjcl_1.js +1 -0
- data/lib/js_ref_impl/upload_10.js +691 -0
- data/lib/megar.rb +11 -0
- data/lib/megar/catalog.rb +5 -0
- data/lib/megar/catalog/catalog_item.rb +90 -0
- data/lib/megar/catalog/file.rb +14 -0
- data/lib/megar/catalog/files.rb +13 -0
- data/lib/megar/catalog/folder.rb +20 -0
- data/lib/megar/catalog/folders.rb +28 -0
- data/lib/megar/connection.rb +84 -0
- data/lib/megar/crypto.rb +399 -0
- data/lib/megar/exception.rb +55 -0
- data/lib/megar/session.rb +157 -0
- data/lib/megar/shell.rb +87 -0
- data/lib/megar/version.rb +3 -0
- data/megar.gemspec +30 -0
- data/spec/fixtures/crypto_expectations/sample_user.json +109 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/crypto_expectations_helper.rb +44 -0
- data/spec/support/mocks_helper.rb +22 -0
- data/spec/unit/catalog/file_spec.rb +31 -0
- data/spec/unit/catalog/files_spec.rb +26 -0
- data/spec/unit/catalog/folder_spec.rb +28 -0
- data/spec/unit/catalog/folders_spec.rb +49 -0
- data/spec/unit/connection_spec.rb +50 -0
- data/spec/unit/crypto_spec.rb +476 -0
- data/spec/unit/exception_spec.rb +35 -0
- data/spec/unit/extensions/math_spec.rb +21 -0
- data/spec/unit/session_spec.rb +146 -0
- data/spec/unit/shell_spec.rb +18 -0
- metadata +238 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Megar
|
2
|
+
|
3
|
+
# A general Megar exception
|
4
|
+
class Error < StandardError; end
|
5
|
+
|
6
|
+
class MegaRequestError < Error
|
7
|
+
|
8
|
+
# Initialise with +error_code+ returned from Mega
|
9
|
+
def initialize(error_code)
|
10
|
+
msg = case error_code
|
11
|
+
when -1
|
12
|
+
"EINTERNAL (-1): An internal error has occurred. Please submit a bug report, detailing the exact circumstances in which this error occurred."
|
13
|
+
when -2
|
14
|
+
"EARGS (-2): You have passed invalid arguments to this command."
|
15
|
+
when -3
|
16
|
+
"EAGAIN (-3) (always at the request level): A temporary congestion or server malfunction prevented your request from being processed. No data was altered. Retry. Retries must be spaced with exponential backoff."
|
17
|
+
when -4
|
18
|
+
"ERATELIMIT (-4): You have exceeded your command weight per time quota. Please wait a few seconds, then try again (this should never happen in sane real-life applications)."
|
19
|
+
when -5
|
20
|
+
"EFAILED (-5): The upload failed. Please restart it from scratch."
|
21
|
+
when -6
|
22
|
+
"ETOOMANY (-6): Too many concurrent IP addresses are accessing this upload target URL."
|
23
|
+
when -7
|
24
|
+
"ERANGE (-7): The upload file packet is out of range or not starting and ending on a chunk boundary."
|
25
|
+
when -8
|
26
|
+
"EEXPIRED (-8): The upload target URL you are trying to access has expired. Please request a fresh one."
|
27
|
+
when -9
|
28
|
+
"ENOENT (-9): Object (typically, node or user) not found"
|
29
|
+
when -10
|
30
|
+
"ECIRCULAR (-10): Circular linkage attempted"
|
31
|
+
when -11
|
32
|
+
"EACCESS (-11): Access violation (e.g., trying to write to a read-only share)"
|
33
|
+
when -12
|
34
|
+
"EEXIST (-12): Trying to create an object that already exists"
|
35
|
+
when -13
|
36
|
+
"EINCOMPLETE (-13): Trying to access an incomplete resource"
|
37
|
+
when -14
|
38
|
+
"EKEY (-14): A decryption operation failed (never returned by the API)"
|
39
|
+
when -15
|
40
|
+
"ESID (-15): Invalid or expired user session, please relogin"
|
41
|
+
when -16
|
42
|
+
"EBLOCKED (-16): User blocked"
|
43
|
+
when -17
|
44
|
+
"EOVERQUOTA (-17): Request over quota"
|
45
|
+
when -18
|
46
|
+
"ETEMPUNAVAIL (-18): Resource temporarily not available, please try again later"
|
47
|
+
else
|
48
|
+
"UNDEFINED Mega error #{error_code}"
|
49
|
+
end
|
50
|
+
super(msg)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
class Megar::Session
|
2
|
+
|
3
|
+
include Megar::Crypto
|
4
|
+
include Megar::Connection
|
5
|
+
|
6
|
+
attr_accessor :options
|
7
|
+
attr_accessor :email
|
8
|
+
attr_accessor :password
|
9
|
+
attr_accessor :master_key
|
10
|
+
attr_accessor :rsa_private_key # binary string
|
11
|
+
attr_accessor :decomposed_rsa_private_key # 4 part array of a32
|
12
|
+
|
13
|
+
# Start a new session, given +options+ hash.
|
14
|
+
#
|
15
|
+
# Required +options+ parameters:
|
16
|
+
# email: 'your email address' -- email for authentication
|
17
|
+
# password: 'your password' -- password for authentication
|
18
|
+
#
|
19
|
+
# Optional +options+ parameters:
|
20
|
+
# api_endpoint: 'url' -- talk to an alternative API endpoint
|
21
|
+
# autoconnect: true/false -- performs immediate login if true (default)
|
22
|
+
#
|
23
|
+
def initialize(options={})
|
24
|
+
default_options = { autoconnect: true }
|
25
|
+
@options = default_options.merge(options.symbolize_keys)
|
26
|
+
self.api_endpoint = @options[:api_endpoint] if @options[:api_endpoint]
|
27
|
+
connect! if @options[:autoconnect]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns authenticated/connected status
|
31
|
+
def connected?
|
32
|
+
!sid.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a pretty representation of the session object
|
36
|
+
def to_s
|
37
|
+
if connected?
|
38
|
+
"#{self.class.name}: connected as #{email}"
|
39
|
+
else
|
40
|
+
"#{self.class.name}: not connected"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Command: perform login session challenge/response.
|
45
|
+
# Establishes a user session based on the response to a cryptographic challenge.
|
46
|
+
#
|
47
|
+
def connect!
|
48
|
+
handle_login_challenge_response(get_login_response)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the user email (convenience method)
|
52
|
+
def email
|
53
|
+
@email ||= options[:email]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the user password (convenience method)
|
57
|
+
def password
|
58
|
+
@password ||= options[:password]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the rsa_private_key base64-encoded
|
62
|
+
def rsa_private_key_b64
|
63
|
+
base64urlencode(rsa_private_key)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the folder collection
|
67
|
+
def folders
|
68
|
+
refresh_files! if @folders.nil?
|
69
|
+
@folders
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the files collection
|
73
|
+
def files
|
74
|
+
refresh_files! if @files.nil?
|
75
|
+
@files
|
76
|
+
end
|
77
|
+
|
78
|
+
def refresh_files!
|
79
|
+
handle_files_response(get_files_response)
|
80
|
+
end
|
81
|
+
|
82
|
+
def reset_files!
|
83
|
+
@folders = Megar::Folders.new
|
84
|
+
@files = Megar::Files.new
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
# Command: enforces guard condition requiring authenticated connection to proceed
|
90
|
+
def ensure_connected!
|
91
|
+
raise "Not connected" unless connected?
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_login_response
|
95
|
+
api_request({'a' => 'us', 'user' => email, 'uh' => uh})
|
96
|
+
end
|
97
|
+
|
98
|
+
# Command: decrypt/decode the login +response_data+ received from Mega
|
99
|
+
#
|
100
|
+
# Javascript reference implementation: function api_getsid2(res,ctx)
|
101
|
+
#
|
102
|
+
def handle_login_challenge_response(response_data)
|
103
|
+
if k = response_data['k']
|
104
|
+
enc_master_key = base64_to_a32(k)
|
105
|
+
self.master_key = decrypt_key(enc_master_key, password_key)
|
106
|
+
end
|
107
|
+
if privk = response_data['privk']
|
108
|
+
self.rsa_private_key = decrypt_base64_to_str(privk, master_key)
|
109
|
+
self.decomposed_rsa_private_key = decompose_rsa_private_key(rsa_private_key)
|
110
|
+
if csid = response_data['csid']
|
111
|
+
self.sid = decrypt_session_id(csid,decomposed_rsa_private_key)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_files_response
|
117
|
+
ensure_connected!
|
118
|
+
api_request({'a' => 'f', 'c' => 1})
|
119
|
+
end
|
120
|
+
|
121
|
+
# Command: decrypt/decode the login +response_data+ received from Mega
|
122
|
+
#
|
123
|
+
def handle_files_response(response_data)
|
124
|
+
reset_files!
|
125
|
+
response_data['f'].each do |f|
|
126
|
+
item_attributes = {id: f['h'], payload: f.dup, type: f['t'] }
|
127
|
+
case f['t']
|
128
|
+
when 0 # File
|
129
|
+
item_attributes[:key] = k = decrypt_file_key(f)
|
130
|
+
item_attributes[:attributes] = decrypt_file_attributes(f,k)
|
131
|
+
files.add(item_attributes)
|
132
|
+
when 1 # Folder
|
133
|
+
item_attributes[:key] = k = decrypt_file_key(f)
|
134
|
+
item_attributes[:attributes] = decrypt_file_attributes(f,k)
|
135
|
+
folders.add(item_attributes)
|
136
|
+
when 2,3,4 # Root, Inbox, Trash Bin
|
137
|
+
folders.add(item_attributes)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns the encoded user password key
|
144
|
+
def password_key
|
145
|
+
prepare_key_pw(password)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns the calculated uh parameter based on email and password
|
149
|
+
#
|
150
|
+
# Javascript reference implementation: function stringhash(s,aes)
|
151
|
+
#
|
152
|
+
def uh
|
153
|
+
stringhash(email.downcase, password_key)
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
end
|
data/lib/megar/shell.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
# class that groks the megar command line options and invokes the required task
|
4
|
+
class Megar::Shell
|
5
|
+
|
6
|
+
# holds the parsed options
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
# holds the remaining command line arguments
|
10
|
+
attr_reader :args
|
11
|
+
|
12
|
+
# initializes the shell with command line argments:
|
13
|
+
#
|
14
|
+
# +options+ is expected to be the hash structure as provided by GetOptions.new(..)
|
15
|
+
#
|
16
|
+
# +args+ is the remaining command line arguments
|
17
|
+
#
|
18
|
+
def initialize(options,args)
|
19
|
+
@options = (options||{}).each{|k,v| {k => v} }
|
20
|
+
@args = args
|
21
|
+
end
|
22
|
+
|
23
|
+
# Command: execute the megar task according to the options provided on initialisation
|
24
|
+
def run
|
25
|
+
if email && password
|
26
|
+
$stderr.puts "Connecting to mega as #{email}.."
|
27
|
+
raise "Failed to connect!" unless session.connected?
|
28
|
+
case args.first
|
29
|
+
when /ls/i
|
30
|
+
session.files.each do |file|
|
31
|
+
puts file
|
32
|
+
end
|
33
|
+
else
|
34
|
+
$stderr.puts "Connected!"
|
35
|
+
end
|
36
|
+
else
|
37
|
+
usage
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# defines the valid command line options
|
42
|
+
OPTIONS = %w(help verbose email=s password=s)
|
43
|
+
|
44
|
+
class << self
|
45
|
+
|
46
|
+
# prints usage/help information
|
47
|
+
def usage
|
48
|
+
$stderr.puts <<-EOS
|
49
|
+
|
50
|
+
Megar v#{Megar::VERSION}
|
51
|
+
===================================
|
52
|
+
|
53
|
+
Usage:
|
54
|
+
megar [options] [commands]
|
55
|
+
|
56
|
+
Options:
|
57
|
+
-h | --help : shows command help
|
58
|
+
-v | --verbose : run with verbose
|
59
|
+
-e= | --email=value : email address for login
|
60
|
+
-p= | --password=value : password for login
|
61
|
+
|
62
|
+
Commands:
|
63
|
+
(none) : will perform a basic connection test only
|
64
|
+
ls : returns a full file listing
|
65
|
+
|
66
|
+
Examples:
|
67
|
+
megar --email=my@mail.com --password=MyPassword ls
|
68
|
+
megar -e my@mail.com -p MyPassword ls
|
69
|
+
|
70
|
+
EOS
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# prints usage/help information
|
75
|
+
def usage
|
76
|
+
self.class.usage
|
77
|
+
end
|
78
|
+
|
79
|
+
def session
|
80
|
+
@session ||= Megar::Session.new(email: email, password: password)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Option shortcuts
|
84
|
+
def email ; options[:email] ; end
|
85
|
+
def password ; options[:password] ; end
|
86
|
+
|
87
|
+
end
|
data/megar.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'megar/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "megar"
|
8
|
+
gem.version = Megar::VERSION
|
9
|
+
gem.authors = ["Paul Gallagher"]
|
10
|
+
gem.email = ["gallagher.paul@gmail.com"]
|
11
|
+
gem.description = %q{Megaargh! A Ruby wrapper for the Mega API (mega.co.nz)}
|
12
|
+
gem.summary = %q{A Ruby wrapper and command-line tool for the Mega API (mega.co.nz)}
|
13
|
+
gem.homepage = "https://github.com/tardate/megar"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_runtime_dependency(%q<getoptions>, [">= 0.3"])
|
21
|
+
gem.add_runtime_dependency(%q<activesupport>, [">= 3.0.3"])
|
22
|
+
|
23
|
+
gem.add_development_dependency(%q<bundler>, ["> 1.1.0"])
|
24
|
+
gem.add_development_dependency(%q<rake>, ["~> 0.9.2.2"])
|
25
|
+
gem.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
26
|
+
gem.add_development_dependency(%q<rdoc>, ["~> 3.11"])
|
27
|
+
gem.add_development_dependency(%q<guard-rspec>, ["~> 1.2.0"])
|
28
|
+
gem.add_development_dependency(%q<rb-fsevent>, ["~> 0.9.1"])
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
{
|
2
|
+
"email": "megartest@gmail.com",
|
3
|
+
"email_mixed_case": "Megartest@gmail.com",
|
4
|
+
"password": "15kMW4GiHVWFmqJJ",
|
5
|
+
"autoconnect": false,
|
6
|
+
"login_response_data": {
|
7
|
+
"csid": "CAA4by3fJFnderfxuUgwXDhQJkaxKTREaVIA4QuyKmE2CnVDP2w5pU-tftPcHvfdCoV9Gi-rTKsB11rBcc1yK1I8IVOzAwST9yUwSmZI-9Euq-FEUOCsnHYLDlykTOSisU9OU0GausJZbCCHrSLI_Q49Ndc-BBQc361W-DkZUl8ZgKCl3qleBP5aepJbR-bSTR5bJ-IxRmdf2jYUE0dz3lLMGSC4XjGBXgydFlGNgJqURpik9FrW1gPFyKESRNfxudteoSWO-f2bgD-4eEek4kHAaZZQW2K5Yb2GBXCOVQ0_7jpcRd9-gwhUHpTJETNxtEPxMEBtOtAhEm1hxXSxWZgr",
|
8
|
+
"privk": "4Iurk4vQ0BlLEEvEyaRUX8QnYzJFIedm0RVKe2pLh4wTzBBtgmafnszD_dP3Y40P-DSNLEGfWghL-0_BIW4XP8tfGNFkMg7mnYgQYC91ccz58BbhGEDf7-j97dstckf3OSSsT9D9H-cocXzyt1m231w9d7YLX23c3KAGz3vxdnl66F4jsFGO9AdIyb1KTEEt7NHkljtbz3WgWlk6W6wBawuEbJvLPHPx2L16i0iacbbkQi8ZF4pmddswMa9yWOSXwUribGDbdgx_jDGjBoKJUJI-7Aa-aOaRPEoVUTft2R2lNAVErvYwD_GIsIhQiCcJWul-KqPhI3vquvzUHd2rHHvKyTLyvXKyIDeVdBGXTaqFA2ni9xsjUNMOX14ftBZ4_fgDce0jvrZzYRs5IuOMt3K9gKMpBpUWtnlaBYbnYdL2zJuFlrM77PlcYab2uLLqlSe4hh-FxMAc_p_8tDAoU4dPgpgOpU3GRR8i7oszu_MKibzNpRBeAX1UtwKwQepjPnipu9aQlPy9OtgB-5KmGi34EcMKBPg8BN6vHRYg0Za_lk_TtTQ4WbkllAqR3Fla5-RBjzB7f3dWae4ES3VX4f-dI-UYrrKDQkqaS0R_xLaMPNG6_GQMDM7L5Fsa8I3hFjdgfs9rV4Xf_uIFrhUjm25EuT5JCdobNmwBi9VU5nCbk0LQJdrXDNYV3fmD-Y_p_KV8x_-opRnXUV03SCopOD6DhitsFtpv065QXcG1SNDu0mM-kgDh9E-QddtQQtXLLPuKFyX5o1ts08EqXTxHsZo5tIsevbExZoz9hxSRrr-V5swEDcJXoV78_k6sR3iniZ_m77JVo9QU572av2MvNhyu5YeTXyc0m6Me7cPGiO0",
|
9
|
+
"k": "GmSWkhwjjn38w8OHkD_S-A"
|
10
|
+
},
|
11
|
+
"master_key": [
|
12
|
+
384287193,
|
13
|
+
302859698,
|
14
|
+
554881366,
|
15
|
+
530403344
|
16
|
+
],
|
17
|
+
"expected_uh": "mBdCzS2yFgo",
|
18
|
+
"sid": "yfMNTyTPzUKOuWYWRO-qhXpBOEN6Q2Y5dFp3JAKn0WNBqLBEzgbaMaILNg",
|
19
|
+
"rsa_private_key_b64": "BACOQ7VCjwkiwYCKhqRRvPTMBaQ5Yx2_sszj6ILrxrTBOJ2bu-9LsOSvaGz0HpnM2lXpJg3h6QWJdlQBOhwvfeafHg7rcEaaDuUWONifv5ABpQgeoAij6cgARMvFiOdjarMvu954Eduup8PHcgfjsBSu76qpu3UqkZCpBpByAYU1oQQA1i5oxuA9i7qsXxhJRsBeceI7hZSnNYAQzsWfFD0kDW8GsJBuK-CST6oNNp0z7MQ5Qof6DZ8x9wt5ZJR43HFmD2VtTQUZLvIeemC4URuR74UWn25CETyzQdIhdNSEibaCRvi0sNwb-ikCZVxxo4-O7ZBQPw0egrQOJW06HlCQUykH_00EIoiBRcbJLS6W3nJ8KhddDf_4glZYPz6fBpqu1jIdIBGOGQf4Ttn_DmdAgkLxWF7AF6k59D45J9kxfANRJIBGSWUsI1bQBlrwFtois4O14uQkQ40Jh_d5BCrLPe599zrliGH1SsECx_xYGWcWY_GPsPa99d_St56BB9oUtDW3A1clEx2uVS8OWqRPgVimu6MXs_TEEnjWGRFofHpl_8qGeAoPbNkXsTMQb6uUK4NCYq3UzVfreByEnOqxuQcu2jlF4Ey0UH9w_KjkRyT8xu--kyZAbktYaw4EZmGUxZIlkZLk_OAGaW8KWPZhdGxjfi8K7WeZK2HtLe4At48DC_ED_20pNtkTCrB6-FQlMj6a4O2C1sE6pSdrIPofcK-HpaefOXqYKWpRM-Wnp_qHnuJgEtgodQ-pw74nXkOsVFZoJzVGCepZKoa2xhevAu3CfXMfR97LIski17PPwWV9n7yQ7onSKDmJP-q4mO7PG7LICE22WkgJkk_T1W4UkDTkCxZE_t64F6JOryg",
|
20
|
+
"decomposed_rsa_private_key": [
|
21
|
+
99901518447147034909201847419097315968297147437151469508360346463543063455874100243913856315732601845631262435262260706834732781343251117295631282035669718956849603873760427510697419513879951677293141811802298231979984193675329310799949319780256427743430868153430092107435691279045586737323088097814348379553,
|
22
|
+
150403214039042969422234539598081448727095065760827625117291927993312435808658801596490175435022631344068300286691567969167599002686861320953369584858579175145292571827741537678953851066650767421880724569960757205263834584408256907364362335186143689470541020576121430290451811639884653381769242114589063140137,
|
23
|
+
9722388475302835659981770144245473802727189238482784140772185098454692776534140965636906536278050956583642123384956999145748370323609525303581225997179041811165866787665739142915159339213277652697292051951101524711140179706280769338283140995188236373535772131640760223532777113050011892350517809489041748221890761908227035155427120665309649346176680716768795083108884918500667128372337390742180547015864208380672823661707652326881334341297176353315311938916714461230279773342086788397843164325182504213999351119600183937196301188144973390771200970801617167449547771853642668679963596445734355177856606187012189522929,
|
24
|
+
76655456251690686310715773467748134538235257990884898225079665817629234781830040448768066408365824785604130747777597240274232562744683362773774949177985094198657737800269908016421544875604264806165580741547472576851314301645952126968540259498362204011872412045782028541860398434400028332528808362023863391812
|
25
|
+
],
|
26
|
+
"files_response_data": {
|
27
|
+
"f": [
|
28
|
+
{
|
29
|
+
"h": "ewZ1GAqT",
|
30
|
+
"p": "",
|
31
|
+
"u": "zA8CzCf9tZw",
|
32
|
+
"t": 4,
|
33
|
+
"a": "",
|
34
|
+
"k": "",
|
35
|
+
"ts": 1361694312
|
36
|
+
},
|
37
|
+
{
|
38
|
+
"h": "qtBjmBTR",
|
39
|
+
"p": "",
|
40
|
+
"u": "zA8CzCf9tZw",
|
41
|
+
"t": 3,
|
42
|
+
"a": "",
|
43
|
+
"k": "",
|
44
|
+
"ts": 1361694312
|
45
|
+
},
|
46
|
+
{
|
47
|
+
"h": "ywJVFBKB",
|
48
|
+
"p": "",
|
49
|
+
"u": "zA8CzCf9tZw",
|
50
|
+
"t": 2,
|
51
|
+
"a": "",
|
52
|
+
"k": "",
|
53
|
+
"ts": 1361694312
|
54
|
+
},
|
55
|
+
{
|
56
|
+
"h": "jtwkAQaK",
|
57
|
+
"p": "ywJVFBKB",
|
58
|
+
"u": "zA8CzCf9tZw",
|
59
|
+
"t": 1,
|
60
|
+
"a": "US0wKXcni_p8dnqRvhR_Otafji3ioNJ5IsgSHB5zhOw",
|
61
|
+
"k": "zA8CzCf9tZw:4LMrqo0U-VwPGhhXV2fjQw",
|
62
|
+
"ts": 1361696928
|
63
|
+
},
|
64
|
+
{
|
65
|
+
"h": "atY1xRAb",
|
66
|
+
"p": "ywJVFBKB",
|
67
|
+
"u": "zA8CzCf9tZw",
|
68
|
+
"t": 1,
|
69
|
+
"a": "XOtY9s3EU2DypiRM2I74SS79lZaaQYQcmO4-Lekk0rw",
|
70
|
+
"k": "zA8CzCf9tZw:56VbHKn14ww22T-Xuwyjvg",
|
71
|
+
"ts": 1361696936
|
72
|
+
},
|
73
|
+
{
|
74
|
+
"h": "74ZTXbyR",
|
75
|
+
"p": "ywJVFBKB",
|
76
|
+
"u": "zA8CzCf9tZw",
|
77
|
+
"t": 0,
|
78
|
+
"a": "m9IIApZejMhZnsRy63HvhrkYh_AalPjfRYzsMpkq5-Q",
|
79
|
+
"k": "zA8CzCf9tZw:fJjggPPQGf_5MzqCuvyUGxuxVnDJLo6qBGAOwJAkOm4",
|
80
|
+
"s": 39,
|
81
|
+
"ts": 1361697187
|
82
|
+
},
|
83
|
+
{
|
84
|
+
"h": "L0xHwayA",
|
85
|
+
"p": "ywJVFBKB",
|
86
|
+
"u": "zA8CzCf9tZw",
|
87
|
+
"t": 0,
|
88
|
+
"a": "n4CazRegf4aLA4BNrdoEsqRLGLQ244NjJUJi53Zz-J4",
|
89
|
+
"k": "zA8CzCf9tZw:Iz6fsJ_qIgmS4uC4eirPnfaZOcLOoQA2t_5wTtfqp7Y",
|
90
|
+
"s": 137080,
|
91
|
+
"ts": 1361697194
|
92
|
+
}
|
93
|
+
],
|
94
|
+
"ok": [
|
95
|
+
|
96
|
+
],
|
97
|
+
"s": [
|
98
|
+
|
99
|
+
],
|
100
|
+
"u": [
|
101
|
+
{
|
102
|
+
"u": "zA8CzCf9tZw",
|
103
|
+
"c": 2,
|
104
|
+
"m": "megartest@gmail.com"
|
105
|
+
}
|
106
|
+
],
|
107
|
+
"sn": "pQ-WDyYPBHU"
|
108
|
+
}
|
109
|
+
}
|