Skip to content

Instantly share code, notes, and snippets.

@mrnerdhair
Created September 22, 2024 05:29
Show Gist options
  • Save mrnerdhair/49dedd899358a6cc4a7c0d56eddb6995 to your computer and use it in GitHub Desktop.
Save mrnerdhair/49dedd899358a6cc4a7c0d56eddb6995 to your computer and use it in GitHub Desktop.
<!doctype html>
<html>
<head>
<meta charset="utf8">
<meta http-equiv="Content-Security-Policy" content="
default-src
'none';
style-src
'sha512-kT0v1BxcibEO2Yc+6Z3W1gNsN+2cZ/U6uITqHhIJl8SAvt9vpO8llugdCPXA7cCnp8G1xbuSqHNMRaR3Zlz9yA=='
'sha512-8Bv8zoQXXuQjsOLm0XflNqACcwAlT1Pd4z6hjt/JgZDRwdPQH2bR4PqlWjXV19eDDjUybxLBmXlecknb2jPCxQ=='
'unsafe-inline';
script-src
'sha512-NjCCP22dfRqI3FGzH9vC7sMs2xkWnquGqxTMzvQ2xYCsDDou0rICdGkW6OTef8PNqYIblgUFgLQc9ZitlH10wQ=='
'sha512-aLSwsdjU35MF6PERT7Pic3+X6qL7O+Us8hYQl/gjrPoV4JXUNoCF2Ys3/vfJSiBW1QNxz2WTr4tEo5VcOdHt/g=='
'sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSQX0FslNhTDadL4O5SAGapGt4FodqL8My0mA=='
'sha512-ZHzbWDQKpcZxIT9l5KhcnwQTidZFzwK/c7gpUUsFvGjEsxPusdUCyFxjjpc7e/Wj7vLhfMujNx7COwOmzbn+2w=='
'sha512-Q0E5vAcPB1nO8YCNZZ2tS0AVRZBgEB/78fofZsp3gHmrQzhZtcUJbunoCxEPf0ZLdJH2GRTE4plVXkQDrIESvQ=='
'unsafe-inline';
connect-src
https://cdnjs.cloudflare.com/ajax/libs/toastify-js/1.12.0/toastify.css
https://dweet.io/socket.io/1/
wss://dweet.io/socket.io/1/websocket/;
img-src
data:;
require-trusted-types-for 'script';
">
<style>
#qrDiv {
position: fixed;
inset: 0;
width: fit-content;
height: fit-content;
margin: auto;
}
</style>
</head>
<body>
<div id="qrDiv"></div>
<script>
// This is so stupid, but the hash-based style-src CSP doesn't work with a link tag for some reason.
window.loadedToastify = fetch("https://cdnjs.cloudflare.com/ajax/libs/toastify-js/1.12.0/toastify.css", {
credentials: "omit",
integrity: "sha512-kT0v1BxcibEO2Yc+6Z3W1gNsN+2cZ/U6uITqHhIJl8SAvt9vpO8llugdCPXA7cCnp8G1xbuSqHNMRaR3Zlz9yA==",
referrerPolicy: "no-referrer",
}).then(resp => resp.text()).then(x => {
const style = document.createElement("style")
style.textContent = x
document.head.appendChild(style)
})
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tweetnacl/1.0.2/nacl-fast.min.js" integrity="sha512-aLSwsdjU35MF6PERT7Pic3+X6qL7O+Us8hYQl/gjrPoV4JXUNoCF2Ys3/vfJSiBW1QNxz2WTr4tEo5VcOdHt/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" integrity="sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSQX0FslNhTDadL4O5SAGapGt4FodqL8My0mA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastify-js/1.12.0/toastify.js" integrity="sha512-ZHzbWDQKpcZxIT9l5KhcnwQTidZFzwK/c7gpUUsFvGjEsxPusdUCyFxjjpc7e/Wj7vLhfMujNx7COwOmzbn+2w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function openWs(...args) {
return new Promise((resolve, reject) => {
const ws = new WebSocket(...args)
const listeners = {
resolve: () => {
ws.removeEventListener("open", listeners.resolve)
ws.removeEventListener("error", listeners.reject)
resolve(ws)
}, reject: (event) => {
ws.removeEventListener("open", listeners.resolve)
ws.removeEventListener("error", listeners.reject)
reject(event)
}
}
ws.addEventListener("open", listeners.resolve)
ws.addEventListener("error", listeners.reject)
})
}
function wsExpect(ws) {
return new Promise((resolve, reject) => {
const listeners = {
resolve: (event) => {
ws.removeEventListener("message", listeners.resolve)
ws.removeEventListener("close", listeners.reject)
ws.removeEventListener("error", listeners.reject)
resolve(event.data)
}, reject: (event) => {
ws.removeEventListener("message", listeners.resolve)
ws.removeEventListener("close", listeners.reject)
ws.removeEventListener("error", listeners.reject)
reject(event)
}
}
ws.addEventListener("message", listeners.resolve)
ws.addEventListener("close", listeners.reject)
ws.addEventListener("error", listeners.reject)
})
}
async function expect(x, y) {
const x2 = await x
if (x2 !== y) throw x2
return x2
}
async function waitForDweet(topic, listener) {
const resp = await fetch(`https://dweet.io/socket.io/1/?t=${Date.now()}`)
if (!resp.ok) throw resp
const slug = (await resp.text()).split(':')[0]
const ws = await openWs(`wss://dweet.io/socket.io/1/websocket/${slug}`)
try {
await expect(wsExpect(ws), "1::")
ws.send("1::/stream")
await expect(wsExpect(ws), "1::/stream")
ws.send(`5::/stream:${JSON.stringify({
name: "subscribe",
args: [
{
thing: topic,
key: null,
},
],
})}`)
while (true) {
const msg = await wsExpect(ws)
if (msg === "2::") {
ws.send("2::")
} else if (msg.startsWith("5::/stream:")) {
ws.send("2::")
const out = JSON.parse(msg.substr("5::/stream:".length))
if (out.name === "new_dweet" && out.args && out.args.length > 0 && out.args[0].thing === topic) {
await listener(out.args[0].content)
}
} else {
throw msg
}
}
} finally {
ws.close(1000)
}
}
function hex(x) {
return Array.from(x).map(i => i.toString(16).padStart(2, '0')).join('')
}
function unhex(x) {
return Uint8Array.from(x.match(/.{2}/g).map((byte) => parseInt(byte, 16)))
}
async function go() {
const kp = nacl.box.keyPair()
const pk = hex(kp.publicKey)
const qr = new QRCode(document.getElementById("qrDiv"), {useSVG: true})
qr.makeCode(JSON.stringify({pk}))
await waitForDweet(pk, async (payload) => {
const output = JSON.parse(new TextDecoder().decode(nacl.box.open(
unhex(payload.c),
unhex(payload.n),
unhex(payload.pk),
kp.secretKey,
)))
console.log(output)
const toast = Toastify({
text: {toString: () => {
return output || "(empty string)"
}},
duration: -1,
close: false,
gravity: "bottom",
position: "center",
style: (output ? undefined : {
color: "grey",
fontStyle: "italic",
}),
onClick: () => {
navigator.clipboard.writeText(output)
toast.hideToast()
}
})
toast.showToast()
})
}
window.loadedToastify.then(go).then(undefined, (e) => {
console.error(e)
Toastify({
text: e,
duration: -1,
close: false,
gravity: "bottom",
position: "center",
style: {
background: "red",
},
onClick: () => {
window.location.reload()
},
})
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment