mirror of
https://github.com/Blah-IM/blahrs.git
synced 2025-05-01 08:41:09 +00:00
feat(frontend): impl register and fix
This commit is contained in:
parent
3af64f35a5
commit
a9ca9b976c
3 changed files with 63 additions and 10 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,5 +4,6 @@
|
||||||
|
|
||||||
config.toml
|
config.toml
|
||||||
/test-frontend/default.json
|
/test-frontend/default.json
|
||||||
|
/test-frontend/.well-known
|
||||||
result
|
result
|
||||||
result-*
|
result-*
|
||||||
|
|
|
@ -50,8 +50,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="input-area">
|
<div id="input-area">
|
||||||
<div>
|
<div>
|
||||||
<label for="user-pubkey">user pubkey:</label>
|
<label for="id-pubkey">id_pubkey:</label>
|
||||||
<input type="text" id="user-pubkey" placeholder="-" readonly />
|
<input type="text" id="id-pubkey" placeholder="-" />
|
||||||
|
<label for="act-pubkey">act_pubkey:</label>
|
||||||
|
<input type="text" id="act-pubkey" placeholder="-" readonly />
|
||||||
<button id="regen-key">regenerate</button>
|
<button id="regen-key">regenerate</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -63,6 +65,7 @@
|
||||||
pattern="https://.*"
|
pattern="https://.*"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<button id="register">register</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="rooms">joined rooms:</label>
|
<label for="rooms">joined rooms:</label>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const msgFlow = document.querySelector('#msg-flow');
|
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 serverUrlInput = document.querySelector('#server-url');
|
||||||
const roomsInput = document.querySelector('#rooms');
|
const roomsInput = document.querySelector('#rooms');
|
||||||
const joinNewRoomInput = document.querySelector('#join-new-room');
|
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)))
|
return new Uint8Array(hex.match(/[\da-f]{2}/gi).map(m => parseInt(m, 16)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserPubkey() {
|
function getIdPubkey() {
|
||||||
if (keypair === null) throw new Error('no userkey');
|
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));
|
return bufToHex(await crypto.subtle.exportKey('raw', keypair.publicKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,9 +89,11 @@ async function generateKeypair() {
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log('keypair generated');
|
log('keypair generated');
|
||||||
|
actPubkeyDisplay.value = await getActPubkey();
|
||||||
document.querySelectorAll('input, button, select').forEach((el) => el.disabled = false);
|
document.querySelectorAll('input, button, select').forEach((el) => el.disabled = false);
|
||||||
|
|
||||||
try {
|
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) {
|
async function showChatMsg(chat) {
|
||||||
let verifyRet = null;
|
let verifyRet = null;
|
||||||
try {
|
try {
|
||||||
|
@ -304,7 +346,7 @@ async function joinRoom(rid) {
|
||||||
permission: 1, // POST_CHAT
|
permission: 1, // POST_CHAT
|
||||||
room: rid,
|
room: rid,
|
||||||
typ: 'add_member',
|
typ: 'add_member',
|
||||||
user: await getUserPubkey(),
|
user: await getActPubkey(),
|
||||||
});
|
});
|
||||||
log('joined room');
|
log('joined room');
|
||||||
await loadRoomList(false)
|
await loadRoomList(false)
|
||||||
|
@ -322,7 +364,7 @@ async function leaveRoom() {
|
||||||
await signAndPost(`${serverUrl}/room/${curRoom}/admin`, {
|
await signAndPost(`${serverUrl}/room/${curRoom}/admin`, {
|
||||||
room: curRoom,
|
room: curRoom,
|
||||||
typ: 'remove_member',
|
typ: 'remove_member',
|
||||||
user: await getUserPubkey(),
|
user: await getActPubkey(),
|
||||||
});
|
});
|
||||||
log('left room');
|
log('left room');
|
||||||
await loadRoomList(true);
|
await loadRoomList(true);
|
||||||
|
@ -351,17 +393,20 @@ async function signAndPost(url, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function signData(payload) {
|
async function signData(payload) {
|
||||||
const userKey = await getUserPubkey();
|
const userKey = await getActPubkey();
|
||||||
const nonceBuf = new Uint32Array(1);
|
const nonceBuf = new Uint32Array(1);
|
||||||
crypto.getRandomValues(nonceBuf);
|
crypto.getRandomValues(nonceBuf);
|
||||||
const timestamp = (Number(new Date()) / 1000) | 0;
|
const timestamp = (Number(new Date()) / 1000) | 0;
|
||||||
const signee = {
|
const signee = {
|
||||||
|
// sorted fields.
|
||||||
|
act_key: userKey,
|
||||||
|
id_key: getIdPubkey(),
|
||||||
nonce: nonceBuf[0],
|
nonce: nonceBuf[0],
|
||||||
payload,
|
payload,
|
||||||
timestamp,
|
timestamp,
|
||||||
user: userKey,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(JSON.stringify(signee));
|
||||||
const signeeBytes = (new TextEncoder()).encode(JSON.stringify(signee));
|
const signeeBytes = (new TextEncoder()).encode(JSON.stringify(signee));
|
||||||
const sig = await crypto.subtle.sign('Ed25519', keypair.privateKey, signeeBytes);
|
const sig = await crypto.subtle.sign('Ed25519', keypair.privateKey, signeeBytes);
|
||||||
|
|
||||||
|
@ -421,7 +466,10 @@ window.onload = async (_) => {
|
||||||
await generateKeypair();
|
await generateKeypair();
|
||||||
}
|
}
|
||||||
if (keypair !== null) {
|
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) {
|
if (serverUrlInput.value === '' && defaultConfig.server_url) {
|
||||||
serverUrlInput.value = defaultConfig.server_url;
|
serverUrlInput.value = defaultConfig.server_url;
|
||||||
|
@ -444,6 +492,7 @@ function onButtonClick(selector, handler) {
|
||||||
}
|
}
|
||||||
onButtonClick('#leave-room', leaveRoom);
|
onButtonClick('#leave-room', leaveRoom);
|
||||||
onButtonClick('#regen-key', generateKeypair);
|
onButtonClick('#regen-key', generateKeypair);
|
||||||
|
onButtonClick('#register', register);
|
||||||
onButtonClick('#refresh-rooms', async () => await loadRoomList(true));
|
onButtonClick('#refresh-rooms', async () => await loadRoomList(true));
|
||||||
onButtonClick('#mark-seen', markSeen);
|
onButtonClick('#mark-seen', markSeen);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue