diff --git a/src/hooks/useHandlePaymentNotification.tsx b/src/hooks/useHandlePaymentNotification.tsx index b5df816..cc6e4e5 100644 --- a/src/hooks/useHandlePaymentNotification.tsx +++ b/src/hooks/useHandlePaymentNotification.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { getBaseApiReact } from '../App'; import { getData, storeData } from '../utils/chromeStorage'; import { checkDifference, getNameInfoForOthers } from '../background'; @@ -7,126 +7,131 @@ import { lastPaymentSeenTimestampAtom } from '../atoms/global'; import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events'; export const useHandlePaymentNotification = (address) => { - const [latestTx, setLatestTx] = useState(null); + const [latestTx, setLatestTx] = useState(null); - const nameAddressOfSender = useRef({}) - const isFetchingName = useRef({}) - - - const [lastEnteredTimestampPayment, setLastEnteredTimestampPayment] = - useRecoilState(lastPaymentSeenTimestampAtom); - - useEffect(() => { - if (lastEnteredTimestampPayment && address) { - storeData(`last-seen-payment-${address}`, Date.now()).catch((error) => { - console.error(error); - }); - } - }, [lastEnteredTimestampPayment, address]); - - const getNameOrAddressOfSender = useCallback(async(senderAddress)=> { - if(isFetchingName.current[senderAddress]) return senderAddress - try { - isFetchingName.current[senderAddress] = true - const res = await getNameInfoForOthers(senderAddress) - nameAddressOfSender.current[senderAddress] = res || senderAddress - } catch (error) { - console.error(error) - } finally { - isFetchingName.current[senderAddress] = false - } - - }, []) + const nameAddressOfSender = useRef({}); + const isFetchingName = useRef({}); - const getNameOrAddressOfSenderMiddle = useCallback(async(senderAddress)=> { - getNameOrAddressOfSender(senderAddress) - return senderAddress - - }, [getNameOrAddressOfSender]) - - const hasNewPayment = useMemo(() => { - if (!latestTx) return false; - if (!checkDifference(latestTx?.timestamp)) return false; - if ( - !lastEnteredTimestampPayment || - lastEnteredTimestampPayment < latestTx?.timestamp - ) - return true; - - return false; - }, [lastEnteredTimestampPayment, latestTx]); - - const getLastSeenData = useCallback(async () => { - try { - if (!address) return; - const key = `last-seen-payment-${address}`; - - const res = await getData(key).catch(() => null); - if (res) { - setLastEnteredTimestampPayment(res); - } - - const response = await fetch( - `${getBaseApiReact()}/transactions/search?txType=PAYMENT&address=${address}&confirmationStatus=CONFIRMED&limit=5&reverse=true` - ); - - const responseData = await response.json(); - - const latestTx = responseData.filter( - (tx) => tx?.creatorAddress !== address && tx?.recipient === address - )[0]; - if (!latestTx) { - return; // continue to the next group - } - - setLatestTx(latestTx); - } catch (error) { + const [lastEnteredTimestampPayment, setLastEnteredTimestampPayment] = + useRecoilState(lastPaymentSeenTimestampAtom); + + useEffect(() => { + if (lastEnteredTimestampPayment && address) { + storeData(`last-seen-payment-${address}`, Date.now()).catch((error) => { console.error(error); - } - }, [address, setLastEnteredTimestampPayment]); - - - useEffect(() => { - getLastSeenData(); - // Handler function for incoming messages - const messageHandler = (event) => { - if (event.origin !== window.location.origin) { - return; - } - const message = event.data; - if (message?.action === "SET_PAYMENT_ANNOUNCEMENT" && message?.payload) { - setLatestTx(message.payload); - } - }; - - // Attach the event listener - window.addEventListener("message", messageHandler); - - // Clean up the event listener on component unmount - return () => { - window.removeEventListener("message", messageHandler); - }; - }, [getLastSeenData]); + }); + } + }, [lastEnteredTimestampPayment, address]); - const setLastEnteredTimestampPaymentEventFunc = useCallback( - (e) => { - setLastEnteredTimestampPayment(Date.now) - }, - [setLastEnteredTimestampPayment] + const getNameOrAddressOfSender = useCallback(async (senderAddress) => { + if (isFetchingName.current[senderAddress]) return senderAddress; + try { + isFetchingName.current[senderAddress] = true; + const res = await getNameInfoForOthers(senderAddress); + nameAddressOfSender.current[senderAddress] = res || senderAddress; + } catch (error) { + console.error(error); + } finally { + isFetchingName.current[senderAddress] = false; + } + }, []); + + const getNameOrAddressOfSenderMiddle = useCallback( + async (senderAddress) => { + getNameOrAddressOfSender(senderAddress); + return senderAddress; + }, + [getNameOrAddressOfSender] + ); + + const hasNewPayment = useMemo(() => { + if (!latestTx) return false; + if (!checkDifference(latestTx?.timestamp)) return false; + if ( + !lastEnteredTimestampPayment || + lastEnteredTimestampPayment < latestTx?.timestamp + ) + return true; + + return false; + }, [lastEnteredTimestampPayment, latestTx]); + + const getLastSeenData = useCallback(async () => { + try { + if (!address) return; + const key = `last-seen-payment-${address}`; + + const res = await getData(key).catch(() => null); + if (res) { + setLastEnteredTimestampPayment(res); + } + + const response = await fetch( + `${getBaseApiReact()}/transactions/search?txType=PAYMENT&address=${address}&confirmationStatus=CONFIRMED&limit=5&reverse=true` ); - - useEffect(() => { - subscribeToEvent("setLastEnteredTimestampPaymentEvent", setLastEnteredTimestampPaymentEventFunc); - - return () => { - unsubscribeFromEvent("setLastEnteredTimestampPaymentEvent", setLastEnteredTimestampPaymentEventFunc); - }; - }, [setLastEnteredTimestampPaymentEventFunc]); + + const responseData = await response.json(); + + const latestTx = responseData.filter( + (tx) => tx?.creatorAddress !== address && tx?.recipient === address + )[0]; + if (!latestTx) { + return; // continue to the next group + } + + setLatestTx(latestTx); + } catch (error) { + console.error(error); + } + }, [address, setLastEnteredTimestampPayment]); + + useEffect(() => { + getLastSeenData(); + // Handler function for incoming messages + const messageHandler = (event) => { + if (event.origin !== window.location.origin) { + return; + } + const message = event.data; + if (message?.action === 'SET_PAYMENT_ANNOUNCEMENT' && message?.payload) { + setLatestTx(message.payload); + } + }; + + // Attach the event listener + window.addEventListener('message', messageHandler); + + // Clean up the event listener on component unmount + return () => { + window.removeEventListener('message', messageHandler); + }; + }, [getLastSeenData]); + + const setLastEnteredTimestampPaymentEventFunc = useCallback( + (e) => { + setLastEnteredTimestampPayment(Date.now); + }, + [setLastEnteredTimestampPayment] + ); + + useEffect(() => { + subscribeToEvent( + 'setLastEnteredTimestampPaymentEvent', + setLastEnteredTimestampPaymentEventFunc + ); + + return () => { + unsubscribeFromEvent( + 'setLastEnteredTimestampPaymentEvent', + setLastEnteredTimestampPaymentEventFunc + ); + }; + }, [setLastEnteredTimestampPaymentEventFunc]); return { latestTx, getNameOrAddressOfSenderMiddle, hasNewPayment, setLastEnteredTimestampPayment, - nameAddressOfSender - } -} + nameAddressOfSender, + }; +}; diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts index 4ae357f..a160305 100644 --- a/src/qortalRequests/get.ts +++ b/src/qortalRequests/get.ts @@ -1,6 +1,5 @@ -import { Sha256 } from "asmcrypto.js"; +import { Sha256 } from 'asmcrypto.js'; import { - computePow, createEndpoint, getBalanceInfo, getFee, @@ -8,12 +7,10 @@ import { getLastRef, getSaveWallet, processTransactionVersion2, - removeDuplicateWindow, signChatFunc, joinGroup as joinGroupFunc, sendQortFee, sendCoin as sendCoinFunc, - isUsingLocal, createBuyOrderTx, performPowTask, parseErrorResponse, @@ -35,18 +32,24 @@ import { cancelSellName, buyName, getBaseApi, -} from "../background"; -import { getNameInfo, uint8ArrayToObject } from "../backgroundFunctions/encryption"; -import { showSaveFilePicker } from "../components/Apps/useQortalMessageListener"; -import { getPublishesFromAdminsAdminSpace } from "../components/Chat/AdminSpaceInner"; -import { extractComponents } from "../components/Chat/MessageDisplay"; -import { decryptResource, getGroupAdmins, getPublishesFromAdmins, validateSecretKey } from "../components/Group/Group"; -import { QORT_DECIMALS } from "../constants/constants"; -import Base58 from "../deps/Base58"; -import ed2curve from "../deps/ed2curve"; -import nacl from "../deps/nacl-fast"; - - +} from '../background'; +import { + getNameInfo, + uint8ArrayToObject, +} from '../backgroundFunctions/encryption'; +import { showSaveFilePicker } from '../components/Apps/useQortalMessageListener'; +import { getPublishesFromAdminsAdminSpace } from '../components/Chat/AdminSpaceInner'; +import { extractComponents } from '../components/Chat/MessageDisplay'; +import { + decryptResource, + getGroupAdmins, + getPublishesFromAdmins, + validateSecretKey, +} from '../components/Group/Group'; +import { QORT_DECIMALS } from '../constants/constants'; +import Base58 from '../deps/Base58'; +import ed2curve from '../deps/ed2curve'; +import nacl from '../deps/nacl-fast'; import { base64ToUint8Array, createSymmetricKeyAndNonce, @@ -59,49 +62,49 @@ import { objectToBase64, uint8ArrayStartsWith, uint8ArrayToBase64, -} from "../qdn/encryption/group-encryption"; -import { publishData } from "../qdn/publish/pubish"; +} from '../qdn/encryption/group-encryption'; +import { publishData } from '../qdn/publish/pubish'; import { getPermission, isRunningGateway, setPermission, -} from "../qortalRequests"; -import TradeBotCreateRequest from "../transactions/TradeBotCreateRequest"; -import DeleteTradeOffer from "../transactions/TradeBotDeleteRequest"; -import signTradeBotTransaction from "../transactions/signTradeBotTransaction"; -import { createTransaction } from "../transactions/transactions"; -import { executeEvent } from "../utils/events"; -import { fileToBase64 } from "../utils/fileReading"; -import { mimeToExtensionMap } from "../utils/memeTypes"; -import { RequestQueueWithPromise } from "../utils/queue/queue"; -import utils from "../utils/utils"; +} from '../qortalRequests'; +import TradeBotCreateRequest from '../transactions/TradeBotCreateRequest'; +import DeleteTradeOffer from '../transactions/TradeBotDeleteRequest'; +import signTradeBotTransaction from '../transactions/signTradeBotTransaction'; +import { createTransaction } from '../transactions/transactions'; +import { executeEvent } from '../utils/events'; +import { fileToBase64 } from '../utils/fileReading'; +import { mimeToExtensionMap } from '../utils/memeTypes'; +import { RequestQueueWithPromise } from '../utils/queue/queue'; +import utils from '../utils/utils'; export const requestQueueGetAtAddresses = new RequestQueueWithPromise(10); const sellerForeignFee = { LITECOIN: { - value: "~0.00005", - ticker: "LTC", + value: '~0.00005', + ticker: 'LTC', }, DOGECOIN: { - value: "~0.005", - ticker: "DOGE", + value: '~0.005', + ticker: 'DOGE', }, BITCOIN: { - value: "~0.0001", - ticker: "BTC", + value: '~0.0001', + ticker: 'BTC', }, DIGIBYTE: { - value: "~0.0005", - ticker: "DGB", + value: '~0.0005', + ticker: 'DGB', }, RAVENCOIN: { - value: "~0.006", - ticker: "RVN", + value: '~0.006', + ticker: 'RVN', }, PIRATECHAIN: { - value: "~0.0002", - ticker: "ARRR", + value: '~0.0002', + ticker: 'ARRR', }, }; @@ -113,24 +116,28 @@ const rvnFeePerByte = 0.00001125; const MAX_RETRIES = 3; // Set max number of retries - -export async function retryTransaction(fn, args, throwError, retries = MAX_RETRIES) { +export async function retryTransaction( + fn, + args, + throwError, + retries = MAX_RETRIES +) { let attempt = 0; while (attempt < retries) { try { - return await fn(...args); + return await fn(...args); } catch (error) { console.error(`Attempt ${attempt + 1} failed: ${error.message}`); attempt++; if (attempt === retries) { - console.error("Max retries reached. Skipping transaction."); - if(throwError){ - throw new Error(error?.message || "Unable to process transaction") + console.error('Max retries reached. Skipping transaction.'); + if (throwError) { + throw new Error(error?.message || 'Unable to process transaction'); } else { - throw new Error(error?.message || "Unable to process transaction") + throw new Error(error?.message || 'Unable to process transaction'); } } - await new Promise(res => setTimeout(res, 10000)); + await new Promise((res) => setTimeout(res, 10000)); } } } @@ -142,23 +149,24 @@ function roundUpToDecimals(number, decimals = 8) { export const _createPoll = async ( { pollName, pollDescription, options }, - isFromExtension, skipPermission + isFromExtension, + skipPermission ) => { - const fee = await getFee("CREATE_POLL"); - let resPermission = {} - if(!skipPermission){ - resPermission = await getUserPermission( + const fee = await getFee('CREATE_POLL'); + let resPermission = {}; + if (!skipPermission) { + resPermission = await getUserPermission( { - text1: "You are requesting to create the poll below:", + text1: 'You are requesting to create the poll below:', text2: `Poll: ${pollName}`, text3: `Description: ${pollDescription}`, - text4: `Options: ${options?.join(", ")}`, + text4: `Options: ${options?.join(', ')}`, fee: fee.fee, }, isFromExtension ); } - + const { accepted = false } = resPermission; if (accepted || skipPermission) { @@ -186,11 +194,11 @@ export const _createPoll = async ( const res = await processTransactionVersion2(signedBytes); if (!res?.signature) throw new Error( - res?.message || "Transaction was not able to be processed" + res?.message || 'Transaction was not able to be processed' ); return res; } else { - throw new Error("User declined request"); + throw new Error('User declined request'); } }; @@ -198,11 +206,11 @@ const _deployAt = async ( { name, description, tags, creationBytes, amount, assetId, atType }, isFromExtension ) => { - const fee = await getFee("DEPLOY_AT"); + const fee = await getFee('DEPLOY_AT'); const resPermission = await getUserPermission( { - text1: "Would you like to deploy this AT?", + text1: 'Would you like to deploy this AT?', text2: `Name: ${name}`, text3: `Description: ${description}`, fee: fee.fee, @@ -242,24 +250,25 @@ const _deployAt = async ( const res = await processTransactionVersion2(signedBytes); if (!res?.signature) throw new Error( - res?.message || "Transaction was not able to be processed" + res?.message || 'Transaction was not able to be processed' ); return res; } else { - throw new Error("User declined transaction"); + throw new Error('User declined transaction'); } }; export const _voteOnPoll = async ( { pollName, optionIndex, optionName }, - isFromExtension, skipPermission + isFromExtension, + skipPermission ) => { - const fee = await getFee("VOTE_ON_POLL"); - let resPermission = {} - if(!skipPermission){ + const fee = await getFee('VOTE_ON_POLL'); + let resPermission = {}; + if (!skipPermission) { resPermission = await getUserPermission( { - text1: "You are being requested to vote on the poll below:", + text1: 'You are being requested to vote on the poll below:', text2: `Poll: ${pollName}`, text3: `Option: ${optionName}`, fee: fee.fee, @@ -267,7 +276,7 @@ export const _voteOnPoll = async ( isFromExtension ); } - + const { accepted = false } = resPermission; if (accepted || skipPermission) { @@ -294,11 +303,11 @@ export const _voteOnPoll = async ( const res = await processTransactionVersion2(signedBytes); if (!res?.signature) throw new Error( - res?.message || "Transaction was not able to be processed" + res?.message || 'Transaction was not able to be processed' ); return res; } else { - throw new Error("User declined request"); + throw new Error('User declined request'); } }; @@ -309,7 +318,7 @@ const handleFileMessage = (event) => { const { action, requestId, result, error } = event.data; if ( - action === "getFileFromIndexedDBResponse" && + action === 'getFileFromIndexedDBResponse' && fileRequestResolvers.has(requestId) ) { const { resolve, reject } = fileRequestResolvers.get(requestId); @@ -318,12 +327,12 @@ const handleFileMessage = (event) => { if (result) { resolve(result); } else { - reject(error || "Failed to retrieve file"); + reject(error || 'Failed to retrieve file'); } } }; -window.addEventListener("message", handleFileMessage); +window.addEventListener('message', handleFileMessage); function getFileFromContentScript(fileId) { return new Promise((resolve, reject) => { @@ -334,14 +343,14 @@ function getFileFromContentScript(fileId) { // Send the request message window.postMessage( - { action: "getFileFromIndexedDB", fileId, requestId }, + { action: 'getFileFromIndexedDB', fileId, requestId }, targetOrigin ); // Timeout to handle no response scenario setTimeout(() => { if (fileRequestResolvers.has(requestId)) { - fileRequestResolvers.get(requestId).reject("Request timed out"); + fileRequestResolvers.get(requestId).reject('Request timed out'); fileRequestResolvers.delete(requestId); // Clean up on timeout } }, 10000); // 10-second timeout @@ -362,7 +371,7 @@ const handleMessage = (event) => { // Check if this is the expected response action and if we have a stored resolver if ( - action === "QORTAL_REQUEST_PERMISSION_RESPONSE" && + action === 'QORTAL_REQUEST_PERMISSION_RESPONSE' && responseResolvers.has(requestId) ) { // Resolve the stored promise with the result @@ -371,7 +380,7 @@ const handleMessage = (event) => { } }; -window.addEventListener("message", handleMessage); +window.addEventListener('message', handleMessage); async function getUserPermission(payload, isFromExtension) { return new Promise((resolve) => { @@ -382,7 +391,7 @@ async function getUserPermission(payload, isFromExtension) { // Send the request message window.postMessage( { - action: "QORTAL_REQUEST_PERMISSION", + action: 'QORTAL_REQUEST_PERMISSION', payload, requestId, isFromExtension, @@ -400,7 +409,11 @@ async function getUserPermission(payload, isFromExtension) { }); } -export const getUserAccount = async ({ isFromExtension, appInfo, skipAuth }) => { +export const getUserAccount = async ({ + isFromExtension, + appInfo, + skipAuth, +}) => { try { const value = (await getPermission(`qAPPAutoAuth-${appInfo?.name}`)) || false; @@ -408,17 +421,17 @@ export const getUserAccount = async ({ isFromExtension, appInfo, skipAuth }) => if (value) { skip = true; } - if(skipAuth){ - skip = true + if (skipAuth) { + skip = true; } let resPermission; if (!skip) { resPermission = await getUserPermission( { - text1: "Do you give this application permission to authenticate?", + text1: 'Do you give this application permission to authenticate?', checkbox1: { value: false, - label: "Always authenticate automatically", + label: 'Always authenticate automatically', }, }, isFromExtension @@ -438,10 +451,10 @@ export const getUserAccount = async ({ isFromExtension, appInfo, skipAuth }) => publicKey, }; } else { - throw new Error("User declined request"); + throw new Error('User declined request'); } } catch (error) { - throw new Error("Unable to fetch user account"); + throw new Error('Unable to fetch user account'); } }; @@ -452,7 +465,7 @@ export const encryptData = async (data, sender) => { data64 = await fileToBase64(data?.file || data?.blob); } if (!data64) { - throw new Error("Please include data to encrypt"); + throw new Error('Please include data to encrypt'); } const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; @@ -468,195 +481,203 @@ export const encryptData = async (data, sender) => { if (encryptDataResponse) { return encryptDataResponse; } else { - throw new Error("Unable to encrypt"); + throw new Error('Unable to encrypt'); } }; export const encryptQortalGroupData = async (data, sender) => { let data64 = data?.data64 || data?.base64; - let groupId = data?.groupId - let isAdmins = data?.isAdmins - if(!groupId){ - throw new Error('Please provide a groupId') + let groupId = data?.groupId; + let isAdmins = data?.isAdmins; + if (!groupId) { + throw new Error('Please provide a groupId'); } if (data?.file || data?.blob) { data64 = await fileToBase64(data?.file || data?.blob); } if (!data64) { - throw new Error("Please include data to encrypt"); + throw new Error('Please include data to encrypt'); } - - let secretKeyObject - if(!isAdmins){ - if(groupSecretkeys[groupId] && groupSecretkeys[groupId].secretKeyObject && groupSecretkeys[groupId]?.timestamp && (Date.now() - groupSecretkeys[groupId]?.timestamp) < 1200000){ - secretKeyObject = groupSecretkeys[groupId].secretKeyObject - } - - if(!secretKeyObject){ - const { names } = - await getGroupAdmins(groupId) - - const publish = - await getPublishesFromAdmins(names, groupId); - if(publish === false) throw new Error('No group key found.') - const url = await createEndpoint(`/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ - publish.identifier - }?encoding=base64&rebuild=true`); - - const res = await fetch( -url - ); - const resData = await res.text(); - - const decryptedKey: any = await decryptResource(resData, true); - - const dataint8Array = base64ToUint8Array(decryptedKey.data); - const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); - - if (!validateSecretKey(decryptedKeyToObject)) - throw new Error("SecretKey is not valid"); - secretKeyObject = decryptedKeyToObject - groupSecretkeys[groupId] = { - secretKeyObject, - timestamp: Date.now() + let secretKeyObject; + if (!isAdmins) { + if ( + groupSecretkeys[groupId] && + groupSecretkeys[groupId].secretKeyObject && + groupSecretkeys[groupId]?.timestamp && + Date.now() - groupSecretkeys[groupId]?.timestamp < 1200000 + ) { + secretKeyObject = groupSecretkeys[groupId].secretKeyObject; } - } -} else { - if(groupSecretkeys[`admins-${groupId}`] && groupSecretkeys[`admins-${groupId}`].secretKeyObject && groupSecretkeys[`admins-${groupId}`]?.timestamp && (Date.now() - groupSecretkeys[`admins-${groupId}`]?.timestamp) < 1200000){ - secretKeyObject = groupSecretkeys[`admins-${groupId}`].secretKeyObject - } + if (!secretKeyObject) { + const { names } = await getGroupAdmins(groupId); - if(!secretKeyObject){ - const { names } = - await getGroupAdmins(groupId) + const publish = await getPublishesFromAdmins(names, groupId); + if (publish === false) throw new Error('No group key found.'); + const url = await createEndpoint( + `/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ + publish.identifier + }?encoding=base64&rebuild=true` + ); - const publish = - await getPublishesFromAdminsAdminSpace(names, groupId); - if(publish === false) throw new Error('No group key found.') - const url = await createEndpoint(`/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ - publish.identifier - }?encoding=base64&rebuild=true`); + const res = await fetch(url); + const resData = await res.text(); - const res = await fetch( -url - ); - const resData = await res.text(); - const decryptedKey: any = await decryptResource(resData, true); - const dataint8Array = base64ToUint8Array(decryptedKey.data); - const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); + const decryptedKey: any = await decryptResource(resData, true); - if (!validateSecretKey(decryptedKeyToObject)) - throw new Error("SecretKey is not valid"); - secretKeyObject = decryptedKeyToObject - groupSecretkeys[`admins-${groupId}`] = { - secretKeyObject, - timestamp: Date.now() + const dataint8Array = base64ToUint8Array(decryptedKey.data); + const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); + + if (!validateSecretKey(decryptedKeyToObject)) + throw new Error('SecretKey is not valid'); + secretKeyObject = decryptedKeyToObject; + groupSecretkeys[groupId] = { + secretKeyObject, + timestamp: Date.now(), + }; + } + } else { + if ( + groupSecretkeys[`admins-${groupId}`] && + groupSecretkeys[`admins-${groupId}`].secretKeyObject && + groupSecretkeys[`admins-${groupId}`]?.timestamp && + Date.now() - groupSecretkeys[`admins-${groupId}`]?.timestamp < 1200000 + ) { + secretKeyObject = groupSecretkeys[`admins-${groupId}`].secretKeyObject; + } + + if (!secretKeyObject) { + const { names } = await getGroupAdmins(groupId); + + const publish = await getPublishesFromAdminsAdminSpace(names, groupId); + if (publish === false) throw new Error('No group key found.'); + const url = await createEndpoint( + `/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ + publish.identifier + }?encoding=base64&rebuild=true` + ); + + const res = await fetch(url); + const resData = await res.text(); + const decryptedKey: any = await decryptResource(resData, true); + const dataint8Array = base64ToUint8Array(decryptedKey.data); + const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); + + if (!validateSecretKey(decryptedKeyToObject)) + throw new Error('SecretKey is not valid'); + secretKeyObject = decryptedKeyToObject; + groupSecretkeys[`admins-${groupId}`] = { + secretKeyObject, + timestamp: Date.now(), + }; } } + const resGroupEncryptedResource = encryptSingle({ + data64, + secretKeyObject: secretKeyObject, + }); - -} - - const resGroupEncryptedResource = encryptSingle({ - data64, secretKeyObject: secretKeyObject, - }) - if (resGroupEncryptedResource) { return resGroupEncryptedResource; } else { - throw new Error("Unable to encrypt"); + throw new Error('Unable to encrypt'); } }; export const decryptQortalGroupData = async (data, sender) => { let data64 = data?.data64 || data?.base64; - let groupId = data?.groupId - let isAdmins = data?.isAdmins - if(!groupId){ - throw new Error('Please provide a groupId') + let groupId = data?.groupId; + let isAdmins = data?.isAdmins; + if (!groupId) { + throw new Error('Please provide a groupId'); } if (!data64) { - throw new Error("Please include data to encrypt"); + throw new Error('Please include data to encrypt'); } - let secretKeyObject - if(!isAdmins){ - if(groupSecretkeys[groupId] && groupSecretkeys[groupId].secretKeyObject && groupSecretkeys[groupId]?.timestamp && (Date.now() - groupSecretkeys[groupId]?.timestamp) < 1200000){ - secretKeyObject = groupSecretkeys[groupId].secretKeyObject - } - if(!secretKeyObject){ - const { names } = - await getGroupAdmins(groupId) - - const publish = - await getPublishesFromAdmins(names, groupId); - if(publish === false) throw new Error('No group key found.') - const url = await createEndpoint(`/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ - publish.identifier - }?encoding=base64&rebuild=true`); - - const res = await fetch( -url - ); - const resData = await res.text(); - const decryptedKey: any = await decryptResource(resData, true); - - const dataint8Array = base64ToUint8Array(decryptedKey.data); - const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); - if (!validateSecretKey(decryptedKeyToObject)) - throw new Error("SecretKey is not valid"); - secretKeyObject = decryptedKeyToObject - groupSecretkeys[groupId] = { - secretKeyObject, - timestamp: Date.now() + let secretKeyObject; + if (!isAdmins) { + if ( + groupSecretkeys[groupId] && + groupSecretkeys[groupId].secretKeyObject && + groupSecretkeys[groupId]?.timestamp && + Date.now() - groupSecretkeys[groupId]?.timestamp < 1200000 + ) { + secretKeyObject = groupSecretkeys[groupId].secretKeyObject; } - } -} else { - if(groupSecretkeys[`admins-${groupId}`] && groupSecretkeys[`admins-${groupId}`].secretKeyObject && groupSecretkeys[`admins-${groupId}`]?.timestamp && (Date.now() - groupSecretkeys[`admins-${groupId}`]?.timestamp) < 1200000){ - secretKeyObject = groupSecretkeys[`admins-${groupId}`].secretKeyObject - } - if(!secretKeyObject){ - const { names } = - await getGroupAdmins(groupId) + if (!secretKeyObject) { + const { names } = await getGroupAdmins(groupId); - const publish = - await getPublishesFromAdminsAdminSpace(names, groupId); - if(publish === false) throw new Error('No group key found.') - const url = await createEndpoint(`/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ - publish.identifier - }?encoding=base64&rebuild=true`); + const publish = await getPublishesFromAdmins(names, groupId); + if (publish === false) throw new Error('No group key found.'); + const url = await createEndpoint( + `/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ + publish.identifier + }?encoding=base64&rebuild=true` + ); - const res = await fetch( -url - ); - const resData = await res.text(); - const decryptedKey: any = await decryptResource(resData, true); + const res = await fetch(url); + const resData = await res.text(); + const decryptedKey: any = await decryptResource(resData, true); - const dataint8Array = base64ToUint8Array(decryptedKey.data); - const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); - if (!validateSecretKey(decryptedKeyToObject)) - throw new Error("SecretKey is not valid"); - secretKeyObject = decryptedKeyToObject - groupSecretkeys[`admins-${groupId}`] = { - secretKeyObject, - timestamp: Date.now() + const dataint8Array = base64ToUint8Array(decryptedKey.data); + const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); + if (!validateSecretKey(decryptedKeyToObject)) + throw new Error('SecretKey is not valid'); + secretKeyObject = decryptedKeyToObject; + groupSecretkeys[groupId] = { + secretKeyObject, + timestamp: Date.now(), + }; + } + } else { + if ( + groupSecretkeys[`admins-${groupId}`] && + groupSecretkeys[`admins-${groupId}`].secretKeyObject && + groupSecretkeys[`admins-${groupId}`]?.timestamp && + Date.now() - groupSecretkeys[`admins-${groupId}`]?.timestamp < 1200000 + ) { + secretKeyObject = groupSecretkeys[`admins-${groupId}`].secretKeyObject; + } + if (!secretKeyObject) { + const { names } = await getGroupAdmins(groupId); + + const publish = await getPublishesFromAdminsAdminSpace(names, groupId); + if (publish === false) throw new Error('No group key found.'); + const url = await createEndpoint( + `/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ + publish.identifier + }?encoding=base64&rebuild=true` + ); + + const res = await fetch(url); + const resData = await res.text(); + const decryptedKey: any = await decryptResource(resData, true); + + const dataint8Array = base64ToUint8Array(decryptedKey.data); + const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); + if (!validateSecretKey(decryptedKeyToObject)) + throw new Error('SecretKey is not valid'); + secretKeyObject = decryptedKeyToObject; + groupSecretkeys[`admins-${groupId}`] = { + secretKeyObject, + timestamp: Date.now(), + }; } } - -} - - const resGroupDecryptResource = decryptSingle({ - data64, secretKeyObject: secretKeyObject, skipDecodeBase64: true - }) + const resGroupDecryptResource = decryptSingle({ + data64, + secretKeyObject: secretKeyObject, + skipDecodeBase64: true, + }); if (resGroupDecryptResource) { return resGroupDecryptResource; } else { - throw new Error("Unable to decrypt"); + throw new Error('Unable to decrypt'); } }; @@ -667,14 +688,14 @@ export const encryptDataWithSharingKey = async (data, sender) => { data64 = await fileToBase64(data?.file || data?.blob); } if (!data64) { - throw new Error("Please include data to encrypt"); + throw new Error('Please include data to encrypt'); } - const symmetricKey = createSymmetricKeyAndNonce() + const symmetricKey = createSymmetricKeyAndNonce(); const dataObject = { data: data64, - key:symmetricKey.messageKey - } - const dataObjectBase64 = await objectToBase64(dataObject) + key: symmetricKey.messageKey, + }; + const dataObjectBase64 = await objectToBase64(dataObject); const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; @@ -686,70 +707,70 @@ export const encryptDataWithSharingKey = async (data, sender) => { publicKeys: publicKeys, privateKey, userPublicKey, - customSymmetricKey: symmetricKey.messageKey + customSymmetricKey: symmetricKey.messageKey, }); if (encryptDataResponse) { return encryptDataResponse; } else { - throw new Error("Unable to encrypt"); + throw new Error('Unable to encrypt'); } }; export const decryptDataWithSharingKey = async (data, sender) => { const { encryptedData, key } = data; - if (!encryptedData) { - throw new Error("Please include data to decrypt"); + throw new Error('Please include data to decrypt'); } - const decryptedData = await decryptGroupEncryptionWithSharingKey({data64EncryptedData: encryptedData, key}) - const base64ToObject = JSON.parse(atob(decryptedData)) - if(!base64ToObject.data) throw new Error('No data in the encrypted resource') - return base64ToObject.data + const decryptedData = await decryptGroupEncryptionWithSharingKey({ + data64EncryptedData: encryptedData, + key, + }); + const base64ToObject = JSON.parse(atob(decryptedData)); + if (!base64ToObject.data) + throw new Error('No data in the encrypted resource'); + return base64ToObject.data; }; export const getHostedData = async (data, isFromExtension) => { const isGateway = await isRunningGateway(); if (isGateway) { - throw new Error("This action cannot be done through a public node"); + throw new Error('This action cannot be done through a public node'); } const resPermission = await getUserPermission( { - text1: "Do you give this application permission to", + text1: 'Do you give this application permission to', text2: `Get a list of your hosted data?`, }, isFromExtension ); const { accepted } = resPermission; - if(accepted){ + if (accepted) { const limit = data?.limit ? data?.limit : 20; - const query = data?.query ? data?.query : "" - const offset = data?.offset ? data?.offset : 0 + const query = data?.query ? data?.query : ''; + const offset = data?.offset ? data?.offset : 0; - let urlPath = `/arbitrary/hosted/resources/?limit=${limit}&offset=${offset}` - if(query){ - urlPath = urlPath + `&query=${query}` + let urlPath = `/arbitrary/hosted/resources/?limit=${limit}&offset=${offset}`; + if (query) { + urlPath = urlPath + `&query=${query}`; } - - const url = await createEndpoint(urlPath); - const response = await fetch(url); - const dataResponse = await response.json(); - return dataResponse - - } else { - throw new Error("User declined to get list of hosted resources"); + const url = await createEndpoint(urlPath); + const response = await fetch(url); + const dataResponse = await response.json(); + return dataResponse; + } else { + throw new Error('User declined to get list of hosted resources'); } - }; export const deleteHostedData = async (data, isFromExtension) => { const isGateway = await isRunningGateway(); if (isGateway) { - throw new Error("This action cannot be done through a public node"); + throw new Error('This action cannot be done through a public node'); } - const requiredFields = ["hostedData"]; + const requiredFields = ['hostedData']; const missingFields: string[] = []; requiredFields.forEach((field) => { if (!data[field]) { @@ -758,35 +779,36 @@ export const deleteHostedData = async (data, isFromExtension) => { }); const resPermission = await getUserPermission( { - text1: "Do you give this application permission to", + text1: 'Do you give this application permission to', text2: `Delete ${data?.hostedData?.length} hosted resources?`, }, isFromExtension ); const { accepted } = resPermission; - if(accepted){ + if (accepted) { const { hostedData } = data; - for (const hostedDataItem of hostedData){ - try { - const url = await createEndpoint(`/arbitrary/resource/${hostedDataItem.service}/${hostedDataItem.name}/${hostedDataItem.identifier}`); - await fetch(url, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - } - }); - } catch (error) { - //error + for (const hostedDataItem of hostedData) { + try { + const url = await createEndpoint( + `/arbitrary/resource/${hostedDataItem.service}/${hostedDataItem.name}/${hostedDataItem.identifier}` + ); + await fetch(url, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + //error + } } - } - return true + return true; } else { - throw new Error("User declined delete hosted resources"); + throw new Error('User declined delete hosted resources'); } - }; export const decryptData = async (data) => { const { encryptedData, publicKey } = data; @@ -800,7 +822,7 @@ export const decryptData = async (data) => { const uint8Array = base64ToUint8Array(encryptedData); const startsWithQortalEncryptedData = uint8ArrayStartsWith( uint8Array, - "qortalEncryptedData" + 'qortalEncryptedData' ); if (startsWithQortalEncryptedData) { if (!publicKey) { @@ -816,7 +838,7 @@ export const decryptData = async (data) => { } const startsWithQortalGroupEncryptedData = uint8ArrayStartsWith( uint8Array, - "qortalGroupEncryptedData" + 'qortalGroupEncryptedData' ); if (startsWithQortalGroupEncryptedData) { const decryptedData = decryptGroupDataQortalRequest( @@ -826,15 +848,15 @@ export const decryptData = async (data) => { const decryptedDataToBase64 = uint8ArrayToBase64(decryptedData); return decryptedDataToBase64; } - throw new Error("Unable to decrypt"); + throw new Error('Unable to decrypt'); }; export const getListItems = async (data, isFromExtension) => { const isGateway = await isRunningGateway(); if (isGateway) { - throw new Error("This action cannot be done through a public node"); + throw new Error('This action cannot be done through a public node'); } - const requiredFields = ["list_name"]; + const requiredFields = ['list_name']; const missingFields: string[] = []; requiredFields.forEach((field) => { if (!data[field]) { @@ -842,11 +864,11 @@ export const getListItems = async (data, isFromExtension) => { } }); if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(", "); + const missingFieldsString = missingFields.join(', '); const errorMsg = `Missing fields: ${missingFieldsString}`; throw new Error(errorMsg); } - const value = (await getPermission("qAPPAutoLists")) || false; + const value = (await getPermission('qAPPAutoLists')) || false; let skip = false; if (value) { @@ -858,12 +880,12 @@ export const getListItems = async (data, isFromExtension) => { if (!skip) { resPermission = await getUserPermission( { - text1: "Do you give this application permission to", - text2: "Access the list", + text1: 'Do you give this application permission to', + text2: 'Access the list', highlightedText: data.list_name, checkbox1: { value: value, - label: "Always allow lists to be retrieved automatically", + label: 'Always allow lists to be retrieved automatically', }, }, isFromExtension @@ -871,27 +893,27 @@ export const getListItems = async (data, isFromExtension) => { const { accepted, checkbox1 } = resPermission; acceptedVar = accepted; checkbox1Var = checkbox1; - setPermission("qAPPAutoLists", checkbox1); + setPermission('qAPPAutoLists', checkbox1); } if (acceptedVar || skip) { const url = await createEndpoint(`/lists/${data.list_name}`); const response = await fetch(url); - if (!response.ok) throw new Error("Failed to fetch"); + if (!response.ok) throw new Error('Failed to fetch'); const list = await response.json(); return list; } else { - throw new Error("User declined to share list"); + throw new Error('User declined to share list'); } }; export const addListItems = async (data, isFromExtension) => { const isGateway = await isRunningGateway(); if (isGateway) { - throw new Error("This action cannot be done through a public node"); + throw new Error('This action cannot be done through a public node'); } - const requiredFields = ["list_name", "items"]; + const requiredFields = ['list_name', 'items']; const missingFields: string[] = []; requiredFields.forEach((field) => { if (!data[field]) { @@ -899,7 +921,7 @@ export const addListItems = async (data, isFromExtension) => { } }); if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(", "); + const missingFieldsString = missingFields.join(', '); const errorMsg = `Missing fields: ${missingFieldsString}`; throw new Error(errorMsg); } @@ -909,9 +931,9 @@ export const addListItems = async (data, isFromExtension) => { const resPermission = await getUserPermission( { - text1: "Do you give this application permission to", + text1: 'Do you give this application permission to', text2: `Add the following to the list ${list_name}:`, - highlightedText: items.join(", "), + highlightedText: items.join(', '), }, isFromExtension ); @@ -924,14 +946,14 @@ export const addListItems = async (data, isFromExtension) => { }; const bodyToString = JSON.stringify(body); const response = await fetch(url, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: bodyToString, }); - if (!response.ok) throw new Error("Failed to add to list"); + if (!response.ok) throw new Error('Failed to add to list'); let res; try { res = await response.clone().json(); @@ -940,16 +962,16 @@ export const addListItems = async (data, isFromExtension) => { } return res; } else { - throw new Error("User declined add to list"); + throw new Error('User declined add to list'); } }; export const deleteListItems = async (data, isFromExtension) => { const isGateway = await isRunningGateway(); if (isGateway) { - throw new Error("This action cannot be done through a public node"); + throw new Error('This action cannot be done through a public node'); } - const requiredFields = ["list_name"]; + const requiredFields = ['list_name']; const missingFields: string[] = []; requiredFields.forEach((field) => { if (!data[field]) { @@ -957,20 +979,20 @@ export const deleteListItems = async (data, isFromExtension) => { } }); if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(", "); + const missingFieldsString = missingFields.join(', '); const errorMsg = `Missing fields: ${missingFieldsString}`; throw new Error(errorMsg); } - if(!data?.item && !data?.items){ - throw new Error('Missing fields: items') + if (!data?.item && !data?.items) { + throw new Error('Missing fields: items'); } const item = data?.item; - const items = data?.items + const items = data?.items; const list_name = data.list_name; const resPermission = await getUserPermission( { - text1: "Do you give this application permission to", + text1: 'Do you give this application permission to', text2: `Remove the following from the list ${list_name}:`, highlightedText: items ? JSON.stringify(items) : item, }, @@ -985,14 +1007,14 @@ export const deleteListItems = async (data, isFromExtension) => { }; const bodyToString = JSON.stringify(body); const response = await fetch(url, { - method: "DELETE", + method: 'DELETE', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: bodyToString, }); - if (!response.ok) throw new Error("Failed to add to list"); + if (!response.ok) throw new Error('Failed to add to list'); let res; try { res = await response.clone().json(); @@ -1001,7 +1023,7 @@ export const deleteListItems = async (data, isFromExtension) => { } return res; } else { - throw new Error("User declined delete from list"); + throw new Error('User declined delete from list'); } }; @@ -1010,7 +1032,7 @@ export const publishQDNResource = async ( sender, isFromExtension ) => { - const requiredFields = ["service"]; + const requiredFields = ['service']; const missingFields: string[] = []; requiredFields.forEach((field) => { if (!data[field]) { @@ -1018,25 +1040,25 @@ export const publishQDNResource = async ( } }); if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(", "); + const missingFieldsString = missingFields.join(', '); const errorMsg = `Missing fields: ${missingFieldsString}`; throw new Error(errorMsg); } if (!data.file && !data.data64 && !data.base64) { - throw new Error("No data or file was submitted"); + throw new Error('No data or file was submitted'); } // Use "default" if user hasn't specified an identifier const service = data.service; - const appFee = data?.appFee ? +data.appFee : undefined - const appFeeRecipient = data?.appFeeRecipient - let hasAppFee = false - if(appFee && appFee > 0 && appFeeRecipient){ - hasAppFee = true + const appFee = data?.appFee ? +data.appFee : undefined; + const appFeeRecipient = data?.appFeeRecipient; + let hasAppFee = false; + if (appFee && appFee > 0 && appFeeRecipient) { + hasAppFee = true; } const registeredName = await getNameInfo(); const name = registeredName; - if(!name){ - throw new Error('User has no Qortal name') + if (!name) { + throw new Error('User has no Qortal name'); } let identifier = data.identifier; let data64 = data.data64 || data.base64; @@ -1046,18 +1068,18 @@ export const publishQDNResource = async ( const category = data.category; const tags = data?.tags || []; -const result = {}; + const result = {}; -// Fill tags dynamically while maintaining backward compatibility -for (let i = 0; i < 5; i++) { - result[`tag${i + 1}`] = tags[i] || data[`tag${i + 1}`] || undefined; -} + // Fill tags dynamically while maintaining backward compatibility + for (let i = 0; i < 5; i++) { + result[`tag${i + 1}`] = tags[i] || data[`tag${i + 1}`] || undefined; + } -// Access tag1 to tag5 from result -const { tag1, tag2, tag3, tag4, tag5 } = result; + // Access tag1 to tag5 from result + const { tag1, tag2, tag3, tag4, tag5 } = result; if (data.identifier == null) { - identifier = "default"; + identifier = 'default'; } if (data?.file || data?.blob) { data64 = await fileToBase64(data?.file || data?.blob); @@ -1067,10 +1089,9 @@ const { tag1, tag2, tag3, tag4, tag5 } = result; (!data.publicKeys || (Array.isArray(data.publicKeys) && data.publicKeys.length === 0)) ) { - throw new Error("Encrypting data requires public keys"); + throw new Error('Encrypting data requires public keys'); } - if (data.encrypt) { try { const resKeyPair = await getKeyPair(); @@ -1088,46 +1109,45 @@ const { tag1, tag2, tag3, tag4, tag5 } = result; } } catch (error) { throw new Error( - error.message || "Upload failed due to failed encryption" + error.message || 'Upload failed due to failed encryption' ); } } - const fee = await getFee("ARBITRARY"); + const fee = await getFee('ARBITRARY'); - const handleDynamicValues = {} - if(hasAppFee){ - const feePayment = await getFee("PAYMENT"); + const handleDynamicValues = {}; + if (hasAppFee) { + const feePayment = await getFee('PAYMENT'); - handleDynamicValues['appFee'] = +appFee + +feePayment.fee, - handleDynamicValues['checkbox1'] = { - value: true, - label: "accept app fee", - } + (handleDynamicValues['appFee'] = +appFee + +feePayment.fee), + (handleDynamicValues['checkbox1'] = { + value: true, + label: 'accept app fee', + }); } - if(!!data?.encrypt){ - handleDynamicValues['highlightedText'] = `isEncrypted: ${!!data.encrypt}` + if (!!data?.encrypt) { + handleDynamicValues['highlightedText'] = `isEncrypted: ${!!data.encrypt}`; } const resPermission = await getUserPermission( { - text1: "Do you give this application permission to publish to QDN?", + text1: 'Do you give this application permission to publish to QDN?', text2: `service: ${service}`, text3: `identifier: ${identifier || null}`, fee: fee.fee, - ...handleDynamicValues + ...handleDynamicValues, }, isFromExtension ); const { accepted, checkbox1 = false } = resPermission; if (accepted) { - try { const resPublish = await publishData({ registeredName: encodeURIComponent(name), file: data64, service: service, identifier: encodeURIComponent(identifier), - uploadType: "file", + uploadType: 'file', isBase64: true, filename: filename, title, @@ -1141,18 +1161,21 @@ const { tag1, tag2, tag3, tag4, tag5 } = result; apiVersion: 2, withFee: true, }); - if(resPublish?.signature && hasAppFee && checkbox1){ - sendCoinFunc({ - amount: appFee, - receiver: appFeeRecipient - }, true) + if (resPublish?.signature && hasAppFee && checkbox1) { + sendCoinFunc( + { + amount: appFee, + receiver: appFeeRecipient, + }, + true + ); } return resPublish; } catch (error) { - throw new Error(error?.message || "Upload failed"); + throw new Error(error?.message || 'Upload failed'); } } else { - throw new Error("User declined request"); + throw new Error('User declined request'); } }; @@ -1162,9 +1185,9 @@ export const checkArrrSyncStatus = async (seed) => { while (tries < 36) { const response = await fetch(_url, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: seed, }); @@ -1176,7 +1199,7 @@ export const checkArrrSyncStatus = async (seed) => { res = await response.text(); } - if (res.indexOf('<') > -1 || res !== "Synchronized") { + if (res.indexOf('<') > -1 || res !== 'Synchronized') { // Wait 2 seconds before trying again await new Promise((resolve) => setTimeout(resolve, 2000)); tries += 1; @@ -1187,16 +1210,15 @@ export const checkArrrSyncStatus = async (seed) => { } // If we exceed 6 tries, throw an error - throw new Error("Failed to synchronize after 36 attempts"); + throw new Error('Failed to synchronize after 36 attempts'); }; - export const publishMultipleQDNResources = async ( data: any, sender, isFromExtension ) => { - const requiredFields = ["resources"]; + const requiredFields = ['resources']; const missingFields: string[] = []; let feeAmount = null; requiredFields.forEach((field) => { @@ -1205,32 +1227,32 @@ export const publishMultipleQDNResources = async ( } }); if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(", "); + const missingFieldsString = missingFields.join(', '); const errorMsg = `Missing fields: ${missingFieldsString}`; throw new Error(errorMsg); } const resources = data.resources; if (!Array.isArray(resources)) { - throw new Error("Invalid data"); + throw new Error('Invalid data'); } if (resources.length === 0) { - throw new Error("No resources to publish"); + throw new Error('No resources to publish'); } - const encrypt = data?.encrypt + const encrypt = data?.encrypt; for (const resource of resources) { - const resourceEncrypt = encrypt && resource?.disableEncrypt !== true - if (!resourceEncrypt && resource?.service.endsWith("_PRIVATE")) { - const errorMsg = "Only encrypted data can go into private services"; - throw new Error(errorMsg) - } else if(resourceEncrypt && !resource?.service.endsWith("_PRIVATE")){ - const errorMsg = "For an encrypted publish please use a service that ends with _PRIVATE"; - throw new Error(errorMsg) + const resourceEncrypt = encrypt && resource?.disableEncrypt !== true; + if (!resourceEncrypt && resource?.service.endsWith('_PRIVATE')) { + const errorMsg = 'Only encrypted data can go into private services'; + throw new Error(errorMsg); + } else if (resourceEncrypt && !resource?.service.endsWith('_PRIVATE')) { + const errorMsg = + 'For an encrypted publish please use a service that ends with _PRIVATE'; + throw new Error(errorMsg); } } - - + // if ( // data.encrypt && // (!data.publicKeys || @@ -1238,35 +1260,35 @@ export const publishMultipleQDNResources = async ( // ) { // throw new Error("Encrypting data requires public keys"); // } - const fee = await getFee("ARBITRARY"); + const fee = await getFee('ARBITRARY'); const registeredName = await getNameInfo(); const name = registeredName; - if(!name){ - throw new Error('You need a Qortal name to publish.') + if (!name) { + throw new Error('You need a Qortal name to publish.'); } - const appFee = data?.appFee ? +data.appFee : undefined - const appFeeRecipient = data?.appFeeRecipient - let hasAppFee = false - if(appFee && appFee > 0 && appFeeRecipient){ - hasAppFee = true + const appFee = data?.appFee ? +data.appFee : undefined; + const appFeeRecipient = data?.appFeeRecipient; + let hasAppFee = false; + if (appFee && appFee > 0 && appFeeRecipient) { + hasAppFee = true; } - const handleDynamicValues = {} - if(hasAppFee){ - const feePayment = await getFee("PAYMENT"); + const handleDynamicValues = {}; + if (hasAppFee) { + const feePayment = await getFee('PAYMENT'); - handleDynamicValues['appFee'] = +appFee + +feePayment.fee, - handleDynamicValues['checkbox1'] = { - value: true, - label: "accept app fee", - } + (handleDynamicValues['appFee'] = +appFee + +feePayment.fee), + (handleDynamicValues['checkbox1'] = { + value: true, + label: 'accept app fee', + }); } - if(data?.encrypt){ - handleDynamicValues['highlightedText'] = `isEncrypted: ${!!data.encrypt}` + if (data?.encrypt) { + handleDynamicValues['highlightedText'] = `isEncrypted: ${!!data.encrypt}`; } const resPermission = await getUserPermission( { - text1: "Do you give this application permission to publish to QDN?", + text1: 'Do you give this application permission to publish to QDN?', html: `