Skip to content

Instantly share code, notes, and snippets.

@ylxdzsw
Last active October 25, 2022 14:55
Show Gist options
  • Save ylxdzsw/552a90ece24de187b163aff0d37820b7 to your computer and use it in GitHub Desktop.
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/)
<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