From 83ebfff6114ff9285e080595e1547bded1e7f7f9 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Sat, 11 Jan 2025 18:29:14 +0200 Subject: [PATCH] update send chat message qortalRequest --- src/components/Apps/AppViewer.tsx | 3 +- src/qortalRequests.ts | 4 +- src/qortalRequests/get.ts | 149 ++++++++++++++++++++++++------ 3 files changed, 126 insertions(+), 30 deletions(-) diff --git a/src/components/Apps/AppViewer.tsx b/src/components/Apps/AppViewer.tsx index 6b55ed0..cef2d8d 100644 --- a/src/components/Apps/AppViewer.tsx +++ b/src/components/Apps/AppViewer.tsx @@ -189,7 +189,8 @@ export const AppViewer = React.forwardRef(({ app , hide, isDevMode}, iframeRef) height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`, border: 'none', width: '100%' - }} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" allow="fullscreen"> + }} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" + allow="fullscreen; clipboard-read; clipboard-write"> diff --git a/src/qortalRequests.ts b/src/qortalRequests.ts index bd3e688..78a305a 100644 --- a/src/qortalRequests.ts +++ b/src/qortalRequests.ts @@ -376,7 +376,7 @@ export const isRunningGateway = async ()=> { case "GET_USER_WALLET": { try { - const res = await getUserWallet(request.payload, isFromExtension); + const res = await getUserWallet(request.payload, isFromExtension, appInfo); event.source.postMessage({ requestId: request.requestId, action: request.action, @@ -416,7 +416,7 @@ export const isRunningGateway = async ()=> { case "GET_USER_WALLET_INFO": { try { - const res = await getUserWalletInfo(request.payload, isFromExtension); + const res = await getUserWalletInfo(request.payload, isFromExtension, appInfo); event.source.postMessage({ requestId: request.requestId, action: request.action, diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts index aa9b30b..ff3c63c 100644 --- a/src/qortalRequests/get.ts +++ b/src/qortalRequests/get.ts @@ -1416,15 +1416,42 @@ export const createPoll = async (data, isFromExtension) => { } }; + +function isBase64(str) { + const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; + return base64Regex.test(str) && str.length % 4 === 0; +} + +function checkValue(value) { + if (typeof value === "string") { + if (isBase64(value)) { + return 'string' + } else { + return 'string' + } + } else if (typeof value === "object" && value !== null) { + return 'object' + } else { + throw new Error('Field fullContent is in an invalid format. Either use a string, base64 or an object.') + } +} + + export const sendChatMessage = async (data, isFromExtension, appInfo) => { const message = data?.message; - const fullMessageObject = data?.fullMessageObject - const recipient = data.destinationAddress; + const fullMessageObject = data?.fullMessageObject || data?.fullContent + const recipient = data?.destinationAddress || data.recipient; const groupId = data.groupId; - const isRecipient = !groupId; - - const value = - (await getPermission(`qAPPSendChatMessage-${appInfo?.name}`)) || false; + const isRecipient = groupId === undefined; + const chatReference = data?.chatReference + if(groupId === undefined && recipient === undefined){ + throw new Error('Please provide a recipient or groupId') + } + let fullMessageObjectType + if(fullMessageObject){ + fullMessageObjectType = checkValue(fullMessageObject) + } + const value = (await getPermission(`qAPPSendChatMessage-${appInfo?.name}`)) || false; let skip = false; if (value) { skip = true; @@ -1436,7 +1463,7 @@ if (!skip) { text1: "Do you give this application permission to send this chat message?", text2: `To: ${isRecipient ? recipient : `group ${groupId}`}`, - text3: `${message?.slice(0, 25)}${message?.length > 25 ? "..." : ""}`, + text3: fullMessageObject ? fullMessageObjectType === 'string' ? `${fullMessageObject?.slice(0, 25)}${fullMessageObject?.length > 25 ? "..." : ""}` : `${JSON.stringify(fullMessageObject)?.slice(0, 25)}${JSON.stringify(fullMessageObject)?.length > 25 ? "..." : ""}` : `${message?.slice(0, 25)}${message?.length > 25 ? "..." : ""}`, checkbox1: { value: false, label: "Always allow chat messages from this app", @@ -1471,7 +1498,10 @@ if (!skip) { version: 3, }; - const stringifyMessageObject = JSON.stringify(messageObject); + let stringifyMessageObject = JSON.stringify(messageObject); + if(fullMessageObjectType === 'string'){ + stringifyMessageObject = messageObject + } const balance = await getBalanceInfo(); const hasEnoughBalance = +balance < 4 ? false : true; @@ -1527,16 +1557,22 @@ if (!skip) { publicKey: uint8PublicKey, }; + let handleDynamicValues = {} + if(chatReference){ + handleDynamicValues['chatReference'] = chatReference + } + const tx = await createTransaction(18, keyPair, { timestamp: sendTimestamp, recipient: recipient, recipientPublicKey: key, - hasChatReference: 0, + hasChatReference: chatReference ? 1 : 0, message: stringifyMessageObject, lastReference: reference, proofOfWorkNonce: 0, isEncrypted: 1, isText: 1, + ...handleDynamicValues }); const chatBytes = tx.chatBytes; @@ -1565,16 +1601,22 @@ if (!skip) { publicKey: uint8PublicKey, }; + let handleDynamicValues = {} + if(chatReference){ + handleDynamicValues['chatReference'] = chatReference + } + const txBody = { timestamp: Date.now(), groupID: Number(groupId), hasReceipient: 0, - hasChatReference: 0, + hasChatReference: chatReference ? 1 : 0, message: stringifyMessageObject, lastReference: reference, proofOfWorkNonce: 0, isEncrypted: 0, // Set default to not encrypted for groups isText: 1, + ...handleDynamicValues }; const tx = await createTransaction(181, keyPair, txBody); @@ -1771,7 +1813,7 @@ export const deployAt = async (data, isFromExtension) => { } }; -export const getUserWallet = async (data, isFromExtension) => { +export const getUserWallet = async (data, isFromExtension, appInfo) => { const requiredFields = ["coin"]; const missingFields: string[] = []; requiredFields.forEach((field) => { @@ -1790,17 +1832,43 @@ export const getUserWallet = async (data, isFromExtension) => { throw new Error( "Cannot view ARRR wallet info through the gateway. Please use your local node." ); - const resPermission = await getUserPermission( + + const value = + (await getPermission( + `qAPPAutoGetUserWallet-${appInfo?.name}-${data.coin}` + )) || false; + let skip = false; + if (value) { + skip = true; + } + + let resPermission; + + if (!skip) { + resPermission = await getUserPermission( { text1: "Do you give this application permission to get your wallet information?", highlightedText: `coin: ${data.coin}`, + checkbox1: { + value: true, + label: "Always allow wallet to be retrieved automatically", + }, }, isFromExtension ); - const { accepted } = resPermission; - if (accepted) { +} +const { accepted = false, checkbox1 = false } = resPermission || {}; + +if (resPermission) { + setPermission( + `qAPPAutoGetUserWallet-${appInfo?.name}-${data.coin}`, + checkbox1 + ); +} + + if (accepted || skip) { let coin = data.coin; let userWallet = {}; let arrrAddress = ""; @@ -2086,7 +2154,7 @@ export const getUserWalletFunc = async (coin) => { return userWallet; }; -export const getUserWalletInfo = async (data, isFromExtension) => { +export const getUserWalletInfo = async (data, isFromExtension, appInfo) => { const requiredFields = ["coin"]; const missingFields: string[] = []; requiredFields.forEach((field) => { @@ -2105,17 +2173,41 @@ export const getUserWalletInfo = async (data, isFromExtension) => { "ARRR is not supported for this call." ); } - const resPermission = await getUserPermission( + const value = + (await getPermission( + `getUserWalletInfo-${appInfo?.name}-${data.coin}` + )) || false; +let skip = false; +if (value) { + skip = true; +} + let resPermission; + + if (!skip) { + + resPermission = await getUserPermission( { text1: "Do you give this application permission to retrieve your wallet information", highlightedText: `coin: ${data.coin}`, + checkbox1: { + value: true, + label: "Always allow wallet info to be retrieved automatically", + }, }, isFromExtension ); - const { accepted } = resPermission; +} +const { accepted = false, checkbox1 = false } = resPermission || {}; - if (accepted) { +if (resPermission) { + setPermission( + `getUserWalletInfo-${appInfo?.name}-${data.coin}`, + checkbox1 + ); +} + + if (accepted || skip) { let coin = data.coin; let walletKeys = await getUserWalletFunc(coin); @@ -2579,7 +2671,7 @@ export const getDaySummary = async () => { }; export const sendCoin = async (data, isFromExtension) => { - const requiredFields = ["coin", "destinationAddress", "amount"]; + const requiredFields = ["coin", "amount"]; const missingFields: string[] = []; requiredFields.forEach((field) => { if (!data[field]) { @@ -2591,6 +2683,9 @@ export const sendCoin = async (data, isFromExtension) => { const errorMsg = `Missing fields: ${missingFieldsString}`; throw new Error(errorMsg); } + if(!data?.destinationAddress && !data?.recipient){ + throw new Error('Missing fields: recipient') + } let checkCoin = data.coin; const wallet = await getSaveWallet(); const address = wallet.address0; @@ -2603,12 +2698,12 @@ export const sendCoin = async (data, isFromExtension) => { "Cannot send a non-QORT coin through the gateway. Please use your local node." ); if (checkCoin === "QORT") { - // Params: data.coin, data.destinationAddress, data.amount, data.fee + // Params: data.coin, data.recipient, data.amount, data.fee // 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) // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}` const amount = Number(data.amount); - const recipient = data.destinationAddress; + const recipient = data?.recipient || data.destinationAddress; const url = await createEndpoint(`/addresses/balance/${address}`); const response = await fetch(url); @@ -2665,7 +2760,7 @@ export const sendCoin = async (data, isFromExtension) => { } } else if (checkCoin === "BTC") { const amount = Number(data.amount); - const recipient = data.destinationAddress; + const recipient = data?.recipient || data.destinationAddress; const xprv58 = parsedData.btcPrivateKey; const feePerByte = data.fee ? data.fee : btcFeePerByte; @@ -2722,7 +2817,7 @@ export const sendCoin = async (data, isFromExtension) => { } } else if (checkCoin === "LTC") { const amount = Number(data.amount); - const recipient = data.destinationAddress; + const recipient = data?.recipient || data.destinationAddress; const xprv58 = parsedData.ltcPrivateKey; const feePerByte = data.fee ? data.fee : ltcFeePerByte; const ltcWalletBalance = await getWalletBalance({ coin: checkCoin }, true); @@ -2777,7 +2872,7 @@ export const sendCoin = async (data, isFromExtension) => { } } else if (checkCoin === "DOGE") { const amount = Number(data.amount); - const recipient = data.destinationAddress; + const recipient = data?.recipient || data.destinationAddress; const xprv58 = parsedData.dogePrivateKey; const feePerByte = data.fee ? data.fee : dogeFeePerByte; const dogeWalletBalance = await getWalletBalance({ coin: checkCoin }, true); @@ -2834,7 +2929,7 @@ export const sendCoin = async (data, isFromExtension) => { } } else if (checkCoin === "DGB") { const amount = Number(data.amount); - const recipient = data.destinationAddress; + const recipient = data?.recipient || data.destinationAddress; const xprv58 = parsedData.dbgPrivateKey; const feePerByte = data.fee ? data.fee : dgbFeePerByte; const dgbWalletBalance = await getWalletBalance({ coin: checkCoin }, true); @@ -2891,7 +2986,7 @@ export const sendCoin = async (data, isFromExtension) => { } } else if (checkCoin === "RVN") { const amount = Number(data.amount); - const recipient = data.destinationAddress; + const recipient = data?.recipient || data.destinationAddress; const xprv58 = parsedData.rvnPrivateKey; const feePerByte = data.fee ? data.fee : rvnFeePerByte; const rvnWalletBalance = await getWalletBalance({ coin: checkCoin }, true); @@ -2948,7 +3043,7 @@ export const sendCoin = async (data, isFromExtension) => { } } else if (checkCoin === "ARRR") { const amount = Number(data.amount); - const recipient = data.destinationAddress; + const recipient = data?.recipient || data.destinationAddress; const memo = data?.memo; const arrrWalletBalance = await getWalletBalance({ coin: checkCoin }, true);