Fixed SEND_CHAT_MESSAGE bugs

This commit is contained in:
Justin Ferrari 2023-02-23 12:52:51 -05:00
parent 2d276d583f
commit 9a7cf9e4d4
3 changed files with 256 additions and 25 deletions

View File

@ -498,7 +498,9 @@
"bchange18": "Do you give this application permission to get your user address?", "bchange18": "Do you give this application permission to get your user address?",
"bchange19": "Do you give this application permission to publish to QDN?", "bchange19": "Do you give this application permission to publish to QDN?",
"bchange20": "Do you give this application permission to get your wallet balance?", "bchange20": "Do you give this application permission to get your wallet balance?",
"bchange21": "Fetch Wallet Failed. Please try again!" "bchange21": "Fetch Wallet Failed. Please try again!",
"bchange22": "Do you give this application permission to send a chat message?",
"bchange23": "Message Sent!"
}, },
"datapage": { "datapage": {
"dchange1": "Data Management", "dchange1": "Data Management",

View File

@ -16,6 +16,7 @@ registerTranslateConfig({
import '@material/mwc-button'; import '@material/mwc-button';
import '@material/mwc-icon'; import '@material/mwc-icon';
import WebWorker from 'web-worker:./computePowWorkerFile.src.js'; import WebWorker from 'web-worker:./computePowWorkerFile.src.js';
import WebWorkerChat from 'web-worker:./computePowWorker.src.js';
import { publishData } from '../../../utils/publish-image.js'; import { publishData } from '../../../utils/publish-image.js';
import { Loader } from '../../../utils/loader.js'; import { Loader } from '../../../utils/loader.js';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
@ -108,7 +109,8 @@ class WebBrowser extends LitElement {
constructor() { constructor() {
super(); super();
this.url = 'about:blank'; this.url = 'about:blank';
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress; this.myAddress = window.parent.reduxStore.getState().app.selectedAddress;
this._publicKey = { key: '', hasPubKey: false };
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
this.name = urlParams.get('name'); this.name = urlParams.get('name');
this.service = urlParams.get('service'); this.service = urlParams.get('service');
@ -231,7 +233,6 @@ class WebBrowser extends LitElement {
} }
render() { render() {
console.log(3, 'browser page here');
return html` return html`
<div id="websitesWrapper" style="width:auto; padding:10px; background: var(--white);"> <div id="websitesWrapper" style="width:auto; padding:10px; background: var(--white);">
<div class="layout horizontal center"> <div class="layout horizontal center">
@ -321,8 +322,8 @@ class WebBrowser extends LitElement {
console.log('UI received event: ' + JSON.stringify(data)); console.log('UI received event: ' + JSON.stringify(data));
switch (data.action) { switch (data.action) {
case 'GET_USER_ACCOUNT': case 'GET_USER_ACCOUNT':
case actions.GET_USER_ACCOUNT: case actions.GET_USER_ACCOUNT:
const res1 = await showModalAndWait( const res1 = await showModalAndWait(
actions.GET_USER_ACCOUNT actions.GET_USER_ACCOUNT
); );
@ -418,12 +419,159 @@ class WebBrowser extends LitElement {
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}` // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break; break;
case 'SEND_CHAT_MESSAGE': case 'SEND_CHAT_MESSAGE': {
const message = data.message;
const recipient = data.destinationAddress;
const sendMessage = async (messageText, chatReference) => {
this.loader.show();
let _reference = new Uint8Array(64);
window.crypto.getRandomValues(_reference);
let reference = window.parent.Base58.encode(_reference);
const sendMessageRequest = async () => {
let chatResponse = await parentEpml.request('chat', {
type: 18,
nonce: this.selectedAddress.nonce,
params: {
timestamp: Date.now(),
recipient: recipient,
recipientPublicKey: this._publicKey.key,
hasChatReference: 0,
chatReference: chatReference,
message: messageText,
lastReference: reference,
proofOfWorkNonce: 0,
isEncrypted: 1,
isText: 1
}
});
const msgResponse = await _computePow(chatResponse)
return msgResponse;
};
const _computePow = async (chatBytes) => {
const difficulty = 8;
const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
const worker = new WebWorkerChat();
let nonce = null;
let chatBytesArray = null;
await new Promise((res) => {
worker.postMessage({chatBytes, path, difficulty});
worker.onmessage = e => {
chatBytesArray = e.data.chatBytesArray;
nonce = e.data.nonce;
res();
}
});
let _response = await parentEpml.request('sign_chat', {
nonce: this.selectedAddress.nonce,
chatBytesArray: chatBytesArray,
chatNonce: nonce
});
const chatResponse = getSendChatResponse(_response);
return chatResponse;
};
const getSendChatResponse = (res) => {
if (res === true) {
let successString = get("browserpage.bchange23");
parentEpml.request('showSnackBar', `${successString}`);
} else if (res.error) {
parentEpml.request('showSnackBar', res.message);
}
this.loader.hide();
return res;
};
const chatResponse = await sendMessageRequest();
return chatResponse;
}
const result = await showModalAndWait(
actions.SEND_CHAT_MESSAGE
);
if (result.action === "accept") {
let hasPublicKey = true;
const res = await parentEpml.request('apiCall', {
type: 'api',
url: `/addresses/publickey/${recipient}`
});
if (res.error === 102) {
this._publicKey.key = ''
this._publicKey.hasPubKey = false
hasPublicKey = false;
} else if (res !== false) {
this._publicKey.key = res
this._publicKey.hasPubKey = true
} else {
this._publicKey.key = ''
this._publicKey.hasPubKey = false
hasPublicKey = false;
}
if (!hasPublicKey) {
let err4string = get("chatpage.cchange39");
parentEpml.request('showSnackBar', `${err4string}`)
return
}
this.loader.show();
const tiptapJson = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: message,
},
],
},
],
}
const messageObject = {
messageText: tiptapJson,
images: [''],
repliedTo: '',
version: 2
};
const stringifyMessageObject = JSON.stringify(messageObject);
// if (this.balance < 4) {
// this.myTrimmedMeassage = ''
// this.myTrimmedMeassage = stringifyMessageObject
// this.shadowRoot.getElementById('confirmDialog').open()
// } else {
// this.sendMessage(stringifyMessageObject, typeMessage);
// }
try {
const msgResponse = await sendMessage(stringifyMessageObject);
response = msgResponse;
} catch (error) {
console.error(error);
return '{"error": "Request could not be fulfilled"}';
} finally {
this.loader.hide();
console.log("Case completed.");
}
} else {
response = '{"error": "User declined request"}';
}
// this.loader.show();
// Params: data.groupId, data.destinationAddress, data.message // Params: data.groupId, data.destinationAddress, data.message
// TODO: prompt user to send chat message. If they confirm, sign+process a CHAT transaction // TODO: prompt user to send chat message. If they confirm, sign+process a CHAT transaction
// then set the response string from the core to the `response` variable (defined above) // then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}` // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break; break;
}
case actions.JOIN_GROUP: case actions.JOIN_GROUP:
const groupId = data.groupId; const groupId = data.groupId;
@ -450,8 +598,7 @@ class WebBrowser extends LitElement {
// TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address` // TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
// then set the response string from the core to the `response` variable (defined above) // then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}` // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
console.log({data}); const res3 = await showModalAndWait(
const res3 = await showModalAndWait(
actions.GET_WALLET_BALANCE actions.GET_WALLET_BALANCE
); );
if (res3.action === 'accept') { if (res3.action === 'accept') {
@ -463,7 +610,6 @@ class WebBrowser extends LitElement {
const QORTBalance = await parentEpml.request('apiCall', { const QORTBalance = await parentEpml.request('apiCall', {
url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`, url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`,
}) })
console.log({QORTBalance})
return QORTBalance; return QORTBalance;
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -504,19 +650,21 @@ class WebBrowser extends LitElement {
break break
} }
try { try {
this.loader.show() this.loader.show();
await parentEpml.request('apiCall', { const res = await parentEpml.request('apiCall', {
url: _url, url: _url,
method: 'POST', method: 'POST',
body: _body, body: _body,
}).then((res) => {
if (isNaN(Number(res))) {
throw new Error(get("browserpage.bchange21"));
} else {
console.log((Number(res) / 1e8).toFixed(8), "other wallet balance here");
return (Number(res) / 1e8).toFixed(8)
}
}) })
if (isNaN(Number(res))) {
const data = {};
const errorMsg = error.message || get("browserpage.bchange21");
data['error'] = errorMsg;
response = JSON.stringify(data);
return;
} else {
response = (Number(res) / 1e8).toFixed(8);
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
const data = {}; const data = {};
@ -534,7 +682,6 @@ class WebBrowser extends LitElement {
break; break;
case 'SEND_COIN': case 'SEND_COIN':
console.log({data});
// Params: data.coin, data.destinationAddress, data.amount, data.fee // Params: data.coin, data.destinationAddress, data.amount, data.fee
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction // TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
// then set the response string from the core to the `response` variable (defined above) // then set the response string from the core to the `response` variable (defined above)
@ -697,12 +844,12 @@ class WebBrowser extends LitElement {
} finally { } finally {
console.log("Case completed."); console.log("Case completed.");
} }
break; break;
default: default:
console.log('Unhandled message: ' + JSON.stringify(data)); console.log('Unhandled message: ' + JSON.stringify(data));
return; return;
} }
// Parse response // Parse response
let responseObj; let responseObj;
@ -712,7 +859,6 @@ class WebBrowser extends LitElement {
// Not all responses will be JSON // Not all responses will be JSON
responseObj = response; responseObj = response;
} }
// Respond to app // Respond to app
if (responseObj.error != null) { if (responseObj.error != null) {
event.ports[0].postMessage({ event.ports[0].postMessage({
@ -1050,6 +1196,7 @@ async function showModalAndWait(type, data) {
${type === actions.GET_USER_ACCOUNT ? `<p class="modal-paragraph">${get("browserpage.bchange18")}</p>` : ''} ${type === actions.GET_USER_ACCOUNT ? `<p class="modal-paragraph">${get("browserpage.bchange18")}</p>` : ''}
${type === actions.PUBLISH_QDN_RESOURCE ? `<p class="modal-paragraph">${get("browserpage.bchange19")}</p>` : ''} ${type === actions.PUBLISH_QDN_RESOURCE ? `<p class="modal-paragraph">${get("browserpage.bchange19")}</p>` : ''}
${type === actions.GET_WALLET_BALANCE ? `<p class="modal-paragraph">${get("browserpage.bchange20")}</p>` : ''} ${type === actions.GET_WALLET_BALANCE ? `<p class="modal-paragraph">${get("browserpage.bchange20")}</p>` : ''}
${type === actions.SEND_CHAT_MESSAGE ? `<p class="modal-paragraph">${get("browserpage.bchange22")}</p>` : ''}
</div> </div>
<div class="modal-buttons"> <div class="modal-buttons">
<button id="cancel-button">Reject</button> <button id="cancel-button">Reject</button>

View File

@ -0,0 +1,82 @@
import { Sha256 } from 'asmcrypto.js'
function sbrk(size, heap){
let brk = 512 * 1024 // stack top
let old = brk
brk += size
if (brk > heap.length)
throw new Error('heap exhausted')
return old
}
self.addEventListener('message', async e => {
const response = await computePow(e.data.chatBytes, e.data.path, e.data.difficulty)
postMessage(response)
})
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
const heap = new Uint8Array(memory.buffer)
const computePow = async (chatBytes, path, difficulty) => {
let response = null
await new Promise((resolve, reject)=> {
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
const chatBytesArray = new Uint8Array(_chatBytesArray);
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result;
const hashPtr = sbrk(32, heap);
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32);
hashAry.set(chatBytesHash);
const workBufferLength = 8 * 1024 * 1024;
const workBufferPtr = sbrk(workBufferLength, heap);
const importObject = {
env: {
memory: memory
},
};
function loadWebAssembly(filename, imports) {
// Fetch the file and compile it
return fetch(filename)
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
// Create the instance.
return new WebAssembly.Instance(module, importObject);
});
}
loadWebAssembly(path)
.then(wasmModule => {
response = {
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
chatBytesArray
}
resolve()
});
})
return response
}