forked from ComputerTech/bastebin
129 lines
4.8 KiB
HTML
129 lines
4.8 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ cfg.site.name }}{% endblock %}
|
|
{% block main_class %}full-page{% endblock %}
|
|
|
|
{% block nav_actions %}
|
|
<span id="navPasteTitle" class="nav-paste-title"></span>
|
|
<button onclick="rawView()" class="nav-btn">Raw</button>
|
|
<button onclick="copyPaste()" class="nav-btn">Copy</button>
|
|
<button onclick="downloadPaste()" class="nav-btn">Download</button>
|
|
<a href="{{ url_for('index') }}" class="nav-btn nav-btn-save">New</a>
|
|
{% if cfg.theme.allow_user_toggle %}
|
|
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
|
{% endif %}
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div id="errorState" class="error-inline" style="display:none">
|
|
🔐 <strong id="errorTitle">Decryption Failed</strong> — <span id="errorDetail"></span>
|
|
</div>
|
|
<div class="view-full" id="viewFull" style="display:none">
|
|
<pre id="viewPre"><code id="codeBlock"></code></pre>
|
|
</div>
|
|
<script type="application/json" id="encryptedPayload">{{ paste.encrypted_data | tojson }}</script>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
let _decryptedPaste = null;
|
|
const E2E = {{ cfg.features.encrypt_pastes | tojson }};
|
|
|
|
(async function () {
|
|
let rawPayload;
|
|
try {
|
|
rawPayload = JSON.parse(document.getElementById('encryptedPayload').textContent);
|
|
} catch (e) {
|
|
showError('Bad Data', 'Could not read the paste payload.');
|
|
return;
|
|
}
|
|
|
|
if (E2E) {
|
|
const keyBase64 = window.location.hash.slice(1);
|
|
if (!keyBase64) {
|
|
showError('No Key', 'The decryption key is missing from the URL. Use the full link including the # part.');
|
|
return;
|
|
}
|
|
try {
|
|
const key = await PasteCrypto.importKey(keyBase64);
|
|
const plaintext = await PasteCrypto.decrypt(rawPayload, key);
|
|
_decryptedPaste = JSON.parse(plaintext);
|
|
} catch (e) {
|
|
showError('Decryption Failed', 'Wrong key or tampered data.');
|
|
return;
|
|
}
|
|
} else {
|
|
try {
|
|
_decryptedPaste = JSON.parse(rawPayload);
|
|
} catch (e) {
|
|
showError('Bad Data', 'Could not parse paste data.');
|
|
return;
|
|
}
|
|
}
|
|
|
|
renderPaste(_decryptedPaste);
|
|
})();
|
|
|
|
function renderPaste(paste) {
|
|
const title = paste.title || 'Untitled';
|
|
document.title = title + ' — {{ cfg.site.name }}';
|
|
document.getElementById('navPasteTitle').textContent = title;
|
|
|
|
const lang = paste.language || 'text';
|
|
const prismLangMap = { text: false, html: 'markup', xml: 'markup', docker: 'docker' };
|
|
const prismLang = (lang in prismLangMap) ? prismLangMap[lang] : lang;
|
|
|
|
const codeBlock = document.getElementById('codeBlock');
|
|
const viewPre = document.getElementById('viewPre');
|
|
codeBlock.textContent = paste.content || '';
|
|
if (prismLang) {
|
|
codeBlock.className = 'language-' + prismLang;
|
|
viewPre.className = 'language-' + prismLang;
|
|
Prism.highlightElement(codeBlock);
|
|
}
|
|
|
|
document.getElementById('viewFull').style.display = 'block';
|
|
}
|
|
|
|
function showError(title, detail) {
|
|
document.getElementById('errorTitle').textContent = title;
|
|
document.getElementById('errorDetail').textContent = detail;
|
|
document.getElementById('errorState').style.display = 'block';
|
|
}
|
|
|
|
function rawView() {
|
|
if (!_decryptedPaste) return;
|
|
const blob = new Blob([_decryptedPaste.content], { type: 'text/plain; charset=utf-8' });
|
|
const url = URL.createObjectURL(blob);
|
|
window.open(url, '_blank');
|
|
setTimeout(() => URL.revokeObjectURL(url), 10000);
|
|
}
|
|
|
|
async function copyPaste() {
|
|
if (!_decryptedPaste) return;
|
|
const ok = await copyToClipboard(_decryptedPaste.content);
|
|
const btn = document.querySelector('.nav-btn[onclick="copyPaste()"]');
|
|
if (btn) { const t = btn.textContent; btn.textContent = ok ? 'Copied!' : 'Failed'; setTimeout(() => btn.textContent = t, 1500); }
|
|
}
|
|
|
|
function downloadPaste() {
|
|
if (!_decryptedPaste) return;
|
|
const { title = 'untitled', content = '', language = 'text' } = _decryptedPaste;
|
|
const extMap = {
|
|
javascript: '.js', typescript: '.ts', python: '.py', java: '.java',
|
|
c: '.c', cpp: '.cpp', csharp: '.cs', html: '.html', css: '.css',
|
|
scss: '.scss', sql: '.sql', json: '.json', yaml: '.yaml', xml: '.xml',
|
|
bash: '.sh', powershell: '.ps1', php: '.php', ruby: '.rb', go: '.go',
|
|
rust: '.rs', swift: '.swift', kotlin: '.kt', markdown: '.md',
|
|
diff: '.diff', docker: '', nginx: '.conf', toml: '.toml', ini: '.ini',
|
|
};
|
|
const filename = title.replace(/[^a-z0-9.\-]/gi, '_') + (extMap[language] ?? '.txt');
|
|
const blob = new Blob([content], { type: 'text/plain' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = Object.assign(document.createElement('a'), { href: url, download: filename });
|
|
document.body.appendChild(a); a.click(); document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
</script>
|
|
{% endblock %}
|