mirror of
https://github.com/elder-plinius/P4RS3LT0NGV3.git
synced 2026-02-12 16:52:46 +00:00
508 lines
29 KiB
HTML
508 lines
29 KiB
HTML
<!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">
|
|
<link rel="stylesheet" href="css/notification.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>
|
|
<div class="logo">
|
|
<h1>🐍 Parseltongue</h1>
|
|
</div>
|
|
<div class="actions">
|
|
<button
|
|
@click="toggleCopyHistory"
|
|
class="history-button"
|
|
title="Show copy history"
|
|
aria-label="Show copy history"
|
|
>
|
|
<i class="fas fa-history"></i>
|
|
</button>
|
|
<button
|
|
@click="toggleTheme"
|
|
@keyup.d="toggleTheme"
|
|
class="theme-button"
|
|
title="Toggle dark mode (D)"
|
|
aria-label="Toggle dark mode"
|
|
>
|
|
<i class="fas" :class="isDarkTheme ? 'fa-moon' : 'fa-sun'"></i>
|
|
</button>
|
|
<a
|
|
href="https://github.com/elder-plinius/P4RS3LT0NGV3"
|
|
target="_blank"
|
|
class="github-button"
|
|
title="View source on GitHub"
|
|
aria-label="View source code on GitHub"
|
|
>
|
|
<i class="fab fa-github"></i>
|
|
</a>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="tabs">
|
|
<div class="tab-buttons">
|
|
<button
|
|
:class="{ active: activeTab === 'transforms' }"
|
|
@click="activeTab = 'transforms'"
|
|
title="Transform text (T)"
|
|
>
|
|
<i class="fas fa-font"></i> Transform
|
|
</button>
|
|
<button
|
|
:class="{ active: activeTab === 'steganography' }"
|
|
@click="activeTab = 'steganography'"
|
|
title="Hide text in emojis (H)"
|
|
>
|
|
<i class="fas fa-smile"></i> Emoji
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Steganography Tab -->
|
|
<div v-if="activeTab === 'steganography'" class="tab-content">
|
|
<div class="transform-layout">
|
|
<div class="input-section">
|
|
<textarea
|
|
id="steg-input"
|
|
v-model="emojiMessage"
|
|
placeholder="Enter text to hide..."
|
|
@input="autoEncode"
|
|
></textarea>
|
|
</div>
|
|
|
|
<div class="transform-section">
|
|
</div>
|
|
|
|
<!-- Emoji Library Section -->
|
|
<div class="emoji-library">
|
|
<div class="emoji-library-header">
|
|
<div class="emoji-library-title">
|
|
<h3><i class="fas fa-icons"></i> Choose an Emoji</h3>
|
|
</div>
|
|
</div>
|
|
<!-- Emoji grid container - this MUST have id="emoji-grid-container" -->
|
|
<div id="emoji-grid-container" class="emoji-grid-container">
|
|
<!-- Dynamic content will be inserted here by JavaScript -->
|
|
<div class="emoji-grid">
|
|
<!-- Common emojis as fallback -->
|
|
<button class="emoji-button" onclick="app.selectEmoji('😀')">😀</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('😂')">😂</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('🥰')">🥰</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('😎')">😎</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('🤔')">🤔</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('👍')">👍</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('🎉')">🎉</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('🔥')">🔥</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('🚀')">🚀</button>
|
|
<button class="emoji-button" onclick="app.selectEmoji('🐍')">🐍</button>
|
|
</div>
|
|
</div>
|
|
<div class="emoji-library-footer" v-if="selectedEmoji">
|
|
<div class="selected-emoji-info">
|
|
<span class="selected-emoji">{{ selectedEmoji }}</span>
|
|
<span class="selected-emoji-label">Last selected</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="output-section" v-if="encodedMessage">
|
|
<div class="output-heading">
|
|
<h4>
|
|
<i class="fas fa-check-circle"></i>
|
|
Encoded Message
|
|
<small v-if="selectedCarrier">using {{ selectedCarrier.name }}</small>
|
|
<small v-else-if="activeSteg === 'invisible'">using Invisible Text</small>
|
|
</h4>
|
|
</div>
|
|
<div class="output-container">
|
|
<textarea readonly v-model="encodedMessage"></textarea>
|
|
<button class="copy-button" @click="copyToClipboard(encodedMessage)" title="Copy to clipboard">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
<div class="output-instructions">
|
|
<small><i class="fas fa-info-circle"></i> Copy this text and share it. Only people who know how to decode it will be able to read your message.</small>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Universal Decoder Section for Steganography Tab -->
|
|
<div class="decode-section">
|
|
<div class="section-header">
|
|
<h3><i class="fas fa-magic"></i> Universal Decoder</h3>
|
|
<p>Paste any encoded text to try all decoding methods at once</p>
|
|
</div>
|
|
<div class="input-container">
|
|
<textarea
|
|
id="universal-decode-input-steg"
|
|
v-model="universalDecodeInput"
|
|
placeholder="Paste encoded text to decode automatically..."
|
|
@input="runUniversalDecode"
|
|
></textarea>
|
|
<div class="decoded-message" v-if="universalDecodeResult">
|
|
<div class="decode-method">Decoded using: <strong>{{ universalDecodeResult.method }}</strong></div>
|
|
<div class="decode-result">{{ universalDecodeResult.text }}</div>
|
|
<button class="copy-button" @click="copyToClipboard(universalDecodeResult.text)" title="Copy decoded text">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Text Transforms Tab -->
|
|
<div v-if="activeTab === 'transforms'" class="tab-content">
|
|
<div class="transform-layout">
|
|
<div class="input-section">
|
|
<textarea
|
|
id="transform-input"
|
|
v-model="transformInput"
|
|
placeholder="Enter text to transform..."
|
|
@input="autoTransform"
|
|
></textarea>
|
|
</div>
|
|
|
|
<div class="transform-section">
|
|
<div class="transform-category-legend">
|
|
<div class="legend-title">Categories:</div>
|
|
<div class="legend-item transform-category-encoding" data-target="category-encoding">Encoding</div>
|
|
<div class="legend-item transform-category-cipher" data-target="category-cipher">Ciphers</div>
|
|
<div class="legend-item transform-category-visual" data-target="category-visual">Visual</div>
|
|
<div class="legend-item transform-category-format" data-target="category-format">Formatting</div>
|
|
<div class="legend-item transform-category-unicode" data-target="category-unicode">Unicode</div>
|
|
<div class="legend-item transform-category-special" data-target="category-special">Special</div>
|
|
</div>
|
|
<div class="transform-categories">
|
|
<!-- Encoding Category -->
|
|
<div id="category-encoding" class="transform-category-section">
|
|
<h4 class="category-title transform-category-encoding">Encoding</h4>
|
|
<div class="transform-buttons">
|
|
<div v-for="transform in getTransformsByCategory('encoding')" :key="transform.name" class="transform-button-group">
|
|
<button
|
|
@click="applyTransform(transform)"
|
|
class="transform-button transform-category-encoding"
|
|
:class="{ active: activeTransform === transform }"
|
|
:title="'Click to transform and copy: ' + transform.name"
|
|
>
|
|
{{ transform.name }}
|
|
<small class="transform-preview" v-if="transformInput">
|
|
{{ transform.preview(transformInput.slice(0, 10)) }}
|
|
</small>
|
|
<i class="fas fa-copy auto-copy-icon"></i>
|
|
</button>
|
|
<button
|
|
v-if="transformHasReverse(transform)"
|
|
@click="decodeWithTransform(transform)"
|
|
class="decode-button transform-category-encoding"
|
|
:title="'Click to decode using: ' + transform.name"
|
|
>
|
|
<i class="fas fa-undo"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Cipher Category -->
|
|
<div id="category-cipher" class="transform-category-section">
|
|
<h4 class="category-title transform-category-cipher">Ciphers</h4>
|
|
<div class="transform-buttons">
|
|
<div v-for="transform in getTransformsByCategory('cipher')" :key="transform.name" class="transform-button-group">
|
|
<button
|
|
@click="applyTransform(transform)"
|
|
class="transform-button transform-category-cipher"
|
|
:class="{ active: activeTransform === transform }"
|
|
:title="'Click to transform and copy: ' + transform.name"
|
|
>
|
|
{{ transform.name }}
|
|
<small class="transform-preview" v-if="transformInput">
|
|
{{ transform.preview(transformInput.slice(0, 10)) }}
|
|
</small>
|
|
<i class="fas fa-copy auto-copy-icon"></i>
|
|
</button>
|
|
<button
|
|
v-if="transformHasReverse(transform)"
|
|
@click="decodeWithTransform(transform)"
|
|
class="decode-button transform-category-cipher"
|
|
:title="'Click to decode using: ' + transform.name"
|
|
>
|
|
<i class="fas fa-undo"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Visual Category -->
|
|
<div id="category-visual" class="transform-category-section">
|
|
<h4 class="category-title transform-category-visual">Visual</h4>
|
|
<div class="transform-buttons">
|
|
<div v-for="transform in getTransformsByCategory('visual')" :key="transform.name" class="transform-button-group">
|
|
<button
|
|
@click="applyTransform(transform)"
|
|
class="transform-button transform-category-visual"
|
|
:class="{ active: activeTransform === transform }"
|
|
:title="'Click to transform and copy: ' + transform.name"
|
|
>
|
|
{{ transform.name }}
|
|
<small class="transform-preview" v-if="transformInput">
|
|
{{ transform.preview(transformInput.slice(0, 10)) }}
|
|
</small>
|
|
<i class="fas fa-copy auto-copy-icon"></i>
|
|
</button>
|
|
<button
|
|
v-if="transformHasReverse(transform)"
|
|
@click="decodeWithTransform(transform)"
|
|
class="decode-button transform-category-visual"
|
|
:title="'Click to decode using: ' + transform.name"
|
|
>
|
|
<i class="fas fa-undo"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Format Category -->
|
|
<div id="category-format" class="transform-category-section">
|
|
<h4 class="category-title transform-category-format">Formatting</h4>
|
|
<div class="transform-buttons">
|
|
<div v-for="transform in getTransformsByCategory('format')" :key="transform.name" class="transform-button-group">
|
|
<button
|
|
@click="applyTransform(transform)"
|
|
class="transform-button transform-category-format"
|
|
:class="{ active: activeTransform === transform }"
|
|
:title="'Click to transform and copy: ' + transform.name"
|
|
>
|
|
{{ transform.name }}
|
|
<small class="transform-preview" v-if="transformInput">
|
|
{{ transform.preview(transformInput.slice(0, 10)) }}
|
|
</small>
|
|
<i class="fas fa-copy auto-copy-icon"></i>
|
|
</button>
|
|
<button
|
|
v-if="transformHasReverse(transform)"
|
|
@click="decodeWithTransform(transform)"
|
|
class="decode-button transform-category-format"
|
|
:title="'Click to decode using: ' + transform.name"
|
|
>
|
|
<i class="fas fa-undo"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Unicode Category -->
|
|
<div id="category-unicode" class="transform-category-section">
|
|
<h4 class="category-title transform-category-unicode">Unicode</h4>
|
|
<div class="transform-buttons">
|
|
<div v-for="transform in getTransformsByCategory('unicode')" :key="transform.name" class="transform-button-group">
|
|
<button
|
|
@click="applyTransform(transform)"
|
|
class="transform-button transform-category-unicode"
|
|
:class="{ active: activeTransform === transform }"
|
|
:title="'Click to transform and copy: ' + transform.name"
|
|
>
|
|
{{ transform.name }}
|
|
<small class="transform-preview" v-if="transformInput">
|
|
{{ transform.preview(transformInput.slice(0, 10)) }}
|
|
</small>
|
|
<i class="fas fa-copy auto-copy-icon"></i>
|
|
</button>
|
|
<button
|
|
v-if="transformHasReverse(transform)"
|
|
@click="decodeWithTransform(transform)"
|
|
class="decode-button transform-category-unicode"
|
|
:title="'Click to decode using: ' + transform.name"
|
|
>
|
|
<i class="fas fa-undo"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Special Category -->
|
|
<div id="category-special" class="transform-category-section">
|
|
<h4 class="category-title transform-category-special">Special</h4>
|
|
<div class="transform-buttons">
|
|
<div v-for="transform in getTransformsByCategory('special')" :key="transform.name" class="transform-button-group">
|
|
<button
|
|
@click="applyTransform(transform)"
|
|
class="transform-button transform-category-special"
|
|
:class="{ active: activeTransform === transform }"
|
|
:title="'Click to transform and copy: ' + transform.name"
|
|
>
|
|
{{ transform.name }}
|
|
<small class="transform-preview" v-if="transformInput">
|
|
{{ transform.preview(transformInput.slice(0, 10)) }}
|
|
</small>
|
|
<i class="fas fa-copy auto-copy-icon"></i>
|
|
</button>
|
|
<button
|
|
v-if="transformHasReverse(transform)"
|
|
@click="decodeWithTransform(transform)"
|
|
class="decode-button transform-category-special"
|
|
:title="'Click to decode using: ' + transform.name"
|
|
>
|
|
<i class="fas fa-undo"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="output-section" v-if="transformOutput">
|
|
<div class="output-container">
|
|
<textarea
|
|
readonly
|
|
v-model="transformOutput"
|
|
aria-label="Transformed text output"
|
|
></textarea>
|
|
<button class="copy-button" @click="copyToClipboard(transformOutput)" title="Copy to clipboard">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Universal Decoder Section for Transforms Tab -->
|
|
<div class="decode-section">
|
|
<div class="section-header">
|
|
<h3><i class="fas fa-magic"></i> Universal Decoder</h3>
|
|
<p>Paste any encoded text to try all decoding methods at once</p>
|
|
</div>
|
|
<div class="input-container">
|
|
<textarea
|
|
id="universal-decode-input-transforms"
|
|
v-model="universalDecodeInput"
|
|
placeholder="Paste encoded text to decode automatically..."
|
|
@input="runUniversalDecode"
|
|
></textarea>
|
|
<div class="decoded-message" v-if="universalDecodeResult">
|
|
<div class="decode-method">Decoded using: <strong>{{ universalDecodeResult.method }}</strong></div>
|
|
<div class="decode-result">{{ universalDecodeResult.text }}</div>
|
|
<button class="copy-button" @click="copyToClipboard(universalDecodeResult.text)" title="Copy decoded text">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Copy History Panel -->
|
|
<div class="copy-history-panel" :class="{ 'active': showCopyHistory }">
|
|
<div class="copy-history-header">
|
|
<h3><i class="fas fa-history"></i> Copy History</h3>
|
|
<button class="close-button" @click="toggleCopyHistory" title="Close history">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="copy-history-content">
|
|
<div v-if="copyHistory.length === 0" class="no-history">
|
|
<p>No copy history yet. Use the app features to auto-copy content.</p>
|
|
</div>
|
|
<div v-else class="history-items">
|
|
<div v-for="(item, index) in copyHistory" :key="index" class="history-item">
|
|
<div class="history-item-header">
|
|
<span class="history-source">{{ item.source }}</span>
|
|
<span class="history-time">{{ item.timestamp }}</span>
|
|
</div>
|
|
<div class="history-content">
|
|
{{ item.content }}
|
|
</div>
|
|
<div class="history-actions">
|
|
<button class="copy-again-button" @click="copyToClipboard(item.content)" title="Copy again">
|
|
<i class="fas fa-copy"></i> Copy Again
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="js/transforms.js"></script>
|
|
<script src="js/steganography.js"></script>
|
|
<script src="js/emojiLibrary.js"></script>
|
|
<script src="js/app.js"></script>
|
|
|
|
<!-- Force emoji grid rendering -->
|
|
<script>
|
|
// Function to initialize emoji grid with retries
|
|
function initEmojiGrid(retryCount) {
|
|
retryCount = retryCount || 0;
|
|
const maxRetries = 5;
|
|
|
|
console.log('Initializing emoji grid, attempt:', retryCount + 1);
|
|
|
|
// Get the emoji library element
|
|
const emojiLibrary = document.querySelector('.emoji-library');
|
|
|
|
// Access the emoji grid container without forcing styles
|
|
const emojiGridContainer = document.getElementById('emoji-grid-container');
|
|
if (emojiGridContainer) {
|
|
console.log('Found emoji grid container, initializing...');
|
|
// Only set content, let CSS handle display
|
|
emojiGridContainer.innerHTML = '<div class="loading-emojis">Loading emoji grid...</div>';
|
|
|
|
// Manually render emoji grid
|
|
if (window.emojiLibrary && window.emojiLibrary.renderEmojiGrid) {
|
|
try {
|
|
window.emojiLibrary.renderEmojiGrid('emoji-grid-container', function(emoji) {
|
|
// Simulate emoji selection by calling the Vue method if possible
|
|
const app = document.getElementById('app').__vue__;
|
|
if (app && app.selectEmoji) {
|
|
app.selectEmoji(emoji);
|
|
}
|
|
});
|
|
console.log('Emoji grid successfully rendered');
|
|
} catch (error) {
|
|
console.error('Error rendering emoji grid:', error);
|
|
}
|
|
} else {
|
|
console.warn('Emoji library not yet available, will retry');
|
|
if (retryCount < maxRetries) {
|
|
setTimeout(() => initEmojiGrid(retryCount + 1), 500);
|
|
}
|
|
}
|
|
} else {
|
|
console.warn('Emoji grid container not found, will retry');
|
|
if (retryCount < maxRetries) {
|
|
setTimeout(() => initEmojiGrid(retryCount + 1), 500);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize when DOM is loaded
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// First attempt after a short delay to ensure Vue has initialized
|
|
setTimeout(initEmojiGrid, 500);
|
|
|
|
// Also initialize when switching to the steganography tab
|
|
const app = document.getElementById('app');
|
|
if (app && app.__vue__) {
|
|
const vue = app.__vue__;
|
|
// Watch for tab changes
|
|
const originalWatch = vue.$watch;
|
|
if (originalWatch) {
|
|
vue.$watch('activeTab', function(newTab) {
|
|
if (newTab === 'steganography') {
|
|
console.log('Switched to steganography tab, initializing emoji grid');
|
|
setTimeout(initEmojiGrid, 100);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|