diff --git a/.gitignore b/.gitignore index fc46120..928f5aa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ config.toml /test-frontend/default.json +/test-frontend/.well-known result result-* diff --git a/test-frontend/index.html b/test-frontend/index.html index d63aa3a..fa2a504 100644 --- a/test-frontend/index.html +++ b/test-frontend/index.html @@ -50,8 +50,10 @@
- - + + + +
@@ -63,6 +65,7 @@ pattern="https://.*" required /> +
diff --git a/test-frontend/main.js b/test-frontend/main.js index 3519e30..f60752f 100644 --- a/test-frontend/main.js +++ b/test-frontend/main.js @@ -1,5 +1,6 @@ const msgFlow = document.querySelector('#msg-flow'); -const userPubkeyDisplay = document.querySelector('#user-pubkey'); +const idPubkeyInput = document.querySelector('#id-pubkey'); +const actPubkeyDisplay = document.querySelector('#act-pubkey'); const serverUrlInput = document.querySelector('#server-url'); const roomsInput = document.querySelector('#rooms'); const joinNewRoomInput = document.querySelector('#join-new-room'); @@ -22,8 +23,16 @@ function hexToBuf(hex) { return new Uint8Array(hex.match(/[\da-f]{2}/gi).map(m => parseInt(m, 16))) } -async function getUserPubkey() { - if (keypair === null) throw new Error('no userkey'); +function getIdPubkey() { + const s = idPubkeyInput.value.trim(); + if (!s.match(/^[a-zA-Z0-9]{64}$/)) { + throw new Error(`invalid id_key, please re-enter: ${s}`); + } + return s; +} + +async function getActPubkey() { + if (keypair === null) throw new Error('no actkey'); return bufToHex(await crypto.subtle.exportKey('raw', keypair.publicKey)); } @@ -80,9 +89,11 @@ async function generateKeypair() { `, true ); + return; } log('keypair generated'); + actPubkeyDisplay.value = await getActPubkey(); document.querySelectorAll('input, button, select').forEach((el) => el.disabled = false); try { @@ -97,6 +108,37 @@ async function generateKeypair() { } } +async function register() { + function norm(url) { + return String(url).endsWith('/') ? url : url + '/'; + } + + try { + const idUrl = prompt('id_url:', defaultConfig.id_url || ''); + if (idUrl === null) return; + + const getResp = await fetch(`${serverUrl}/user/me`, { + cache: 'no-store' + }) + console.log(getResp.headers); + const challenge = getResp.headers.get('x-blah-nonce'); + if (challenge === null) throw new Error('cannot get challenge nonce'); + + const postResp = await signAndPost(`${serverUrl}/user/me`, { + // sorted fields. + challenge_nonce: parseInt(challenge), + id_key: getIdPubkey(), + id_url: norm(idUrl), + server_url: norm(serverUrl), + typ: 'user_register', + }) + if (!postResp.ok) throw new Error(`status ${getResp.status}: ${(await getResp.json()).error.message}`); + log('registered') + } catch (err) { + log(`failed to register: ${err}`) + } +} + async function showChatMsg(chat) { let verifyRet = null; try { @@ -304,7 +346,7 @@ async function joinRoom(rid) { permission: 1, // POST_CHAT room: rid, typ: 'add_member', - user: await getUserPubkey(), + user: await getActPubkey(), }); log('joined room'); await loadRoomList(false) @@ -322,7 +364,7 @@ async function leaveRoom() { await signAndPost(`${serverUrl}/room/${curRoom}/admin`, { room: curRoom, typ: 'remove_member', - user: await getUserPubkey(), + user: await getActPubkey(), }); log('left room'); await loadRoomList(true); @@ -351,17 +393,20 @@ async function signAndPost(url, data) { } async function signData(payload) { - const userKey = await getUserPubkey(); + const userKey = await getActPubkey(); const nonceBuf = new Uint32Array(1); crypto.getRandomValues(nonceBuf); const timestamp = (Number(new Date()) / 1000) | 0; const signee = { + // sorted fields. + act_key: userKey, + id_key: getIdPubkey(), nonce: nonceBuf[0], payload, timestamp, - user: userKey, }; + console.log(JSON.stringify(signee)); const signeeBytes = (new TextEncoder()).encode(JSON.stringify(signee)); const sig = await crypto.subtle.sign('Ed25519', keypair.privateKey, signeeBytes); @@ -421,7 +466,10 @@ window.onload = async (_) => { await generateKeypair(); } if (keypair !== null) { - userPubkeyDisplay.value = await getUserPubkey(); + actPubkeyDisplay.value = await getActPubkey(); + } + if (idPubkeyInput.value === '' && defaultConfig.id_key) { + idPubkeyInput.value = defaultConfig.id_key; } if (serverUrlInput.value === '' && defaultConfig.server_url) { serverUrlInput.value = defaultConfig.server_url; @@ -444,6 +492,7 @@ function onButtonClick(selector, handler) { } onButtonClick('#leave-room', leaveRoom); onButtonClick('#regen-key', generateKeypair); +onButtonClick('#register', register); onButtonClick('#refresh-rooms', async () => await loadRoomList(true)); onButtonClick('#mark-seen', markSeen);