def api_upload(service, encData, encMeta, keys): ''' Uploads data to Send. Caution! Data is uploaded as given, this function will not encrypt it for you ''' service += 'api/upload' files = requests_toolbelt.MultipartEncoder( fields={'file': ('blob', encData, 'application/octet-stream')}) pbar = progbar(files.len) monitor = requests_toolbelt.MultipartEncoderMonitor( files, lambda files: pbar.update(monitor.bytes_read - pbar.n)) headers = { 'X-File-Metadata': unpadded_urlsafe_b64encode(encMeta), 'Authorization': 'send-v1 ' + unpadded_urlsafe_b64encode(keys.authKey), 'Content-type': monitor.content_type } r = requests.post(service, data=monitor, headers=headers, stream=True) r.raise_for_status() pbar.close() body_json = r.json() secretUrl = body_json['url'] + '#' + unpadded_urlsafe_b64encode( keys.secretKey) fileId = body_json['id'] fileNonce = unpadded_urlsafe_b64decode( r.headers['WWW-Authenticate'].replace('send-v1 ', '')) delete_token = body_json['delete'] return secretUrl, fileId, fileNonce, delete_token
def api_metadata(service, fileId, authorisation): headers = {'Authorization' : 'send-v1 ' + unpadded_urlsafe_b64encode(authorisation)} url = service + 'api/metadata/' + fileId response = requests.get(url, headers=headers) response.raise_for_status() newNonce = unpadded_urlsafe_b64decode(response.headers['WWW-Authenticate'].replace('send-v1 ', '')) return response.json(), newNonce
def send_urlToFile(url, password=None, ignoreVersion=False): service, fileId, key = splitkeyurl(url) if checkServerVersion(service, ignoreVersion) == False: raise Exception('Potentially incompatible server version, use --ignore-version to disable version checks') passwordRequired = check_for_password(service + 'download/' + str(fileId) + '/') rawKey = unpadded_urlsafe_b64decode(key) if passwordRequired == False and password == None: keys = secretKeys(rawKey) elif passwordRequired == True and password != None: keys = secretKeys(rawKey, password=password, url=url) keys.authKey = keys.newAuthKey elif passwordRequired and password == None: print("A password is required, please enter it now") password = getpass.getpass() keys = secretKeys(rawKey, password=password, url=url) keys.authKey = keys.newAuthKey elif passwordRequired == False and password != None: raise Exception('A password was provided but none is required') print('Checking if file exists...') passwordRequired = check_for_password(service + 'download/' + fileId) if password == None and passwordRequired == True: raise Exception('This Send url requires a password') nonce = get_nonce(service + 'download/' + str(fileId) + '/') authorisation = sign_nonce(keys.authKey, nonce) print('Fetching metadata...') jsonMeta, nonce = api_metadata(service, fileId, authorisation) encMeta = unpadded_urlsafe_b64decode(jsonMeta['metadata']) metadata = decrypt_metadata(encMeta, keys) keys.encryptIV = unpadded_urlsafe_b64decode(metadata['iv']) print('The file wishes to be called \'' + metadata['name'] + '\' and is ' + str(jsonMeta['size'] - 16) + ' bytes in size') print('Downloading ' + url) authorisation = sign_nonce(keys.authKey, nonce) data = api_download(service, fileId, authorisation) print('Decrypting to temp file') tmpfile = decrypt_filedata(data, keys) return tmpfile, metadata['name']
def test_unpadded_urlsafe_b64decode(): jwk = '39EL7SuqwWNYe4ISl2M06g' assert unpadded_urlsafe_b64decode( jwk) == b'\xdf\xd1\x0b\xed+\xaa\xc1cX{\x82\x12\x97c4\xea'
def get_nonce(url): r = requests.get(url) r.raise_for_status() nonce = unpadded_urlsafe_b64decode(r.headers['WWW-Authenticate'].replace('send-v1 ', '')) return nonce