import time import ipdb import json import random import qrcode import requests import base64 import re SENDER_LENGTH = 4 PASSWORD_LENGTH = 8 from random_word import RandomWords import secrets from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d from cryptography.fernet import Fernet from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC r = RandomWords() backend = default_backend() iterations = 100_000 def _derive_key(password: bytes, salt: bytes, iterations: int = iterations) -> bytes: """Derive a secret key from a given password and salt""" kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=iterations, backend=backend) return b64e(kdf.derive(password)) def password_encrypt(message: bytes, password: str, iterations: int = iterations) -> bytes: salt = secrets.token_bytes(16) key = _derive_key(password.encode(), salt, iterations) return b64e( b'%b%b%b' % ( salt, iterations.to_bytes(4, 'big'), b64d(Fernet(key).encrypt(message)), ) ) def password_decrypt(token: bytes, password: str) -> bytes: decoded = b64d(token) salt, iter, token = decoded[:16], decoded[16:20], b64e(decoded[20:]) iterations = int.from_bytes(iter, 'big') key = _derive_key(password.encode(), salt, iterations) return Fernet(key).decrypt(token) class Bump: def __init__(self, secret=None, secret_file='.bump_secrets'): self.secrets = self.load_secrets(secret, secret_file) if self.secrets == []: self.generate_secret(secret_file) self.show_secrets() self.URL = "http://0.0.0.0:4000/api/" def load_secrets(self, secret, secrets_file='.bump_secrets'): try: with open(secrets_file, 'r') as f: secrets = f.read().splitlines() except FileNotFoundError: secrets = [] if secret is not None and secret not in self.secrets: secrets.append(secret) return secrets def generate_secret(self, secret_file): WORDS = r.get_random_words() secret = "" for _ in range(SENDER_LENGTH + PASSWORD_LENGTH): secret += random.choice(WORDS) + "-" while len(secret[SENDER_LENGTH:]) < 32: secret += random.choice(WORDS) + "-" secret = secret[:-1] self.secrets.append(secret) with open(secret_file, 'a+') as f: f.write(secret + '\n') def show_secrets(self): for secret in self.secrets: qrcode.make(secret).show() print(secret) def get_password(self, index=0): secret = self.secrets[index].split('-') return "-".join(secret[SENDER_LENGTH:]) def get_sender(self, index=0): words = self.secrets[index].split('-') return "-".join(words[0:SENDER_LENGTH]) def encrypt(self, data): password = self.get_password() return password_encrypt(data.encode(), password) def decrypt(self, data): password = self.get_password() return password_decrypt(data, password).decode() def push_fake(self, data): print(self.encrypt(data)) def push(self, data): url = self.URL + "push" params = { 'sender': self.get_sender(), 'data': self.encrypt(data) } print(url) r = requests.post(url, params) print(r.json()) def peek(self): return self.get_post("peek") def pop(self): return self.get_post("pop") def list(self): params = { 'minutes': 2 } return self.get_post("list", params) def clear(self): return self.get_post("clear") def get_post(self, mechanism, add_params = None): url = self.URL + mechanism params = { 'sender': self.get_sender() } if add_params != None: params.update(add_params) messages = requests.post(url, params).json() if(messages == {} or messages == None or "messages" in messages and messages["messages"] == []): return [{}] elif "messages" in messages: for message in messages.get("messages"): message['data'] = self.decrypt(message.get('data')) return messages else: messages['data'] = self.decrypt(messages.get('data')) return [messages] def load_log(self): with open('.bump_log', "r+") as f: return f.readlines() def save_log(self, message): with open('.bump_log', "a") as f: f.write(self.to_log_line(message)) def to_log_line(self, message): return json.dumps(message) + "\n" def alert(self, sleep_time=1): log = self.load_log() while True: time.sleep(sleep_time) messages = self.list() for message in messages: if self.to_log_line(message) not in log and message != {}: print(message['data']) self.save_log(message) log = self.load_log() if __name__ == '__main__': b = Bump() b.decrypt("M1dEAxKZ5HUHCJoRkgGOvAABhqCAAAAAAGG2eKTSlKXWLDQx5B_wssZsNwsanzQID2UyUm4KKuKYKgfwH5MG2N-qzt6K4mg3pfZmWPaiDB9PiqlX236k6zo9Yvvq")