diff --git a/android/app/src/main/assets/public/index.html b/android/app/src/main/assets/public/index.html index 2ee7428c..21ec1198 100644 --- a/android/app/src/main/assets/public/index.html +++ b/android/app/src/main/assets/public/index.html @@ -86,7 +86,6 @@ async function start() { updateLoadingStatus("loading.loading"); try { - gotoHome(); if (host != null) { await updateProtocolAndUrl(host); @@ -109,6 +108,7 @@ //if fails continue loading encryption may be broken console.error(e); } + gotoHome(); } else { showBlahNotification("error:auth.failed.redirect.to.login"); await delay(2000); diff --git a/android/app/src/main/assets/public/main.js b/android/app/src/main/assets/public/main.js index c3fd59d3..084d54cb 100644 --- a/android/app/src/main/assets/public/main.js +++ b/android/app/src/main/assets/public/main.js @@ -468,29 +468,49 @@ async function decryptString(base64Text, passphrase) { } +let requestMutex = Promise.resolve(); + async function fetchPost(url, value) { - let response = await fetch(url, { - method: "POST", - body: value, - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) - } - }); - let data = await response.text(); - return data; + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let response = await fetch(url, { + method: "POST", + body: value, + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) + } + }); + let data = await response.text(); + return data; + } finally { + release(); + } } async function fetchPostEnc(url, value) { - let nonce = await getNonce(id, passwordHash); - let response = await fetch(url, { - method: "POST", - body: await encryptWithNonce(value, passwordHash, nonce), - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) - } - }); - let data = await response.text(); - return data; + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let nonce = await getNonce(id, passwordHash); + let response = await fetch(url, { + method: "POST", + body: await encryptWithNonce(value, passwordHash, nonce), + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) + } + }); + let data = await response.text(); + return data; + } finally { + release(); + } } async function fetchAsync(url) { @@ -503,15 +523,24 @@ async function fetchAsync(url) { } async function fetchAsyncWAuth(url) { - let response = await fetch(url, { - method: "GET", - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) - } - }); + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let response = await fetch(url, { + method: "GET", + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) + } + }); - let data = await response.text(); - return data; + let data = await response.text(); + return data; + } finally { + release(); + } } async function getServerInfo(host) { @@ -520,48 +549,64 @@ async function getServerInfo(host) { } async function Auth(loginUsername, loginPassword) { - let resolvedId = await fetchAsync(`${url}/nametoid?u=${loginUsername}`); - if (!resolvedId || resolvedId.trim() === "" || resolvedId.startsWith("error:")) { - return "error:invalid.username.or.password"; - } - let actualId = resolvedId.split(":")[0]; - - let passwordHash = await hashSHA3_512(loginPassword); - let response = await fetch(`${url}/auth?id=${actualId}`, { - method: "GET", - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(actualId, passwordHash)) + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let resolvedId = await fetchAsync(`${url}/nametoid?u=${loginUsername}`); + if (!resolvedId || resolvedId.trim() === "" || resolvedId.startsWith("error:")) { + return "error:invalid.username.or.password"; } - }); + let actualId = resolvedId.split(":")[0]; - let data = await response.text(); - if (data.startsWith("success:")) { - data += "|" + actualId; + let passwordHash = await hashSHA3_512(loginPassword); + let response = await fetch(`${url}/auth?id=${actualId}`, { + method: "GET", + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(actualId, passwordHash)) + } + }); + + let data = await response.text(); + if (data.startsWith("success:")) { + data += "|" + actualId; + } + return data; + } finally { + release(); } - return data; - } async function fetchEncrypted(request, body = "") { + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let nonce = await getNonce(id, passwordHash); - let nonce = await getNonce(id, passwordHash); + let response = await fetch(`${url}/encryptedrequest?id=${id}`, { + method: "POST", + body: await encryptWithNonce( + JSON.stringify({ + string1: request, + string2: body + }) - let response = await fetch(`${url}/encryptedrequest?id=${id}`, { - method: "POST", - body: await encryptWithNonce( - JSON.stringify({ - string1: request, - string2: body - }) - - , passwordHash, nonce), - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) - } - }); - let data = await response.text(); - return decryptString(data, passwordHash); + , passwordHash, nonce), + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) + } + }); + let data = await response.text(); + return await decryptString(data, passwordHash); + } finally { + release(); + } } function power(base, exponent, mod) { diff --git a/webroot/blah/en-cat.json b/webroot/blah/en-cat.json index a41d1b4f..75fcf968 100644 --- a/webroot/blah/en-cat.json +++ b/webroot/blah/en-cat.json @@ -121,7 +121,7 @@ "placeholder.username": "cat name", "placeholder.captcha.code": "captcha code", "placeholder.message.input": "meow...", - "desc.messages.encryption.active": "meows are end-to-end encrypted :3", + "desc.messages.loading": "loading meows...", "desc.no.dms": "no direct meowchats :c", "action.dm.opening": "opening meowchat...", "dm.open.failed": "failed to open meowchat :c", diff --git a/webroot/blah/en-us.json b/webroot/blah/en-us.json index 31c45501..104354bb 100644 --- a/webroot/blah/en-us.json +++ b/webroot/blah/en-us.json @@ -120,7 +120,7 @@ "placeholder.username": "username", "placeholder.captcha.code": "captcha code", "placeholder.message.input": "Message...", - "desc.messages.encryption.active": "Messages are end-to-end encrypted", + "desc.messages.loading": "Fetching messages...", "desc.no.dms": "No direct messages", "action.dm.opening": "Opening DM...", "dm.open.failed": "Failed to open DM", diff --git a/webroot/index.html b/webroot/index.html index 2ee7428c..21ec1198 100644 --- a/webroot/index.html +++ b/webroot/index.html @@ -86,7 +86,6 @@ async function start() { updateLoadingStatus("loading.loading"); try { - gotoHome(); if (host != null) { await updateProtocolAndUrl(host); @@ -109,6 +108,7 @@ //if fails continue loading encryption may be broken console.error(e); } + gotoHome(); } else { showBlahNotification("error:auth.failed.redirect.to.login"); await delay(2000); diff --git a/webroot/main.js b/webroot/main.js index c3fd59d3..9a3c8b7d 100644 --- a/webroot/main.js +++ b/webroot/main.js @@ -468,29 +468,49 @@ async function decryptString(base64Text, passphrase) { } +let requestMutex = Promise.resolve(); + async function fetchPost(url, value) { - let response = await fetch(url, { - method: "POST", - body: value, - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) - } - }); - let data = await response.text(); - return data; + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let response = await fetch(url, { + method: "POST", + body: value, + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) + } + }); + let data = await response.text(); + return data; + } finally { + release(); + } } async function fetchPostEnc(url, value) { - let nonce = await getNonce(id, passwordHash); - let response = await fetch(url, { - method: "POST", - body: await encryptWithNonce(value, passwordHash, nonce), - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) - } - }); - let data = await response.text(); - return data; + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let nonce = await getNonce(id, passwordHash); + let response = await fetch(url, { + method: "POST", + body: await encryptWithNonce(value, passwordHash, nonce), + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) + } + }); + let data = await response.text(); + return data; + } finally { + release(); + } } async function fetchAsync(url) { @@ -503,15 +523,24 @@ async function fetchAsync(url) { } async function fetchAsyncWAuth(url) { - let response = await fetch(url, { - method: "GET", - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) - } - }); + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let response = await fetch(url, { + method: "GET", + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(id, passwordHash)) + } + }); - let data = await response.text(); - return data; + let data = await response.text(); + return data; + } finally { + release(); + } } async function getServerInfo(host) { @@ -520,48 +549,64 @@ async function getServerInfo(host) { } async function Auth(loginUsername, loginPassword) { - let resolvedId = await fetchAsync(`${url}/nametoid?u=${loginUsername}`); - if (!resolvedId || resolvedId.trim() === "" || resolvedId.startsWith("error:")) { - return "error:invalid.username.or.password"; - } - let actualId = resolvedId.split(":")[0]; - - let passwordHash = await hashSHA3_512(loginPassword); - let response = await fetch(`${url}/auth?id=${actualId}`, { - method: "GET", - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(actualId, passwordHash)) + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let resolvedId = await fetchAsync(`${url}/nametoid?u=${loginUsername}`); + if (!resolvedId || resolvedId.trim() === "" || resolvedId.startsWith("error:")) { + return "error:invalid.username.or.password"; } - }); + let actualId = resolvedId.split(":")[0]; - let data = await response.text(); - if (data.startsWith("success:")) { - data += "|" + actualId; + let passwordHash = await hashSHA3_512(loginPassword); + let response = await fetch(`${url}/auth?id=${actualId}`, { + method: "GET", + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(actualId, passwordHash)) + } + }); + + let data = await response.text(); + if (data.startsWith("success:")) { + data += "|" + actualId; + } + return data; + } finally { + release(); } - return data; - } async function fetchEncrypted(request, body = "") { + let release; + const lock = new Promise(resolve => release = resolve); + const prevMutex = requestMutex; + requestMutex = prevMutex.then(() => lock); + await prevMutex; + try { + let nonce = await getNonce(id, passwordHash); - let nonce = await getNonce(id, passwordHash); + let response = await fetch(`${url}/encryptedrequest?id=${id}`, { + method: "POST", + body: await encryptWithNonce( + JSON.stringify({ + string1: request, + string2: body + }) - let response = await fetch(`${url}/encryptedrequest?id=${id}`, { - method: "POST", - body: await encryptWithNonce( - JSON.stringify({ - string1: request, - string2: body - }) - - , passwordHash, nonce), - headers: { - "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) - } - }); - let data = await response.text(); - return decryptString(data, passwordHash); + , passwordHash, nonce), + headers: { + "secret": await encryptWithNonce(passwordHash, passwordHash, nonce) + } + }); + let data = await response.text(); + return await decryptString(data, passwordHash); + } finally { + release(); + } } function power(base, exponent, mod) { @@ -1807,7 +1852,7 @@ async function openDm(dmId, username, targetId) { let msgContainer = document.getElementById("chat-messages"); if (msgContainer) { - msgContainer.innerHTML = `