Last active
October 25, 2022 14:55
-
-
Save ylxdzsw/552a90ece24de187b163aff0d37820b7 to your computer and use it in GitHub Desktop.
Ugly alternative to [nopaste](https://github.com/bokub/nopaste), but is a self-contained single-file HTML. [Live version](https://nopaste.ylxdzsw.com/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<meta name="viewport" content="width=device-width, initial-scale=1"/> | |
<p><a href="https://caniuse.com/?search=deflate-raw">only these browsers are supported<a> | |
<p><textarea rows=10 cols=50 style="font: .9em monospace"></textarea> | |
<p><label>Password: <input></input></label> <button id="decrypt">Decrypt</button> | |
<p id="fool" style="display: none"><a href="https://xkcd.com/936/">Don't fool yourself with a weak password</a> | |
<p><button id="getlink">GetLink</button> (Will encrypt if password is not empty) | |
<pre><a></a></pre> | |
<script> | |
document.querySelector("#getlink").addEventListener("click", async () => { | |
const text = document.querySelector("textarea").value | |
const encoded = new TextEncoder().encode(text) | |
const compressor = new CompressionStream("deflate-raw") | |
const writer = compressor.writable.getWriter() | |
writer.write(encoded).then(() => writer.close()) | |
let to_encode = await new Response(compressor.readable).arrayBuffer() | |
const password = document.querySelector("input").value | |
if (password) { | |
if (password.length < 8) | |
document.querySelector("#fool").style.display = "block" | |
const iv = crypto.getRandomValues(new Uint8Array(12)) | |
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, await get_key(password), to_encode) | |
to_encode = [...iv, ...new Uint8Array(encrypted)] | |
} | |
const link = new URL('', location.href).href + '#' + btoa(String.fromCharCode(...new Uint8Array(to_encode))) | |
.replace(/\+/g, "-") | |
.replace(/\//g, "_") | |
.replace(/=/g, "") | |
document.querySelector("pre>a").href = link | |
document.querySelector("pre>a").textContent = link | |
}) | |
async function get_key(password) { | |
const password_encoded = new TextEncoder().encode(password) | |
const base_key = await crypto.subtle.importKey("raw", password_encoded, "PBKDF2", false, ["deriveKey"]) | |
return await crypto.subtle.deriveKey({ | |
name: "PBKDF2", | |
salt: new Uint8Array([109, 111, 51, 57]), | |
iterations: 201025, | |
hash: "SHA-256" | |
}, base_key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]) | |
} | |
async function decode() { | |
try { | |
const compressed = new Uint8Array(atob(location.hash.slice(1) | |
.replace(/-/g, "+") | |
.replace(/_/g, "/")) | |
.split("") | |
.map(c => c.charCodeAt(0))) | |
const password = document.querySelector("input").value | |
const to_decode = password | |
? await crypto.subtle.decrypt({ name: "AES-GCM", iv: compressed.slice(0, 12) }, await get_key(password), compressed.slice(12)) | |
: compressed | |
const decompressor = new DecompressionStream("deflate-raw") | |
const writer = decompressor.writable.getWriter() | |
writer.write(to_decode).then(() => writer.close()) | |
const text = await new Response(decompressor.readable).text() | |
document.querySelector("textarea").value = text | |
} catch (e) { | |
document.querySelector("textarea").value = "Decoding failed (It may be encrypted)." | |
} | |
} | |
document.querySelector("input").addEventListener("input", () => document.querySelector("#fool").style.display = "none") | |
document.querySelector("#decrypt").addEventListener("click", decode) | |
if (location.hash.length > 1) | |
decode() | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment