import html import base64 import urllib import json from guppyproxy.util import display_error_box from guppyproxy.hexteditor import ComboEditor from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QComboBox, QPlainTextEdit, QPushButton from PyQt5.QtCore import pyqtSlot, pyqtSignal from datetime import datetime class DecodeError(Exception): pass def asciihex_encode_helper(s): return ''.join('{0:x}'.format(c) for c in s).encode() def asciihex_decode_helper(s): ret = [] try: for a, b in zip(s[0::2], s[1::2]): c = chr(a) + chr(b) ret.append(chr(int(c, 16))) return ''.join(ret).encode() except Exception as e: raise DecodeError("Unable to decode asciihex") def base64_decode_helper(s): s = s.decode() for i in range(0, 8): try: s_padded = base64.b64decode(s + '=' * i) return s_padded except Exception as e2: pass raise DecodeError("Unable to base64 decode string: %s" % s) def url_decode_helper(s): bs = s.decode() return urllib.parse.unquote(bs).encode() def url_encode_helper(s): bs = s.decode() return urllib.parse.quote_plus(bs).encode() def html_encode_helper(s): return ''.join(['&#x{0:x};'.format(c) for c in s]).encode() def html_decode_helper(s): return html.unescape(s.decode()).encode() def pp_json(s): d = json.loads(s.strip()) return json.dumps(d, indent=2, sort_keys=True).encode() def decode_jwt(s): # in case they paste the whole auth header or the token with "bearer" s = s.strip() fields = s.split(b' ') s = fields[-1].strip() parts = s.split(b'.') ret = b'' for part in parts: try: ret += base64_decode_helper(part.decode()) + b'\n\n' except: ret += b"[error decoding]\n\n" return ret def decode_unixtime(s): ts = int(s) dfmt = '%b %d, %Y %I:%M:%S %p' try: return datetime.utcfromtimestamp(ts).strftime(dfmt).encode() except ValueError: ts = ts/1000 return datetime.utcfromtimestamp(ts).strftime(dfmt).encode() class DecoderWidget(QWidget): def __init__(self): QWidget.__init__(self) layout = QVBoxLayout() self.decoder_input = DecoderInput() layout.addWidget(self.decoder_input) self.setLayout(layout) self.layout().setContentsMargins(0, 0, 0, 0) class DecoderInput(QWidget): decodeRun = pyqtSignal(bytes) decoders = { "encode_b64": ("Encode Base64", base64.b64encode), "decode_b64": ("Decode Base64", base64_decode_helper), "encode_ah": ("Encode Asciihex", asciihex_encode_helper), "decode_ah": ("Decode Asciihex", asciihex_decode_helper), "encode_url": ("URL Encode", url_encode_helper), "decode_url": ("URL Decode", url_decode_helper), "encode_html": ("HTML Encode", html_encode_helper), "decode_html": ("HTML Decode", html_decode_helper), "decode_unixtime": ("Format Unix Timestamp", decode_unixtime), "pp_json": ("Pretty-Print JSON", pp_json), "decode_jwt": ("Decode JWT Token", decode_jwt), } def __init__(self, *args, **kwargs): QWidget.__init__(self) layout = QVBoxLayout() tool_layout = QHBoxLayout() self.editor = ComboEditor(pretty_tab=False, enable_pretty=False) self.encode_entry = QComboBox() encode_button = QPushButton("Go!") encode_button.clicked.connect(self.encode) for k, v in self.decoders.items(): self.encode_entry.addItem(v[0], k) layout.addWidget(self.editor) tool_layout.addWidget(self.encode_entry) tool_layout.addWidget(encode_button) tool_layout.addStretch() layout.addLayout(tool_layout) self.setLayout(layout) self.layout().setContentsMargins(0, 0, 0, 0) @pyqtSlot() def encode(self): text = self.editor.get_bytes() encode_type = self.encode_entry.itemData(self.encode_entry.currentIndex()) encode_func = DecoderInput.decoders[encode_type][1] try: encoded = encode_func(text) except Exception as e: display_error_box("Error processing string:\n" + str(e)) return self.editor.set_bytes(encoded)