Last active
June 15, 2018 04:07
-
-
Save ioistired/e96393c533464840b5a45fbba708b058 to your computer and use it in GitHub Desktop.
Simple aiohttp PrivateBin client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# encoding: utf-8 | |
""" | |
privatebin.py: uploads text to privatebin | |
using code from <https://github.com/r4sas/PBinCLI/blob/master/pbincli/actions.py>, | |
© 2017–2018 R4SAS <[email protected]> | |
using code from <https://github.com/khazhyk/dango.py/blob/master/dango/zerobin.py>, | |
© 2017 khazhyk | |
""" | |
import asyncio | |
import base64 | |
import json | |
import os | |
import sys | |
import zlib | |
import aiohttp | |
from sjcl import SJCL | |
def encrypt(text): | |
key = base64.urlsafe_b64encode(os.urandom(32)) | |
# Encrypting text | |
encrypted_data = SJCL().encrypt(compress(text.encode('utf-8')), key, mode='gcm') | |
return encrypted_data, key | |
def compress(s: bytes): | |
co = zlib.compressobj(wbits=-zlib.MAX_WBITS) | |
b = co.compress(s) + co.flush() | |
return base64.b64encode(''.join(map(chr, b)).encode('utf-8')) | |
def make_payload(text): | |
# Formatting request | |
request = dict( | |
expire='never', | |
formatter='plaintext', | |
burnafterreading='0', | |
opendiscussion='0', | |
) | |
cipher, key = encrypt(text) | |
# TODO: should be implemented in upstream | |
for k in ['salt', 'iv', 'ct']: cipher[k] = cipher[k].decode() | |
request['data'] = json.dumps(cipher, ensure_ascii=False, indent=None, default=lambda x: x.decode('utf-8')) | |
return request, key | |
lock = asyncio.Lock() | |
class PrivateBinException(Exception): pass | |
async def upload(text, loop=None): | |
loop = loop or asyncio.get_event_loop() | |
await lock.acquire() | |
result = None | |
payload, key = await loop.run_in_executor(None, make_payload, text) | |
python_version = '.'.join(map(str, sys.version_info[:3])) | |
async with aiohttp.ClientSession(headers={ | |
'User-Agent': 'privatebin.py/0.0.3 aiohttp/%s python/%s' % (aiohttp.__version__, python_version), | |
'X-Requested-With': 'JSONHttpRequest' | |
}) as session: | |
for tries in range(2): | |
async with session.post('https://privatebin.net/', data=payload) as resp: | |
resp_json = await resp.json() | |
if resp_json['status'] == 0: | |
result = url(resp_json['id'], key) | |
break | |
elif resp_json['status'] == 1: # rate limited | |
await asyncio.sleep(5) | |
lock.release() | |
if result is None: | |
raise PrivateBinException('Failed to upload to privatebin') | |
else: | |
return result | |
def url(paste_id, key): | |
return 'https://privatebin.net/?%s#%s' % (paste_id, key.decode('utf-8')) | |
if __name__ == '__main__': | |
loop = asyncio.get_event_loop() | |
print(loop.run_until_complete(upload(sys.stdin.read()))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment