7
7
import random
8
8
import binascii
9
9
import requests
10
- import time
11
10
import shutil
12
11
from .errors import ValidationError , RequestError
13
12
from .crypto import *
@@ -29,15 +28,15 @@ def __init__(self, options=None):
29
28
30
29
def login (self , email = None , password = None ):
31
30
if email :
32
- self .login_user (email , password )
31
+ self ._login_user (email , password )
33
32
else :
34
33
self .login_anonymous ()
35
34
return self
36
35
37
- def login_user (self , email , password ):
36
+ def _login_user (self , email , password ):
38
37
password_aes = prepare_key (str_to_a32 (password ))
39
38
uh = stringhash (email , password_aes )
40
- resp = self .api_request ({'a' : 'us' , 'user' : email , 'uh' : uh })
39
+ resp = self ._api_request ({'a' : 'us' , 'user' : email , 'uh' : uh })
41
40
#if numeric error code response
42
41
if isinstance (resp , int ):
43
42
raise RequestError (resp )
@@ -48,14 +47,14 @@ def login_anonymous(self):
48
47
password_key = [random .randint (0 , 0xFFFFFFFF )] * 4
49
48
session_self_challenge = [random .randint (0 , 0xFFFFFFFF )] * 4
50
49
51
- user = self .api_request ({
52
- 'a' : 'up' ,
53
- 'k' : a32_to_base64 (encrypt_key (master_key , password_key )),
54
- 'ts' : base64_url_encode (a32_to_str (session_self_challenge ) +
55
- a32_to_str (encrypt_key (session_self_challenge , master_key )))
50
+ user = self ._api_request ({
51
+ 'a' : 'up' ,
52
+ 'k' : a32_to_base64 (encrypt_key (master_key , password_key )),
53
+ 'ts' : base64_url_encode (a32_to_str (session_self_challenge ) +
54
+ a32_to_str (encrypt_key (session_self_challenge , master_key )))
56
55
})
57
56
58
- resp = self .api_request ({'a' : 'us' , 'user' : user })
57
+ resp = self ._api_request ({'a' : 'us' , 'user' : user })
59
58
#if numeric error code response
60
59
if isinstance (resp , int ):
61
60
raise RequestError (resp )
@@ -93,7 +92,7 @@ def _login_process(self, resp, password):
93
92
sid = binascii .unhexlify ('0' + sid if len (sid ) % 2 else sid )
94
93
self .sid = base64_url_encode (sid [:43 ])
95
94
96
- def api_request (self , data ):
95
+ def _api_request (self , data ):
97
96
params = {'id' : self .sequence_num }
98
97
self .sequence_num += 1
99
98
@@ -116,16 +115,16 @@ def api_request(self, data):
116
115
raise RequestError (json_resp )
117
116
return json_resp [0 ]
118
117
119
- def parse_url (self , url ):
118
+ def _parse_url (self , url ):
120
119
#parse file id and key from url
121
- if ( '!' in url ) :
120
+ if '!' in url :
122
121
match = re .findall (r'/#!(.*)' , url )
123
122
path = match [0 ]
124
123
return path
125
124
else :
126
125
raise RequestError ('Url key missing' )
127
126
128
- def process_file (self , file , shared_keys ):
127
+ def _process_file (self , file , shared_keys ):
129
128
"""
130
129
Process a file
131
130
"""
@@ -180,7 +179,7 @@ def process_file(self, file, shared_keys):
180
179
file ['a' ] = {'n' : 'Rubbish Bin' }
181
180
return file
182
181
183
- def init_shared_keys (self , files , shared_keys ):
182
+ def _init_shared_keys (self , files , shared_keys ):
184
183
"""
185
184
Init shared key not associated with a user.
186
185
Seems to happen when a folder is shared,
@@ -213,12 +212,12 @@ def get_files(self):
213
212
"""
214
213
Get all files in account
215
214
"""
216
- files = self .api_request ({'a' : 'f' , 'c' : 1 })
215
+ files = self ._api_request ({'a' : 'f' , 'c' : 1 })
217
216
files_dict = {}
218
217
shared_keys = {}
219
- self .init_shared_keys (files , shared_keys )
218
+ self ._init_shared_keys (files , shared_keys )
220
219
for file in files ['f' ]:
221
- processed_file = self .process_file (file , shared_keys )
220
+ processed_file = self ._process_file (file , shared_keys )
222
221
#ensure each file has a name before returning
223
222
if processed_file ['a' ]:
224
223
files_dict [file ['h' ]] = processed_file
@@ -231,7 +230,7 @@ def get_upload_link(self, file):
231
230
"""
232
231
if 'f' in file :
233
232
file = file ['f' ][0 ]
234
- public_handle = self .api_request ({'a' : 'l' , 'n' : file ['h' ]})
233
+ public_handle = self ._api_request ({'a' : 'l' , 'n' : file ['h' ]})
235
234
file_key = file ['k' ][file ['k' ].index (':' ) + 1 :]
236
235
decrypted_key = a32_to_base64 (decrypt_key (base64_to_a32 (file_key ),
237
236
self .master_key ))
@@ -249,7 +248,7 @@ def get_link(self, file):
249
248
"""
250
249
file = file [1 ]
251
250
if 'h' in file and 'k' in file :
252
- public_handle = self .api_request ({'a' : 'l' , 'n' : file ['h' ]})
251
+ public_handle = self ._api_request ({'a' : 'l' , 'n' : file ['h' ]})
253
252
if public_handle == - 11 :
254
253
raise RequestError ("Can't get a public link from that file (is this a shared file?)" )
255
254
decrypted_key = a32_to_base64 (file ['key' ])
@@ -261,7 +260,7 @@ def get_link(self, file):
261
260
raise ValidationError ('File id and key must be present' )
262
261
263
262
def get_user (self ):
264
- user_data = self .api_request ({'a' : 'ug' })
263
+ user_data = self ._api_request ({'a' : 'ug' })
265
264
return user_data
266
265
267
266
def get_node_by_type (self , type ):
@@ -275,7 +274,7 @@ def get_node_by_type(self, type):
275
274
"""
276
275
nodes = self .get_files ()
277
276
for node in nodes .items ():
278
- if ( node [1 ]['t' ] == type ) :
277
+ if node [1 ]['t' ] == type :
279
278
return node
280
279
281
280
def get_files_in_node (self , target ):
@@ -288,19 +287,19 @@ def get_files_in_node(self, target):
288
287
else :
289
288
node_id = [target ]
290
289
291
- files = self .api_request ({'a' : 'f' , 'c' : 1 })
290
+ files = self ._api_request ({'a' : 'f' , 'c' : 1 })
292
291
files_dict = {}
293
292
shared_keys = {}
294
- self .init_shared_keys (files , shared_keys )
293
+ self ._init_shared_keys (files , shared_keys )
295
294
for file in files ['f' ]:
296
- processed_file = self .process_file (file , shared_keys )
295
+ processed_file = self ._process_file (file , shared_keys )
297
296
if processed_file ['a' ] and processed_file ['p' ] == node_id [0 ]:
298
297
files_dict [file ['h' ]] = processed_file
299
298
return files_dict
300
299
301
300
def get_id_from_public_handle (self , public_handle ):
302
301
#get node data
303
- node_data = self .api_request ({'a' : 'f' , 'f' : 1 , 'p' : public_handle })
302
+ node_data = self ._api_request ({'a' : 'f' , 'f' : 1 , 'p' : public_handle })
304
303
node_id = self .get_id_from_obj (node_data )
305
304
return node_id
306
305
@@ -319,7 +318,7 @@ def get_quota(self):
319
318
"""
320
319
Get current remaining disk quota in MegaBytes
321
320
"""
322
- json_resp = self .api_request ({'a' : 'uq' , 'xfer' : 1 })
321
+ json_resp = self ._api_request ({'a' : 'uq' , 'xfer' : 1 })
323
322
#convert bytes to megabyes
324
323
return json_resp ['mstrg' ] / 1048576
325
324
@@ -340,7 +339,7 @@ def get_storage_space(self, giga=False, mega=False, kilo=False):
340
339
unit_coef = 1048576
341
340
if giga :
342
341
unit_coef = 1073741824
343
- json_resp = self .api_request ({'a' : 'uq' , 'xfer' : 1 , 'strg' : 1 })
342
+ json_resp = self ._api_request ({'a' : 'uq' , 'xfer' : 1 , 'strg' : 1 })
344
343
return {
345
344
'used' : json_resp ['cstrg' ] / unit_coef ,
346
345
'total' : json_resp ['mstrg' ] / unit_coef ,
@@ -350,7 +349,7 @@ def get_balance(self):
350
349
"""
351
350
Get account monetary balance, Pro accounts only
352
351
"""
353
- user_data = self .api_request ({"a" : "uq" , "pro" : 1 })
352
+ user_data = self ._api_request ({"a" : "uq" , "pro" : 1 })
354
353
if 'balance' in user_data :
355
354
return user_data ['balance' ]
356
355
@@ -366,7 +365,7 @@ def delete_url(self, url):
366
365
"""
367
366
Delete a file by its url
368
367
"""
369
- path = self .parse_url (url ).split ('!' )
368
+ path = self ._parse_url (url ).split ('!' )
370
369
public_handle = path [0 ]
371
370
file_id = self .get_id_from_public_handle (public_handle )
372
371
return self .move (file_id , 4 )
@@ -375,15 +374,15 @@ def destroy(self, file_id):
375
374
"""
376
375
Destroy a file by its private id
377
376
"""
378
- return self .api_request ({'a' : 'd' ,
377
+ return self ._api_request ({'a' : 'd' ,
379
378
'n' : file_id ,
380
379
'i' : self .request_id })
381
380
382
381
def destroy_url (self , url ):
383
382
"""
384
383
Destroy a file by its url
385
384
"""
386
- path = self .parse_url (url ).split ('!' )
385
+ path = self ._parse_url (url ).split ('!' )
387
386
public_handle = path [0 ]
388
387
file_id = self .get_id_from_public_handle (public_handle )
389
388
return self .destroy (file_id )
@@ -399,39 +398,39 @@ def empty_trash(self):
399
398
post_list .append ({"a" : "d" ,
400
399
"n" : file ,
401
400
"i" : self .request_id })
402
- return self .api_request (post_list )
401
+ return self ._api_request (post_list )
403
402
404
403
##########################################################################
405
404
# DOWNLOAD
406
405
def download (self , file , dest_path = None , dest_filename = None ):
407
406
"""
408
407
Download a file by it's file object
409
408
"""
410
- self .download_file (None , None , file = file [1 ], dest_path = dest_path , dest_filename = dest_filename , is_public = False )
409
+ self ._download_file (None , None , file = file [1 ], dest_path = dest_path , dest_filename = dest_filename , is_public = False )
411
410
412
411
def download_url (self , url , dest_path = None , dest_filename = None ):
413
412
"""
414
413
Download a file by it's public url
415
414
"""
416
- path = self .parse_url (url ).split ('!' )
415
+ path = self ._parse_url (url ).split ('!' )
417
416
file_id = path [0 ]
418
417
file_key = path [1 ]
419
- self .download_file (file_id , file_key , dest_path , dest_filename , is_public = True )
418
+ self ._download_file (file_id , file_key , dest_path , dest_filename , is_public = True )
420
419
421
- def download_file (self , file_handle , file_key , dest_path = None , dest_filename = None , is_public = False , file = None ):
422
- if file is None :
420
+ def _download_file (self , file_handle , file_key , dest_path = None , dest_filename = None , is_public = False , file = None ):
421
+ if file is None :
423
422
if is_public :
424
423
file_key = base64_to_a32 (file_key )
425
- file_data = self .api_request ({'a' : 'g' , 'g' : 1 , 'p' : file_handle })
424
+ file_data = self ._api_request ({'a' : 'g' , 'g' : 1 , 'p' : file_handle })
426
425
else :
427
- file_data = self .api_request ({'a' : 'g' , 'g' : 1 , 'n' : file_handle })
426
+ file_data = self ._api_request ({'a' : 'g' , 'g' : 1 , 'n' : file_handle })
428
427
429
428
k = (file_key [0 ] ^ file_key [4 ], file_key [1 ] ^ file_key [5 ],
430
429
file_key [2 ] ^ file_key [6 ], file_key [3 ] ^ file_key [7 ])
431
430
iv = file_key [4 :6 ] + (0 , 0 )
432
431
meta_mac = file_key [6 :8 ]
433
432
else :
434
- file_data = self .api_request ({'a' : 'g' , 'g' : 1 , 'n' : file ['h' ]})
433
+ file_data = self ._api_request ({'a' : 'g' , 'g' : 1 , 'n' : file ['h' ]})
435
434
k = file ['k' ]
436
435
iv = file ['iv' ]
437
436
meta_mac = file ['meta_mac' ]
@@ -518,7 +517,7 @@ def upload(self, filename, dest=None, dest_filename=None):
518
517
#request upload url, call 'u' method
519
518
input_file = open (filename , 'rb' )
520
519
file_size = os .path .getsize (filename )
521
- ul_url = self .api_request ({'a' : 'u' , 's' : file_size })['p' ]
520
+ ul_url = self ._api_request ({'a' : 'u' , 's' : file_size })['p' ]
522
521
523
522
#generate random aes key (128) for file
524
523
ul_key = [random .randint (0 , 0xFFFFFFFF ) for _ in range (6 )]
@@ -579,11 +578,11 @@ def upload(self, filename, dest=None, dest_filename=None):
579
578
ul_key [4 ], ul_key [5 ], meta_mac [0 ], meta_mac [1 ]]
580
579
encrypted_key = a32_to_base64 (encrypt_key (key , self .master_key ))
581
580
#update attributes
582
- data = self .api_request ({'a' : 'p' , 't' : dest , 'n' : [{
583
- 'h' : completion_file_handle ,
584
- 't' : 0 ,
585
- 'a' : encrypt_attribs ,
586
- 'k' : encrypted_key }]})
581
+ data = self ._api_request ({'a' : 'p' , 't' : dest , 'n' : [{
582
+ 'h' : completion_file_handle ,
583
+ 't' : 0 ,
584
+ 'a' : encrypt_attribs ,
585
+ 'k' : encrypted_key }]})
587
586
#close input file and return API msg
588
587
input_file .close ()
589
588
return data
@@ -607,7 +606,7 @@ def create_folder(self, name, dest=None):
607
606
encrypted_key = a32_to_base64 (encrypt_key (ul_key [:4 ], self .master_key ))
608
607
609
608
#update attributes
610
- data = self .api_request ({'a' : 'p' ,
609
+ data = self ._api_request ({'a' : 'p' ,
611
610
't' : dest ,
612
611
'n' : [{
613
612
'h' : 'xxxxxxxx' ,
@@ -628,7 +627,7 @@ def rename(self, file, new_name):
628
627
encrypted_key = a32_to_base64 (encrypt_key (file ['key' ], self .master_key ))
629
628
630
629
#update attributes
631
- data = self .api_request ([{
630
+ data = self ._api_request ([{
632
631
'a' : 'a' ,
633
632
'attr' : encrypt_attribs ,
634
633
'key' : encrypted_key ,
@@ -666,7 +665,7 @@ def move(self, file_id, target):
666
665
else :
667
666
file = target [1 ]
668
667
target_node_id = file ['h' ]
669
- return self .api_request ({'a' : 'm' ,
668
+ return self ._api_request ({'a' : 'm' ,
670
669
'n' : file_id ,
671
670
't' : target_node_id ,
672
671
'i' : self .request_id })
@@ -697,10 +696,10 @@ def _edit_contact(self, email, add):
697
696
if not re .match (r"[^@]+@[^@]+\.[^@]+" , email ):
698
697
ValidationError ('add_contact requires a valid email address' )
699
698
else :
700
- return self .api_request ({'a' : 'ur' ,
701
- 'u' : email ,
702
- 'l' : l ,
703
- 'i' : self .request_id })
699
+ return self ._api_request ({'a' : 'ur' ,
700
+ 'u' : email ,
701
+ 'l' : l ,
702
+ 'i' : self .request_id })
704
703
705
704
def get_contacts (self ):
706
705
raise NotImplementedError ()
@@ -722,21 +721,21 @@ def get_public_url_info(self, url):
722
721
"""
723
722
Get size and name from a public url, dict returned
724
723
"""
725
- file_handle , file_key = self .parse_url (url ).split ('!' )
724
+ file_handle , file_key = self ._parse_url (url ).split ('!' )
726
725
return self .get_public_file_info (file_handle , file_key )
727
726
728
727
def import_public_url (self , url , dest_node = None , dest_name = None ):
729
728
"""
730
729
Import the public url into user account
731
730
"""
732
- file_handle , file_key = self .parse_url (url ).split ('!' )
731
+ file_handle , file_key = self ._parse_url (url ).split ('!' )
733
732
return self .import_public_file (file_handle , file_key , dest_node = dest_node , dest_name = dest_name )
734
733
735
734
def get_public_file_info (self , file_handle , file_key ):
736
735
"""
737
736
Get size and name of a public file
738
737
"""
739
- data = self .api_request ({
738
+ data = self ._api_request ({
740
739
'a' : 'g' ,
741
740
'p' : file_handle ,
742
741
'ssm' : 1 })
@@ -753,7 +752,7 @@ def get_public_file_info(self, file_handle, file_key):
753
752
754
753
size = data ['s' ]
755
754
unencrypted_attrs = decrypt_attr (base64_url_decode (data ['at' ]), k )
756
- if not ( unencrypted_attrs ) :
755
+ if not unencrypted_attrs :
757
756
return None
758
757
759
758
result = {
@@ -783,7 +782,7 @@ def import_public_file(self, file_handle, file_key, dest_node=None, dest_name=No
783
782
encrypted_key = a32_to_base64 (encrypt_key (key , self .master_key ))
784
783
encrypted_name = base64_url_encode (encrypt_attr ({'n' : dest_name }, k ))
785
784
786
- data = self .api_request ({
785
+ data = self ._api_request ({
787
786
'a' : 'p' ,
788
787
't' : dest_node ['h' ],
789
788
'n' : [{
0 commit comments