| … | … | @@ -3,6 +3,7 @@ import { serveStatic } from "jsr:@hono/hono/deno"; |
| 3 | 3 | import { marked } from "https://esm.sh/gh/evbogue/bog5@de70376265/lib/marked.esm.js"; |
| 4 | 4 | |
| 5 | 5 | import { foot, head } from "./template.js"; |
| 6 | import tryApp from "./try_app.js"; | |
| 6 | 7 | |
| 7 | 8 | const app = new Hono(); |
| 8 | 9 | |
| … | … | @@ -17,129 +18,11 @@ app.get("/", async (c) => { |
| 17 | 18 | </div> |
| 18 | 19 | `; |
| 19 | 20 | |
| 20 | const html = await head("Index") + content + await foot(); | |
| 21 | const html = await head("ANProto") + content + await foot(); | |
| 21 | 22 | return await c.html(html); |
| 22 | 23 | }); |
| 23 | 24 | |
| 24 | app.get("/try", async (c) => { | |
| 25 | const body = `<body> | |
| 26 | <div id='scroller'> | |
| 27 | <div class='message'> | |
| 28 | <h1>Try ANProto</h1> | |
| 29 | ||
| 30 | <p><em>An Interactive Demonstration</em></p> | |
| 31 | ||
| 32 | <p><strong>Step 1.</strong> Generate an ed25519 keypair</p> | |
| 33 | ||
| 34 | <code>const kp = await an.gen()</code> | |
| 35 | ||
| 36 | <input style='width: 100%;' id='key' placeholder='Make a keypair'></input> | |
| 37 | ||
| 38 | <button id='but'>Generate keypair</button> | |
| 39 | ||
| 40 | </div> | |
| 41 | ||
| 42 | <div class='message'> | |
| 43 | ||
| 44 | <p><strong>Step 2.</strong> Hash your blob with sha256</p> | |
| 45 | ||
| 46 | <code>const hash = await an.hash(content)</code> | |
| 47 | ||
| 48 | <input style='width: 100%;' id='content' placeholder='Write a message'></input> | |
| 49 | ||
| 50 | <button id='hash'>Generate hash</button> | |
| 51 | ||
| 52 | <span id='sha256'></span> | |
| 53 | ||
| 54 | </div> | |
| 55 | ||
| 56 | <div class='message'> | |
| 57 | ||
| 58 | <p><strong>Step 3.</strong> Sign the ANProto message</p> | |
| 59 | ||
| 60 | <code>const sig = await an.sign(hash, keypair)</code> | |
| 61 | ||
| 62 | <input style='width: 100%' id='sig'></input> | |
| 63 | ||
| 64 | <button id='sign'>Sign message</button> | |
| 65 | ||
| 66 | </div> | |
| 67 | <div class="message"> | |
| 68 | ||
| 69 | <p><strong>Step 4.</strong> Open the ANProto message</p> | |
| 70 | ||
| 71 | <code>const opened = await an.open(msg)</code> | |
| 72 | ||
| 73 | <input style='width: 100%;' id='openen'></input> | |
| 74 | ||
| 75 | <button id='open'>Open</button> | |
| 76 | ||
| 77 | </div> | |
| 78 | <div class="message"> | |
| 79 | ||
| 80 | <p><strong>Step 5.</strong> Retrieve the blob</p> | |
| 81 | ||
| 82 | <span id='msg'></span> | |
| 83 | ||
| 84 | <button id='get'>Get</button> | |
| 85 | ||
| 86 | </div> | |
| 87 | </div> | |
| 88 | </body> | |
| 89 | ||
| 90 | <script type='module'> | |
| 91 | import { an } from './an.js' | |
| 92 | ||
| 93 | const key = document.getElementById('key') | |
| 94 | const button = document.getElementById('but') | |
| 95 | ||
| 96 | button.onclick = async () => { | |
| 97 | key.value = await an.gen() | |
| 98 | } | |
| 99 | ||
| 100 | const content = document.getElementById('content') | |
| 101 | const hashbutton = document.getElementById('hash') | |
| 102 | const sha = document.getElementById('sha256') | |
| 103 | ||
| 104 | let blobs = [] | |
| 105 | ||
| 106 | hashbutton.onclick = async () => { | |
| 107 | sha.textContent = await an.hash(content.value) | |
| 108 | blobs[sha.textContent] = content.value | |
| 109 | } | |
| 110 | ||
| 111 | const siginput = document.getElementById('sig') | |
| 112 | const signbutton = document.getElementById('sign') | |
| 113 | ||
| 114 | signbutton.onclick = async () => { | |
| 115 | siginput.value = await an.sign(sha.textContent, key.value) | |
| 116 | } | |
| 117 | ||
| 118 | const openbutton = document.getElementById('open') | |
| 119 | ||
| 120 | const openen = document.getElementById('openen') | |
| 121 | ||
| 122 | openbutton.onclick = async () => { | |
| 123 | openen.value = await an.open(siginput.value) | |
| 124 | } | |
| 125 | ||
| 126 | const msgspan = document.getElementById('msg') | |
| 127 | const getbutton = document.getElementById('get') | |
| 128 | ||
| 129 | getbutton.onclick = async () => { | |
| 130 | msgspan.textContent = blobs[openen.value.substring(13)] | |
| 131 | if (openen.value.substring(13) == sha.textContent) { | |
| 132 | msgspan.textContent = msgspan.textContent + ' ✅' | |
| 133 | } else { | |
| 134 | msgspan.textContent = msgspan.textContent + ' ❌' | |
| 135 | } | |
| 136 | } | |
| 137 | ||
| 138 | </script>`; | |
| 139 | ||
| 140 | const html = await head("Try it") + body + await foot(); | |
| 141 | return await c.html(html); | |
| 142 | }); | |
| 25 | app.route("/try", tryApp); | |
| 143 | 26 | |
| 144 | 27 | app.use( |
| 145 | 28 | "*", |
| … | … | @@ -1,9 +1,10 @@ |
| 1 | export const head = async (title) => { | |
| 1 | export const head = async (title, navLabel) => { | |
| 2 | const navText = navLabel ?? `<span style="color: #fe7a00;">AN</span>Proto`; | |
| 2 | 3 | return await ` |
| 3 | 4 | <!doctype html> |
| 4 | 5 | <html> |
| 5 | 6 | <head> |
| 6 | <title>ANProto | ${title}</title> | |
| 7 | <title>${title}</title> | |
| 7 | 8 | <link rel='stylesheet' href='./style.css' type='text/css' /> |
| 8 | 9 | <meta name='viewport' content='width=device-width initial-scale=1' /> |
| 9 | 10 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
| … | … | @@ -16,8 +17,7 @@ export const head = async (title) => { |
| 16 | 17 | <body> |
| 17 | 18 | <div id='navbar'> |
| 18 | 19 | <a href='/'><img src='https://wiredove.net/doveorange_sm.png' class='avatar_small' style='vertical-align: middle;'></a> |
| 19 | <strong><span style="color: #fe7a00;">AN</span>Proto</strong> | |
| 20 | <strong><a href='./try'>Try it</a></strong> | |
| 20 | <strong>${navText}</strong> | |
| 21 | 21 | </div> |
| 22 | 22 | `; |
| 23 | 23 | }; |
| … | … | @@ -0,0 +1,137 @@ |
| 1 | import { Hono } from "jsr:@hono/hono"; | |
| 2 | import { serveStatic } from "jsr:@hono/hono/deno"; | |
| 3 | ||
| 4 | import { foot, head } from "./template.js"; | |
| 5 | ||
| 6 | const app = new Hono(); | |
| 7 | ||
| 8 | app.use( | |
| 9 | "*", | |
| 10 | serveStatic({ | |
| 11 | root: "./", | |
| 12 | onFound: (_path, c) => { | |
| 13 | c.header("Access-Control-Allow-Origin", "*"); | |
| 14 | }, | |
| 15 | }), | |
| 16 | ); | |
| 17 | ||
| 18 | app.get("/", async (c) => { | |
| 19 | const body = `<body> | |
| 20 | <div id='scroller'> | |
| 21 | <div class='message'> | |
| 22 | <p><em>An Interactive Demonstration</em></p> | |
| 23 | ||
| 24 | <p><strong>Step 1.</strong> Generate an ed25519 keypair</p> | |
| 25 | ||
| 26 | <code>const kp = await an.gen()</code> | |
| 27 | ||
| 28 | <input style='width: 100%;' id='key' placeholder='Make a keypair'></input> | |
| 29 | ||
| 30 | <button id='but'>Generate keypair</button> | |
| 31 | ||
| 32 | </div> | |
| 33 | ||
| 34 | <div class='message'> | |
| 35 | ||
| 36 | <p><strong>Step 2.</strong> Hash your blob with sha256</p> | |
| 37 | ||
| 38 | <code>const hash = await an.hash(content)</code> | |
| 39 | ||
| 40 | <input style='width: 100%;' id='content' placeholder='Write a message'></input> | |
| 41 | ||
| 42 | <button id='hash'>Generate hash</button> | |
| 43 | ||
| 44 | <span id='sha256'></span> | |
| 45 | ||
| 46 | </div> | |
| 47 | ||
| 48 | <div class='message'> | |
| 49 | ||
| 50 | <p><strong>Step 3.</strong> Sign the ANProto message</p> | |
| 51 | ||
| 52 | <code>const sig = await an.sign(hash, keypair)</code> | |
| 53 | ||
| 54 | <input style='width: 100%' id='sig'></input> | |
| 55 | ||
| 56 | <button id='sign'>Sign message</button> | |
| 57 | ||
| 58 | </div> | |
| 59 | <div class="message"> | |
| 60 | ||
| 61 | <p><strong>Step 4.</strong> Open the ANProto message</p> | |
| 62 | ||
| 63 | <code>const opened = await an.open(msg)</code> | |
| 64 | ||
| 65 | <input style='width: 100%;' id='openen'></input> | |
| 66 | ||
| 67 | <button id='open'>Open</button> | |
| 68 | ||
| 69 | </div> | |
| 70 | <div class="message"> | |
| 71 | ||
| 72 | <p><strong>Step 5.</strong> Retrieve the blob</p> | |
| 73 | ||
| 74 | <span id='msg'></span> | |
| 75 | ||
| 76 | <button id='get'>Get</button> | |
| 77 | ||
| 78 | </div> | |
| 79 | </div> | |
| 80 | </body> | |
| 81 | ||
| 82 | <script type='module'> | |
| 83 | import { an } from './an.js' | |
| 84 | ||
| 85 | const key = document.getElementById('key') | |
| 86 | const button = document.getElementById('but') | |
| 87 | ||
| 88 | button.onclick = async () => { | |
| 89 | key.value = await an.gen() | |
| 90 | } | |
| 91 | ||
| 92 | const content = document.getElementById('content') | |
| 93 | const hashbutton = document.getElementById('hash') | |
| 94 | const sha = document.getElementById('sha256') | |
| 95 | ||
| 96 | let blobs = [] | |
| 97 | ||
| 98 | hashbutton.onclick = async () => { | |
| 99 | sha.textContent = await an.hash(content.value) | |
| 100 | blobs[sha.textContent] = content.value | |
| 101 | } | |
| 102 | ||
| 103 | const siginput = document.getElementById('sig') | |
| 104 | const signbutton = document.getElementById('sign') | |
| 105 | ||
| 106 | signbutton.onclick = async () => { | |
| 107 | siginput.value = await an.sign(sha.textContent, key.value) | |
| 108 | } | |
| 109 | ||
| 110 | const openbutton = document.getElementById('open') | |
| 111 | ||
| 112 | const openen = document.getElementById('openen') | |
| 113 | ||
| 114 | openbutton.onclick = async () => { | |
| 115 | openen.value = await an.open(siginput.value) | |
| 116 | } | |
| 117 | ||
| 118 | const msgspan = document.getElementById('msg') | |
| 119 | const getbutton = document.getElementById('get') | |
| 120 | ||
| 121 | getbutton.onclick = async () => { | |
| 122 | msgspan.textContent = blobs[openen.value.substring(13)] | |
| 123 | if (openen.value.substring(13) == sha.textContent) { | |
| 124 | msgspan.textContent = msgspan.textContent + ' ✅' | |
| 125 | } else { | |
| 126 | msgspan.textContent = msgspan.textContent + ' ❌' | |
| 127 | } | |
| 128 | } | |
| 129 | ||
| 130 | </script>`; | |
| 131 | ||
| 132 | const navLabel = `Try <span style="color: #fe7a00;">AN</span>Proto`; | |
| 133 | const html = await head("Try ANProto", navLabel) + body + await foot(); | |
| 134 | return await c.html(html); | |
| 135 | }); | |
| 136 | ||
| 137 | export default app; |
| … | … | @@ -0,0 +1,6 @@ |
| 1 | import tryApp from "./try_app.js"; | |
| 2 | ||
| 3 | const port = 8788; | |
| 4 | const hostname = "::"; | |
| 5 | ||
| 6 | Deno.serve({ port, hostname }, tryApp.fetch); |