Add initial project files

This commit is contained in:
EP
2025-03-09 15:32:48 -04:00
parent cb34bdd42b
commit 803ab0fd16
3 changed files with 871 additions and 0 deletions
+228
View File
@@ -0,0 +1,228 @@
/* Dark hacker theme styling */
:root {
--main-bg-color: #0E1117;
--text-color: #00FF41;
--button-bg: #1E1E1E;
--button-border: #00FF41;
--button-hover-bg: #00FF41;
--button-hover-text: #1E1E1E;
--input-bg: #1E1E1E;
--input-border: #00FF41;
--section-divider: #00FF41;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--main-bg-color);
color: var(--text-color);
font-family: 'Courier New', monospace;
line-height: 1.6;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
}
h1, h2, h3, h4, h5 {
font-family: 'Courier New', monospace;
color: var(--text-color);
margin-bottom: 15px;
}
/* Tabs styling */
.tabs {
margin-top: 20px;
}
.tab-buttons {
display: flex;
margin-bottom: 20px;
border-bottom: 1px solid var(--text-color);
}
.tab-buttons button {
background-color: transparent;
color: var(--text-color);
border: none;
padding: 10px 20px;
cursor: pointer;
font-size: 16px;
font-family: 'Courier New', monospace;
transition: all 0.3s;
}
.tab-buttons button.active {
border-bottom: 3px solid var(--text-color);
font-weight: bold;
}
.tab-buttons button:hover {
background-color: rgba(0, 255, 65, 0.1);
}
.tab-content {
padding: 20px 0;
}
/* Form elements */
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: bold;
}
textarea {
width: 100%;
padding: 12px;
background-color: var(--input-bg);
color: var(--text-color);
border: 1px solid var(--input-border);
border-radius: 4px;
font-family: 'Courier New', monospace;
resize: vertical;
min-height: 100px;
}
button {
background-color: var(--button-bg);
color: var(--text-color);
border: 1px solid var(--button-border);
border-radius: 4px;
padding: 8px 16px;
cursor: pointer;
font-family: 'Courier New', monospace;
transition: all 0.3s;
}
button:hover {
background-color: var(--button-hover-bg);
color: var(--button-hover-text);
}
/* Emoji grid */
.emoji-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
gap: 10px;
margin-top: 10px;
}
.emoji-button {
padding: 5px;
min-width: 60px;
height: 60px;
font-size: 1.5rem;
position: relative;
}
.emoji-button.selected {
background-color: rgba(0, 255, 65, 0.2);
border: 2px solid var(--text-color);
}
.emoji-button .tooltip {
visibility: hidden;
background-color: var(--button-bg);
color: var(--text-color);
text-align: center;
border-radius: 4px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
font-size: 0.8rem;
opacity: 0;
transition: opacity 0.3s;
}
.emoji-button:hover .tooltip {
visibility: visible;
opacity: 1;
}
/* Transform buttons */
.transform-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
}
.transform-button {
padding: 5px 10px;
margin: 2px;
height: auto;
}
/* Copy button */
.copy-button {
margin-top: 10px;
display: inline-flex;
align-items: center;
gap: 5px;
}
/* Section dividers */
.section-divider {
border-top: 1px solid var(--section-divider);
margin: 30px 0;
}
/* GitHub link */
.github-link {
display: inline-flex;
align-items: center;
gap: 5px;
color: var(--text-color);
text-decoration: none;
padding: 8px 16px;
border: 1px solid var(--button-border);
border-radius: 4px;
transition: all 0.3s;
}
.github-link:hover {
background-color: var(--button-hover-bg);
color: var(--button-hover-text);
}
/* Responsive adjustments */
@media (max-width: 768px) {
.emoji-grid {
grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
}
.emoji-button {
min-width: 50px;
height: 50px;
}
.tab-buttons {
flex-direction: column;
}
.tab-buttons button {
width: 100%;
text-align: left;
}
}
+145
View File
@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parseltongue 2.0 - LLM Payload Crafter</title>
<link rel="stylesheet" href="css/style.css">
<!-- Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- Font Awesome for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<div id="app" class="container">
<header>
<h1>🐍 Parseltongue 2.0</h1>
<h3>LLM Payload Crafter</h3>
</header>
<div class="tabs">
<div class="tab-buttons">
<button :class="{ active: activeTab === 'steganography' }" @click="activeTab = 'steganography'">Steganography</button>
<button :class="{ active: activeTab === 'transforms' }" @click="activeTab = 'transforms'">Text Transforms</button>
<button :class="{ active: activeTab === 'about' }" @click="activeTab = 'about'">About</button>
</div>
<!-- Steganography Tab -->
<div v-if="activeTab === 'steganography'" class="tab-content">
<h4>✨ Emoji Steganography</h4>
<div class="form-group">
<label for="emoji-message">Enter your message:</label>
<textarea id="emoji-message" v-model="emojiMessage" placeholder="Type your message here..."></textarea>
</div>
<div class="form-group">
<label>Select an emoji carrier:</label>
<div class="emoji-grid">
<button
v-for="carrier in carriers"
:key="carrier.name"
class="emoji-button"
@click="selectCarrier(carrier)"
:class="{ selected: selectedCarrier === carrier }"
>
{{ carrier.emoji }}
<span class="tooltip">{{ carrier.desc }}</span>
</button>
</div>
</div>
<div class="form-group" v-if="selectedCarrier && emojiMessage">
<label>Encoded Message:</label>
<textarea readonly v-model="encodedEmojiMessage"></textarea>
<button class="copy-button" @click="copyToClipboard(encodedEmojiMessage)">
<i class="fas fa-clipboard"></i> Copy
</button>
</div>
<div class="section-divider"></div>
<h4>🔍 Invisible Text</h4>
<div class="form-group">
<label for="invisible-input">Enter text to make invisible:</label>
<textarea id="invisible-input" v-model="invisibleInput" placeholder="Type your message here..."></textarea>
</div>
<div class="form-group" v-if="invisibleInput">
<label>Invisible Text:</label>
<textarea readonly v-model="invisibleOutput"></textarea>
<button class="copy-button" @click="copyToClipboard(invisibleOutput)">
<i class="fas fa-clipboard"></i> Copy
</button>
</div>
<div class="section-divider"></div>
<h4>🔎 Universal Decoder</h4>
<div class="form-group">
<label for="decode-input">Enter text to decode:</label>
<textarea id="decode-input" v-model="decodeInput" placeholder="Paste encoded text here..."></textarea>
</div>
<div class="form-group" v-if="decodedMessage">
<label>Decoded Message:</label>
<textarea readonly v-model="decodedMessage"></textarea>
<button class="copy-button" @click="copyToClipboard(decodedMessage)">
<i class="fas fa-clipboard"></i> Copy
</button>
</div>
</div>
<!-- Text Transforms Tab -->
<div v-if="activeTab === 'transforms'" class="tab-content">
<h4>Text Transformation Tools</h4>
<div class="form-group">
<label for="transform-input">Enter text to transform:</label>
<textarea id="transform-input" v-model="transformInput" placeholder="Type your text here..."></textarea>
</div>
<div class="transform-buttons">
<button v-for="transform in transforms" :key="transform.name" @click="applyTransform(transform.func)" class="transform-button">
{{ transform.name }}
</button>
</div>
<div class="form-group" v-if="transformOutput">
<label>Transformed Text:</label>
<textarea readonly v-model="transformOutput"></textarea>
<button class="copy-button" @click="copyToClipboard(transformOutput)">
<i class="fas fa-clipboard"></i> Copy
</button>
</div>
</div>
<!-- About Tab -->
<div v-if="activeTab === 'about'" class="tab-content">
<h4>About Parseltongue 2.0</h4>
<p>
Parseltongue 2.0 is a tool for crafting and obfuscating text using various transformation and steganography techniques.
It's designed for educational purposes and to demonstrate the creative ways text can be manipulated.
</p>
<h5>Features:</h5>
<ul>
<li>Emoji Steganography - Hide messages within emoji using Unicode variation selectors</li>
<li>Invisible Text - Create text that's invisible but still present in the document</li>
<li>Text Transformations - Convert text to various formats like leetspeak, binary, morse code, etc.</li>
<li>Universal Decoder - Automatically detect and decode hidden messages</li>
</ul>
<p>
<strong>Note:</strong> This tool is for educational purposes only. Please use responsibly.
</p>
<p>
<a href="https://github.com/yourusername/parseltongue" target="_blank" class="github-link">
<i class="fab fa-github"></i> View on GitHub
</a>
</p>
</div>
</div>
</div>
<script src="js/transforms.js"></script>
<script src="js/steganography.js"></script>
<script src="js/app.js"></script>
</body>
</html>
+498
View File
@@ -0,0 +1,498 @@
import streamlit as st
import base64
import pyperclip
from PIL import Image
import io
import zlib
import numpy as np
import re
import logging
import random
from typing import List, Dict, Optional
from string import ascii_lowercase
# Import additional transformations
from more_transforms_fixed import (
to_upside_down, to_elder_futhark, to_vaporwave, to_zalgo,
to_unicode_circled, to_small_caps, to_braille
)
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('parseltongue')
# Set page config with dark theme and wide layout
st.set_page_config(
page_title="Parseltongue 2.0",
page_icon="🐍",
layout="wide",
initial_sidebar_state="collapsed"
)
# Custom CSS for dark hacker theme
st.markdown("""
<style>
/* Dark theme overrides */
.stApp {
background-color: #0E1117;
color: #00FF41;
}
/* Matrix-style headers */
h1, h2, h3, h4 {
font-family: 'Courier New', monospace;
color: #00FF41 !important;
}
/* Custom button styling */
.stButton > button {
background-color: #1E1E1E;
color: #00FF41;
border: 1px solid #00FF41;
border-radius: 4px;
transition: all 0.3s;
}
.stButton > button:hover {
background-color: #00FF41;
color: #1E1E1E;
}
/* Small emoji buttons */
.emoji-button > button {
padding: 5px 10px;
min-width: 60px;
height: 60px;
font-size: 1.2rem;
}
/* Transform buttons */
.transform-button > button {
padding: 5px 10px;
margin: 2px;
height: auto;
}
/* Text area styling */
.stTextArea textarea {
background-color: #1E1E1E;
color: #00FF41;
border: 1px solid #00FF41;
}
/* Code block styling */
.stCodeBlock {
background-color: #1E1E1E !important;
}
/* Section dividers */
.section-divider {
border-top: 1px solid #00FF41;
margin: 20px 0;
}
</style>
""", unsafe_allow_html=True)
# Helper Functions
def text_to_leetspeak(text: str) -> str:
"""Convert text to leetspeak"""
leet_dict = {
'a': '4', 'e': '3', 'i': '1', 'l': '1',
'o': '0', 's': '5', 't': '7', 'b': '8',
'g': '9', 'z': '2'
}
return ''.join(leet_dict.get(c.lower(), c) for c in text)
def text_to_pig_latin(text: str) -> str:
"""Convert text to Pig Latin"""
words = text.split()
result = []
for word in words:
if word[0].lower() in 'aeiou':
result.append(word + 'way')
else:
consonants = ''
i = 0
while i < len(word) and word[i].lower() not in 'aeiou':
consonants += word[i]
i += 1
result.append(word[i:] + consonants + 'ay')
return ' '.join(result)
def rot13(text: str) -> str:
"""Apply ROT13 encoding"""
result = ''
for char in text:
if char.isalpha():
ascii_offset = ord('a') if char.islower() else ord('A')
rotated = (ord(char) - ascii_offset + 13) % 26 + ascii_offset
result += chr(rotated)
else:
result += char
return result
def to_base64(text: str) -> str:
"""Convert text to Base64"""
if not text:
return ""
return base64.b64encode(text.encode('utf-8')).decode('utf-8')
def to_binary(text: str) -> str:
"""Convert text to binary"""
if not text:
return ""
return ' '.join(format(ord(c), '08b') for c in text)
def to_hex(text: str) -> str:
"""Convert text to hexadecimal"""
if not text:
return ""
return ' '.join(format(ord(c), '02x') for c in text)
def to_bubble_text(text: str) -> str:
"""Convert text to bubble text"""
if not text:
return ""
# Map for bubble text (circled latin letters)
bubble_map = {
'a': '\u24d0', 'b': '\u24d1', 'c': '\u24d2', 'd': '\u24d3', 'e': '\u24d4', 'f': '\u24d5', 'g': '\u24d6', 'h': '\u24d7', 'i': '\u24d8',
'j': '\u24d9', 'k': '\u24da', 'l': '\u24db', 'm': '\u24dc', 'n': '\u24dd', 'o': '\u24de', 'p': '\u24df', 'q': '\u24e0', 'r': '\u24e1',
's': '\u24e2', 't': '\u24e3', 'u': '\u24e4', 'v': '\u24e5', 'w': '\u24e6', 'x': '\u24e7', 'y': '\u24e8', 'z': '\u24e9',
'A': '\u24b6', 'B': '\u24b7', 'C': '\u24b8', 'D': '\u24b9', 'E': '\u24ba', 'F': '\u24bb', 'G': '\u24bc', 'H': '\u24bd', 'I': '\u24be',
'J': '\u24bf', 'K': '\u24c0', 'L': '\u24c1', 'M': '\u24c2', 'N': '\u24c3', 'O': '\u24c4', 'P': '\u24c5', 'Q': '\u24c6', 'R': '\u24c7',
'S': '\u24c8', 'T': '\u24c9', 'U': '\u24ca', 'V': '\u24cb', 'W': '\u24cc', 'X': '\u24cd', 'Y': '\u24ce', 'Z': '\u24cf',
'0': '\u24ea', '1': '\u2460', '2': '\u2461', '3': '\u2462', '4': '\u2463', '5': '\u2464', '6': '\u2465', '7': '\u2466', '8': '\u2467', '9': '\u2468',
' ': ' '
}
return ''.join(bubble_map.get(c, c) for c in text)
def to_fullwidth(text: str) -> str:
"""Convert text to fullwidth characters"""
if not text:
return ""
# Map for fullwidth text
fullwidth_map = {
'a': '\uff41', 'b': '\uff42', 'c': '\uff43', 'd': '\uff44', 'e': '\uff45', 'f': '\uff46', 'g': '\uff47', 'h': '\uff48', 'i': '\uff49',
'j': '\uff4a', 'k': '\uff4b', 'l': '\uff4c', 'm': '\uff4d', 'n': '\uff4e', 'o': '\uff4f', 'p': '\uff50', 'q': '\uff51', 'r': '\uff52',
's': '\uff53', 't': '\uff54', 'u': '\uff55', 'v': '\uff56', 'w': '\uff57', 'x': '\uff58', 'y': '\uff59', 'z': '\uff5a',
'A': '\uff21', 'B': '\uff22', 'C': '\uff23', 'D': '\uff24', 'E': '\uff25', 'F': '\uff26', 'G': '\uff27', 'H': '\uff28', 'I': '\uff29',
'J': '\uff2a', 'K': '\uff2b', 'L': '\uff2c', 'M': '\uff2d', 'N': '\uff2e', 'O': '\uff2f', 'P': '\uff30', 'Q': '\uff31', 'R': '\uff32',
'S': '\uff33', 'T': '\uff34', 'U': '\uff35', 'V': '\uff36', 'W': '\uff37', 'X': '\uff38', 'Y': '\uff39', 'Z': '\uff3a',
'0': '\uff10', '1': '\uff11', '2': '\uff12', '3': '\uff13', '4': '\uff14', '5': '\uff15', '6': '\uff16', '7': '\uff17', '8': '\uff18', '9': '\uff19',
' ': '\u3000', '!': '\uff01', '?': '\uff1f', '.': '\uff0e', ',': '\uff0c', ';': '\uff1b', ':': '\uff1a', '(': '\uff08', ')': '\uff09',
'[': '\uff3b', ']': '\uff3d', '{': '\uff5b', '}': '\uff5d', '<': '\uff1c', '>': '\uff1e', '\\': '\uff3c', '/': '\uff0f', '|': '\uff5c',
'`': '\uff40', '~': '\uff5e', '@': '\uff20', '#': '\uff03', '$': '\uff04', '%': '\uff05', '^': '\uff3e', '&': '\uff06', '*': '\uff0a',
'-': '\uff0d', '_': '\uff3f', '+': '\uff0b', '=': '\uff1d', '"': '\uff02', '\'': '\uff07'
}
return ''.join(fullwidth_map.get(c, c) for c in text)
def to_morse(text: str) -> str:
"""Convert text to Morse code"""
if not text:
return ""
# Morse code mapping
morse_map = {
'a': '.-', 'b': '-...', 'c': '-.-.', 'd': '-..', 'e': '.', 'f': '..-.', 'g': '--.', 'h': '....',
'i': '..', 'j': '.---', 'k': '-.-', 'l': '.-..', 'm': '--', 'n': '-.', 'o': '---', 'p': '.--.',
'q': '--.-', 'r': '.-.', 's': '...', 't': '-', 'u': '..-', 'v': '...-', 'w': '.--', 'x': '-..-',
'y': '-.--', 'z': '--..', '0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', ' ': '/'
}
return ' '.join(morse_map.get(c.lower(), c) for c in text)
def to_binary_ascii(text: str) -> str:
"""Convert text to ASCII binary (with ASCII values)"""
if not text:
return ""
return ' '.join(str(ord(c)) for c in text)
def to_reverse(text: str) -> str:
"""Reverse the text"""
if not text:
return ""
return text[::-1]
# Define carriers for steganography with descriptions
CARRIERS = [
{'emoji': '🐍', 'name': 'SNAKE', 'desc': 'Classic Snake'},
{'emoji': '🐉', 'name': 'DRAGON', 'desc': 'Mystical Dragon'},
{'emoji': '🧙', 'name': 'WIZARD', 'desc': 'Powerful Wizard'},
{'emoji': '🔮', 'name': 'CRYSTAL', 'desc': 'Magic Crystal Ball'},
{'emoji': '', 'name': 'LIGHTNING', 'desc': 'Lightning Bolt'},
{'emoji': '🌟', 'name': 'STAR', 'desc': 'Shining Star'},
{'emoji': '🎭', 'name': 'MASK', 'desc': 'Theater Mask'},
{'emoji': '🗝️', 'name': 'KEY', 'desc': 'Ancient Key'},
{'emoji': '📜', 'name': 'SCROLL', 'desc': 'Magic Scroll'},
{'emoji': '🔒', 'name': 'LOCK', 'desc': 'Secure Lock'}
]
def to_variation_selector(byte: int) -> str:
"""Convert a byte to a variation selector character"""
return chr(0xFE00 + byte)
def from_variation_selector(code_point: int) -> int:
"""Convert a variation selector character back to a byte"""
return code_point - 0xFE00
def encode_emoji(emoji: str, text: str) -> str:
"""Encode text using variation selectors"""
if not text:
return emoji
# Convert text to binary
binary = ''.join(format(ord(c), '08b') for c in text)
# Use variation selectors to encode binary
vs15, vs16 = '\ufe0e', '\ufe0f'
encoded = emoji
for bit in binary:
encoded += vs15 if bit == '0' else vs16
return encoded
def decode_emoji(text: str) -> str:
"""Decode text from variation selectors"""
if not text:
return ""
# Extract variation selectors
vs_pattern = r'[\ufe0e\ufe0f]'
matches = re.findall(vs_pattern, text)
if not matches:
return ""
# Convert variation selectors to binary
binary = ''.join('0' if vs == '\ufe0e' else '1' for vs in matches)
# Convert binary to text
decoded = ""
for i in range(0, len(binary), 8):
byte = binary[i:i+8]
if len(byte) == 8:
decoded += chr(int(byte, 2))
return decoded
def encode_invisible(text: str) -> str:
"""Encode text using Tags Unicode block (U+E0000 to U+E007F)"""
if not text:
return ""
result = ''
for c in text:
# Add the character as a Tags character
result += chr(0xE0000 + ord(c) % 0x7F)
# Add a space from the Tags block
result += chr(0xE0020) # This is the space character in Tags block
return result
def decode_invisible(text: str) -> str:
"""Decode text from Tags Unicode block (U+E0000 to U+E007F)"""
if not text:
return ""
result = ''
# Filter valid Tags characters
chars = [c for c in text if 0xE0000 <= ord(c) <= 0xE007F]
for c in chars:
if ord(c) != 0xE0020: # Skip the space character
# Convert back from Tags block
original = chr((ord(c) - 0xE0000) % 128)
result += original
return result
def encode_image_steganography(image: Image.Image, message: str, plane: str = 'red') -> Image.Image:
"""Encode a message into an image using LSB steganography"""
# Convert the image to RGB if it's not already
img = image.convert('RGB')
# Get the image data as a numpy array
data = np.array(img)
# Convert message to binary
binary = ''.join(format(ord(c), '08b') for c in message)
binary += '00000000' # Add null terminator
# Get the correct color plane
plane_idx = {'red': 0, 'green': 1, 'blue': 2}[plane]
# Encode the message
idx = 0
for i in range(data.shape[0]):
for j in range(data.shape[1]):
if idx < len(binary):
# Clear the LSB and set it to the message bit
data[i, j, plane_idx] = (data[i, j, plane_idx] & 0xFE) | int(binary[idx])
idx += 1
# Create a new image from the modified data
encoded_image = Image.fromarray(data)
return encoded_image
# Main App
st.title("🐍 Parseltongue 2.0")
st.markdown("""<h3 style='color: #00FF41;'>LLM Payload Crafter</h3>""", unsafe_allow_html=True)
# Create tabs for steganography and decoder
tab1, tab2 = st.tabs(["🔐 Steganography", "🔍 Universal Decoder"])
# Steganography Tab
with tab1:
st.markdown("""<h4>✨ Emoji Steganography</h4>""", unsafe_allow_html=True)
# Text input for message
message = st.text_area("Enter your message:", key="emoji_message", placeholder="Type your message here...")
if message:
st.markdown("""<p style='color: #00FF41;'>Click an emoji to encode and copy to clipboard:</p>""", unsafe_allow_html=True)
# Create a grid of emojis with their descriptions
cols = st.columns(8) # More columns for smaller buttons
for i, carrier in enumerate(CARRIERS):
with cols[i % 8]:
# Create a smaller button with just the emoji
button = st.button(carrier['emoji'], key=f"emoji_{i}", help=carrier['desc'])
st.markdown("<div class='emoji-button'></div>", unsafe_allow_html=True)
if button:
try:
# Encode the message
encoded = encode_emoji(carrier['emoji'], message)
# Copy to clipboard
pyperclip.copy(encoded)
# Show success message with preview
st.success(f"✅ Encoded with {carrier['name']} and copied to clipboard!")
except Exception as e:
st.error(f"Error encoding message: {str(e)}")
# Add a divider
st.markdown("<div class='section-divider'></div>", unsafe_allow_html=True)
# Omni-Encoder Section
st.markdown("""<h4>🔍 Omni-Encoder</h4>""", unsafe_allow_html=True)
st.markdown("""<p style='color: #00FF41;'>Click to transform and copy to clipboard:</p>""", unsafe_allow_html=True)
# Create a grid of transformation options - 4 columns, 4 rows
st.markdown("<div style='display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px;'></div>", unsafe_allow_html=True)
# Use 4 rows of 4 columns each
for row in range(4):
transform_cols = st.columns(4)
# Define transformations
transformations = [
{"name": "Base64", "func": to_base64, "icon": "🔢"},
{"name": "Binary", "func": to_binary, "icon": "01"},
{"name": "Hex", "func": to_hex, "icon": "0x"},
{"name": "ASCII", "func": to_binary_ascii, "icon": "🔤"},
{"name": "ROT13", "func": rot13, "icon": "🔓"},
{"name": "Leetspeak", "func": text_to_leetspeak, "icon": "1337"},
{"name": "Pig Latin", "func": text_to_pig_latin, "icon": "🐷"},
{"name": "Morse", "func": to_morse, "icon": "•−•"},
{"name": "Bubble", "func": to_bubble_text, "icon": "ⓑⓤⓑ"},
{"name": "Fullwidth", "func": to_fullwidth, "icon": "FW"},
{"name": "Reversed", "func": to_reverse, "icon": ""},
{"name": "Upside Down", "func": to_upside_down, "icon": "🙃"},
{"name": "Runes", "func": to_elder_futhark, "icon": "ᚠᚢᚦᚨᚱᚲ"},
{"name": "Vaporwave", "func": to_vaporwave, "icon": "vapor"},
{"name": "Zalgo", "func": to_zalgo, "icon": "Z̷̢̧͝a̶̢͝l̸̨̛͝g̵̢̧̛o̵̡͘"},
{"name": "Circled", "func": to_unicode_circled, "icon": "🅒🅘🅡"},
{"name": "Small Caps", "func": to_small_caps, "icon": "ᴀʙᴄ"},
{"name": "Braille", "func": to_braille, "icon": "⠃⠗⠁⠊⠇⠇⠑"}
]
for i, transform in enumerate(transformations):
row_idx = i // 4 # Determine which row this transform belongs to
col_idx = i % 4 # Determine which column in the row
# Only process transforms for the current row
if row_idx < 4: # We have 4 rows total
with transform_cols[col_idx]:
# Create a button for each transformation
button = st.button(f"{transform['icon']} {transform['name']}", key=f"transform_{i}")
st.markdown("<div class='transform-button'></div>", unsafe_allow_html=True)
if button:
try:
# Transform the message
transformed = transform['func'](message)
# Copy to clipboard
pyperclip.copy(transformed)
# Show success message with preview
st.success(f"{transform['name']} encoded and copied to clipboard!\n\nPreview: {transformed[:50] + '...' if len(transformed) > 50 else transformed}")
except Exception as e:
st.error(f"Error transforming message: {str(e)}")
# Invisible Text Section
st.markdown("""<h4>👻 Invisible Text</h4>""", unsafe_allow_html=True)
invisible_input = st.text_area("Enter text to make invisible", key="invisible_input")
if invisible_input:
invisible_output = encode_invisible(invisible_input)
st.text_area("Invisible text (copied to clipboard)", invisible_output, height=100)
if st.button("📋 Copy Invisible Text", key="copy_invisible"):
pyperclip.copy(invisible_output)
st.success("✅ Copied to clipboard!")
# Image Steganography Section
st.markdown("""<h4>🖼️ Image Steganography</h4>""", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
uploaded_file = st.file_uploader("Choose carrier image", type=['png', 'jpg', 'jpeg'])
if uploaded_file:
image = Image.open(uploaded_file)
st.image(image, caption="Carrier Image")
with col2:
steg_message = st.text_area("Enter message to hide", key="steg_message")
color_plane = st.selectbox("Select color plane", ["red", "green", "blue"])
if uploaded_file and steg_message and st.button("🔒 Encode Message"):
try:
encoded_image = encode_image_steganography(image, steg_message, color_plane)
st.image(encoded_image, caption="Encoded Image")
# Save the image to a bytes buffer
buf = io.BytesIO()
encoded_image.save(buf, format='PNG')
byte_im = buf.getvalue()
st.download_button(
label="💾 Download Encoded Image",
data=byte_im,
file_name="encoded_image.png",
mime="image/png"
)
except Exception as e:
st.error(f"Error encoding message in image: {str(e)}")
# Universal Decoder Tab
with tab2:
st.markdown("### Text Transformation Tools")
text_input = st.text_area("Enter text to transform", key="obfuscate_input")
if text_input:
# Create columns for different transformations
col1, col2 = st.columns(2)
with col1:
st.markdown("#### Basic Transformations")
st.text_area("Leetspeak:", text_to_leetspeak(text_input))
st.text_area("Pig Latin:", text_to_pig_latin(text_input))
st.text_area("ROT13:", rot13(text_input))
with col2:
st.markdown("#### Decodings")
# Try to decode emoji
emoji_decoded = decode_emoji(text_input)
if emoji_decoded:
st.text_area("Emoji Decoded:", emoji_decoded)
# Try to decode invisible text
invisible_decoded = decode_invisible(text_input)
if invisible_decoded:
st.text_area("Invisible Text Decoded:", invisible_decoded)