microbin/templates/upload.html
Daniel Szabo 7fdc89a48d Disabled ediiting for secrets
Realistically this privacy level should not allow modifying the data, but even if we did support that, the UX would be very annoying - it is better to make a new upload
2023-07-11 21:21:41 +03:00

394 lines
No EOL
12 KiB
HTML

{% include "header.html" %}
<div style="float: left">
{% if pasta.content != "" %}
<button id="copy-text-button" class="small-button" style="margin-right:
0.5rem">
Copy Text
</button>
{% if args.public_path_as_str() != "" && pasta.pasta_type == "url" %}
<button id="copy-redirect-button" class="small-button" style="margin-right:
0.5rem">
Copy Redirect
</button>
{%- endif %}
<a style="margin-right: 1rem" href="{{ args.public_path_as_str() }}/raw/{{pasta.id_as_animals()}}">Raw Text
Content</a>
{%- endif %} {% if args.qr && args.public_path_as_str() != "" %}
<a style="margin-right: 1rem" href="{{ args.public_path_as_str() }}/qr/{{pasta.id_as_animals()}}">QR</a>
{%- endif %} {% if pasta.editable && !pasta.encrypt_client %}
<a style="margin-right: 1rem" href="{{ args.public_path_as_str() }}/edit/{{pasta.id_as_animals()}}">Edit</a>
{%- endif %}
<a style="margin-right: 1rem" href="{{ args.public_path_as_str() }}/remove/{{pasta.id_as_animals()}}">Remove</a>
</div>
<div style="float: right">
<a style="margin-right: 0.5rem"
href="{{ args.public_path_as_str() }}/upload/{{pasta.id_as_animals()}}"><i>{{pasta.id_as_animals()}}</i></a>
{% if args.public_path_as_str() != "" %}
<button id="copy-url-button" class="small-button" style="margin-right: 0">
Copy URL
</button>
{%- endif %}
</div>
<br>
<br>
{% if pasta.encrypt_client %}
<span style="margin-left: auto; margin-right: auto; display: flex;
justify-content: center; align-items: center;">
<div id="decryption">
{% if pasta.encrypt_client %}
<label for="password-field" style="margin-bottom: 0.5em;">
Please enter your key to decrypt this upload. <sup> <a href="/guide#encryption"></a></sup>
</label>
<input class="small-button" placeholder="Key" style="margin-right: 0.5rem" type="password" id="password-field"
autocomplete="off" />
{% if pasta.content != "" %}
<button class="small-button" id="decrypt-button" style="margin-right:
0.5rem">
<b>
Decrypt text
</b>
</button>
{%- endif %}
{%- endif %}
{% if pasta.file.is_some() && !pasta.file_embeddable() %}
<button class="small-button" id="download-button" style="margin-right:
0.5rem">
<b>
Download {{pasta.file.as_ref().unwrap().name()}}
[{{pasta.file.as_ref().unwrap().size}}]
</b>
</button>
{%- endif %}
</div>
</span>
{%- endif %}
<br>
{% if pasta.content != "" %}
<div class="code-container">
<div style="clear: both;">
{% if pasta.extension == "auto" || pasta.encrypt_client %}
<pre><code id="code">{{pasta.content_escaped()}}</code></pre>
{% else if args.highlightsyntax %}
<pre><code id="code">{{pasta.content_syntax_highlighted()}}</code></pre>
{% else %}
<pre><code id="code">{{pasta.content_not_highlighted()}}</code></pre>
{%- endif %}
</div>
</div>
{%- endif %}
{% if pasta.file.is_some() && !pasta.file_embeddable() && !pasta.encrypt_client %}
<span style="margin-left: auto; margin-right: auto; display: flex;
justify-content: center; align-items: center;">
<p style="font-size: small;">{{pasta.file.as_ref().unwrap().name()}}
[{{pasta.file.as_ref().unwrap().size}}]</p>
<a href="{{ args.public_path_as_str()}}/file/{{pasta.id_as_animals()}}" id="download-link">
<button class="download-button" autofocus>
Download
</button>
</a>
</span>
{%- endif %}
{% if pasta.file.is_some() && pasta.file.as_ref().unwrap().is_image() &&
pasta.file_embeddable() && !pasta.encrypt_client %}
<img id="embed" src="{{ args.public_path_as_str()}}/file/{{pasta.id_as_animals()}}" height="300" />
<span style="margin-left: auto; margin-right: auto; display: flex;
justify-content: center; align-items: center;">
<p style="font-size: small;">{{pasta.file.as_ref().unwrap().name()}}
[{{pasta.file.as_ref().unwrap().size}}]</p>
<a href="{{ args.public_path_as_str() }}/file/{{pasta.id_as_animals()}}" id="download-link" download>
<button class="download-button" autofocus>
Download
</button>
</a>
</span>
{%- endif %}
{% if pasta.file.is_some() && pasta.file.as_ref().unwrap().is_video() &&
pasta.file_embeddable() && !pasta.encrypt_client %}
<video id="embed" controls src="{{ args.public_path_as_str()}}/file/{{pasta.id_as_animals()}}" height="300"></video>
<span style="margin-left: auto; margin-right: auto; display: flex;
justify-content: center; align-items: center;">
<p style="font-size: small;">{{pasta.file.as_ref().unwrap().name()}}
[{{pasta.file.as_ref().unwrap().size}}]</p>
<a href="{{ args.public_path_as_str() }}/file/{{pasta.id_as_animals()}}" download id="download-link">
<button class="download-button">
Download
</button>
</a>
</span>
{%- endif %}
<div>
{% if args.show_read_stats %} {% if pasta.read_count == 1 %}
<p style="font-size: small">Read {{pasta.read_count}} time, last
{{pasta.last_read_time_ago_as_string()}}</p>
{%- else %}
<p style="font-size: small">Read {{pasta.read_count}} times, last
{{pasta.last_read_time_ago_as_string()}}</p>
{%- endif %} {%- endif %}
</div>
<br>
<script type="text/javascript" src="{{ args.public_path_as_str() }}/static/highlight/highlight.min.js"></script>
<link rel="stylesheet" href="{{ args.public_path_as_str()}}/static/highlight/highlight.min.css">
<script>
const copyURLBtn = document.getElementById("copy-url-button")
const copyTextBtn = document.getElementById("copy-text-button")
const copyRedirectBtn = document.getElementById("copy-redirect-button")
var content = `{{ pasta.content_escaped() }}`
const contentElement = document.getElementById("code");
const url = (`{{ args.short_path_as_str()}}` === "") ? `{{ args.public_path_as_str() }}/upload/{{pasta.id_as_animals()}}` : `{{ args.short_path_as_str()}}/p/{{pasta.id_as_animals()}}`
const redirect_url = (`{{ args.short_path_as_str()}}` === "") ? `{{ args.public_path_as_str() }}/url/{{pasta.id_as_animals()}}` : `{{ args.short_path_as_str()}}/u/{{pasta.id_as_animals()}}`
const te = new TextEncoder();
// {% if pasta.extension == "auto" && !pasta.encrypt_client %}
onload = (event) => {
contentElement.innerHTML = content;
hljs.highlightAll();
contentElement.innerHTML =
wrapStringInCodeLines(contentElement.innerHTML);
};
// {% endif %}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
function wrapStringInCodeLines(str) {
const lines = str.split(/\r?\n/); // split the string into an array of lines
const wrappedLines = lines.map((line) => `<code-line>${line}</code-line>`); // wrap each line in a "code-line" tag
return wrappedLines.join("\n"); // join the wrapped lines back into a single string with line breaks
}
const decodeEntity = (inputStr) => {
var textarea = document.createElement("textarea");
textarea.innerHTML = inputStr;
return textarea.value;
}
if (copyURLBtn) {
copyURLBtn.addEventListener("click", () => {
navigator.clipboard.writeText(url)
copyURLBtn.innerHTML = "Copied"
setTimeout(() => {
copyURLBtn.innerHTML = "Copy URL"
}, 1000)
})
}
// it will be undefined when the element does not exist on non-url pastas
if (copyRedirectBtn) {
copyRedirectBtn.addEventListener("click", () => {
navigator.clipboard.writeText(redirect_url)
copyRedirectBtn.innerHTML = "Copied"
setTimeout(() => {
copyRedirectBtn.innerHTML = "Copy Redirect"
}, 1000)
})
}
if (copyTextBtn) {
copyTextBtn.addEventListener("click", () => {
const decodeContent = decodeEntity(content)
navigator.clipboard.writeText(decodeContent)
copyTextBtn.innerHTML = "Copied"
setTimeout(() => {
copyTextBtn.innerHTML = "Copy Text"
}, 1000)
})
}
// {% if pasta.encrypt_client %}
const decryptDiv = document.getElementById('decryption');
const decryptButton = document.getElementById('decrypt-button');
const passwordField = document.getElementById("password-field");
const downloadButton = document.getElementById('download-button');
// {% if pasta.file.is_some() %}
// Set up event listener for download link click
downloadButton.addEventListener('click', async (event) => {
event.preventDefault(); // prevent default click behavior
if (passwordField.value.trim() == "") {
passwordField.focus();
return false;
}
// Fetch encrypted file from server
const formData = new FormData();
// {% if pasta.encrypted_key.is_some() %}
let key = decryptWithPassword(passwordField.value.trim(), "{{ pasta.encrypted_key.as_ref().unwrap() }}");
// {%- endif %}
formData.append('password', key);
const response = await fetch('/secure_file/{{ pasta.id_as_animals() }}', {
method: 'POST',
body: formData,
})
// {% if pasta.file.is_some() %}
const encryptedFile = await response.text();
// Decrypt file contents
const decryptedContents = decryptFileWithPassword(passwordField.value.trim(), encryptedFile);
if (!decryptedContents) {
throw new Error('Failed to decrypt file');
}
// Create blob from decrypted file contents
const decryptedBlob = new Blob([decryptedContents], { type: 'application/octet-stream' });
// Create data URI for decrypted file
// const dataUri = `data:application/octet-stream;${encodeURIComponent(decryptedContents)}`;
// Create temporary anchor element
const tempAnchorEl = document.createElement('a');
// tempAnchorEl.href = dataUri;
tempAnchorEl.href = URL.createObjectURL(decryptedBlob);
tempAnchorEl.download = '{{pasta.file.as_ref().unwrap().name()}}';
// Programmatically click anchor element to trigger download
tempAnchorEl.click();
// {%- endif %}
});
// {% endif %}
decryptButton.addEventListener("click", () => {
password = passwordField.value;
content = contentDecrypted = escapeHtml(decryptWithPassword(password, content));
if (contentDecrypted) {
contentElement.innerHTML = contentDecrypted;
// {% if pasta.extension == "auto" %}
hljs.highlightAll();
// {% endif %}
contentElement.innerHTML = wrapStringInCodeLines(contentElement.innerHTML);
// decryptDiv.style.display = 'none';
}
});
function decryptWithPassword(password, encryptedHex) {
const passwordBytes = aesjs.utils.utf8.toBytes(password.padStart(32, "#"));
const encryptedBytes = aesjs.utils.hex.toBytes(encryptedHex);
const aesCtr = new aesjs.ModeOfOperation.ctr(passwordBytes);
const decryptedBytes = aesCtr.decrypt(encryptedBytes);
const res = aesjs.utils.utf8.fromBytes(decryptedBytes);
if (res.endsWith("!0K")) {
return res.substring(0, res.length - "!0K".length);
} else {
return null;
}
}
function decryptFileWithPassword(password, encryptedHex) {
const passwordBytes = aesjs.utils.utf8.toBytes(password.padStart(32, "#"));
const encryptedBytes = aesjs.utils.hex.toBytes(encryptedHex);
const aesCtr = new aesjs.ModeOfOperation.ctr(passwordBytes);
const decryptedBytes = aesCtr.decrypt(encryptedBytes);
return decryptedBytes;
}
// {% endif %}
</script>
<style>
code-line {
counter-increment: line;
text-align: right;
float: left;
clear: left;
}
code-line::before {
content: counter(line);
display: inline-block;
padding-left: auto;
margin-left: auto;
text-align: left;
width: 1.8rem;
border-right: 1px solid lightgrey;
color: grey;
margin-right: 0.4rem;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#code {
min-height: 2rem;
}
#embed {
background-color: #f7f7f7;
border-radius: 6px;
margin-top: 1rem;
margin-bottom: 1rem;
width: fit-content;
margin-left: auto;
margin-right: auto;
max-height: 480px;
display: flex;
justify-content: center;
align-items: center;
}
.download-button {
margin-left: 1rem;
font-size: small;
padding: 4px;
padding-left: 0.8rem;
padding-right: 0.8rem;
cursor: pointer;
}
.code-container {
position: relative;
}
.hidden {
display: none;
}
.small-button {
font-size: small;
padding: 4px;
padding-left: 0.8rem;
padding-right: 0.8rem;
cursor: pointer;
}
</style>
{% if !args.pure_html %}
<style>
#decryption {
background-color: #f7f7f7;
border-radius: 6px;
padding: 10px;
width: fit-content;
}
</style>
{% endif %}
{% include "footer.html" %}