megar 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|