From 5444bacdd0657b53a5e33d656113ebfd97229252 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Thu, 5 Jun 2025 21:42:33 +0200 Subject: [PATCH] Add check condition --- src/background/background.ts | 31 ++-- src/components/Group/Group.tsx | 18 +-- src/qdn/encryption/group-encryption.ts | 190 +++++++++++++------------ 3 files changed, 127 insertions(+), 112 deletions(-) diff --git a/src/background/background.ts b/src/background/background.ts index 2057914..fce3d83 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -440,7 +440,7 @@ const handleNotificationDirect = async (directs) => { let isFocused; const wallet = await getSaveWallet(); const address = wallet.address0; - let isDisableNotifications = + const isDisableNotifications = (await getUserSettings({ key: 'disable-push-notifications' })) || false; const dataDirects = directs.filter((direct) => direct?.sender !== address); try { @@ -1734,7 +1734,7 @@ export async function decryptSingleFunc({ secretKeyObject, skipDecodeBase64, }) { - let holdMessages = []; + const holdMessages = []; for (const message of messages) { try { @@ -1744,9 +1744,11 @@ export async function decryptSingleFunc({ skipDecodeBase64, }); - const decryptToUnit8Array = base64ToUint8Array(res); - const responseData = uint8ArrayToObject(decryptToUnit8Array); - holdMessages.push({ ...message, decryptedData: responseData }); + if (res) { + const decryptToUnit8Array = base64ToUint8Array(res); + const responseData = uint8ArrayToObject(decryptToUnit8Array); + holdMessages.push({ ...message, decryptedData: responseData }); + } } catch (error) { console.error(error); } @@ -1758,7 +1760,7 @@ export async function decryptSingleForPublishes({ secretKeyObject, skipDecodeBase64, }) { - let holdMessages = []; + const holdMessages = []; for (const message of messages) { try { @@ -2888,6 +2890,7 @@ export async function getTimestampEnterChat() { return {}; } } + export async function getTimestampMention() { const wallet = await getSaveWallet(); const address = wallet.address0; @@ -2900,6 +2903,7 @@ export async function getTimestampMention() { return {}; } } + export async function getTimestampGroupAnnouncement() { const wallet = await getSaveWallet(); const address = wallet.address0; @@ -2996,6 +3000,7 @@ async function getGroupData() { return {}; } } + export async function getGroupDataSingle(groupId) { const wallet = await getSaveWallet(); const address = wallet.address0; @@ -3266,6 +3271,7 @@ function setupMessageListener() { break; case 'updateThreadActivity': updateThreadActivityCase(request, event); + break; case 'decryptGroupEncryption': decryptGroupEncryptionCase(request, event); break; @@ -3411,7 +3417,7 @@ export const checkNewMessages = async () => { myName = userData.name; } - let newAnnouncements = []; + const newAnnouncements = []; const activeData = (await getStoredData('active-groups-directs')) || { groups: [], directs: [], @@ -3463,7 +3469,8 @@ export const checkNewMessages = async () => { } }) ); - let isDisableNotifications = + + const isDisableNotifications = (await getUserSettings({ key: 'disable-push-notifications' })) || false; if ( @@ -3611,8 +3618,8 @@ export const checkThreads = async (bringBack) => { if (userData?.name) { myName = userData.name; } - let newAnnouncements = []; - let dataToBringBack = []; + const newAnnouncements = []; + const dataToBringBack = []; const threadActivity = await getThreadActivity(); if (!threadActivity) return null; @@ -3627,7 +3634,6 @@ export const checkThreads = async (bringBack) => { for (const thread of selectedThreads) { try { const identifier = `thmsg-${thread?.threadId}`; - const name = thread?.qortalName; const endpoint = await getArbitraryEndpoint(); const url = await createEndpoint( `${endpoint}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=1&includemetadata=false&offset=${0}&reverse=true&prefix=true` @@ -3643,7 +3649,6 @@ export const checkThreads = async (bringBack) => { const latestMessage = responseData.filter( (pub) => pub?.name !== myName )[0]; - // const latestMessage = responseData[0] if (!latestMessage) { continue; @@ -3717,7 +3722,7 @@ export const checkThreads = async (bringBack) => { '_type=thread-post' + `_data=${JSON.stringify(newAnnouncements[0])}` ); - let isDisableNotifications = + const isDisableNotifications = (await getUserSettings({ key: 'disable-push-notifications' })) || false; if (!isDisableNotifications) { // Check user settings to see if notifications are disabled diff --git a/src/components/Group/Group.tsx b/src/components/Group/Group.tsx index f4091f2..dc8209d 100644 --- a/src/components/Group/Group.tsx +++ b/src/components/Group/Group.tsx @@ -276,15 +276,13 @@ export async function getNameInfo(address: string) { } export const getGroupAdmins = async (groupNumber: number) => { - // const validApi = await findUsableApi(); - const response = await fetch( `${getBaseApiReact()}/groups/members/${groupNumber}?limit=0&onlyAdmins=true` ); const groupData = await response.json(); - let members: any = []; - let membersAddresses = []; - let both = []; + const members: any = []; + const membersAddresses = []; + const both = []; const getMemNames = groupData?.members?.map(async (member) => { if (member?.member) { @@ -601,9 +599,11 @@ export const Group = ({ const getGroupOwner = async (groupId) => { try { + if (groupId == 0) return; + const url = `${getBaseApiReact()}/groups/${groupId}`; const response = await fetch(url); - let data = await response.json(); + const data = await response.json(); const name = await getNameInfo(data?.owner); if (name) { @@ -742,7 +742,7 @@ export const Group = ({ data = await res.text(); } - const decryptedKey: any = await decryptResource(data); + const decryptedKey: any = await decryptResource(data, null); const dataint8Array = base64ToUint8Array(decryptedKey.data); const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); @@ -877,6 +877,8 @@ export const Group = ({ }; const getOwnerNameForGroup = async (owner: string, groupId: string) => { + if (groupId == '0') return; + try { if (!owner) return; if (groupsOwnerNamesRef.current[groupId]) return; @@ -899,7 +901,7 @@ export const Group = ({ const url = `${getBaseApiReact()}/groups/member/${address}`; const response = await fetch(url); if (!response.ok) throw new Error('Cannot get group properties'); - let data = await response.json(); + const data = await response.json(); const transformToObject = data.reduce((result, item) => { result[item.groupId] = item; return result; diff --git a/src/qdn/encryption/group-encryption.ts b/src/qdn/encryption/group-encryption.ts index ebead90..904413c 100644 --- a/src/qdn/encryption/group-encryption.ts +++ b/src/qdn/encryption/group-encryption.ts @@ -303,106 +303,114 @@ export const decryptSingle = async ({ // First, decode the base64-encoded input (if skipDecodeBase64 is not set) const decodedData = skipDecodeBase64 ? data64 : atob(data64); - // Then, decode it again for the specific format (if double encoding is used) - const decodeForNumber = atob(decodedData); + if (secretKeyObject) { + // Then, decode it again for the specific format (if double encoding is used) + const decodeForNumber = atob(decodedData); - // Extract the key (assuming it's always the first 10 characters) - const keyStr = decodeForNumber.slice(0, 10); + // Extract the key (assuming it's always the first 10 characters) + const keyStr = decodeForNumber.slice(0, 10); - // Convert the key string back to a number - const highestKey = parseInt(keyStr, 10); + // Convert the key string back to a number + const highestKey = parseInt(keyStr, 10); - // Check if we have a valid secret key for the extracted highestKey - if (!secretKeyObject[highestKey]) { - throw new Error( - i18n.t('auth:message.error.find_secret_key', { - postProcess: 'capitalizeFirstChar', - }) - ); - } - - const secretKeyEntry = secretKeyObject[highestKey]; - - let nonceBase64, encryptedDataBase64; - - // Determine if typeNumber exists by checking if the next 3 characters after keyStr are digits - const possibleTypeNumberStr = decodeForNumber.slice(10, 13); - const hasTypeNumber = /^\d{3}$/.test(possibleTypeNumberStr); // Check if next 3 characters are digits - - if (secretKeyEntry.nonce) { - // Old format: nonce is present in the secretKeyObject, so no type number exists - nonceBase64 = secretKeyEntry.nonce; - encryptedDataBase64 = decodeForNumber.slice(10); // The remaining part is the encrypted data - } else { - if (hasTypeNumber) { - // const typeNumberStr = new TextDecoder().decode(typeNumberBytes); - if (decodeForNumber.slice(10, 13) !== '001') { - const decodedBinary = base64ToUint8Array(decodedData); - const highestKeyBytes = decodedBinary.slice(0, 10); // if ASCII digits only - const highestKeyStr = new TextDecoder().decode(highestKeyBytes); - - const nonce = decodedBinary.slice(13, 13 + 24); - const encryptedData = decodedBinary.slice(13 + 24); - const highestKey = parseInt(highestKeyStr, 10); - - const messageKey = base64ToUint8Array( - secretKeyObject[+highestKey].messageKey - ); - const decryptedBytes = nacl.secretbox.open( - encryptedData, - nonce, - messageKey - ); - - // Check if decryption was successful - if (!decryptedBytes) { - throw new Error( - i18n.t('question:message.error.decryption_failed', { - postProcess: 'capitalizeFirstChar', - }) - ); - } - - // Convert the decrypted Uint8Array back to a Base64 string - return uint8ArrayToBase64(decryptedBytes); - } - // New format: Extract type number and nonce - nonceBase64 = decodeForNumber.slice(13, 45); // Extract nonce (next 32 characters after type number) - encryptedDataBase64 = decodeForNumber.slice(45); // The remaining part is the encrypted data - } else { - // Old format without type number (nonce is embedded in the message, first 32 characters after keyStr) - nonceBase64 = decodeForNumber.slice(10, 42); // First 32 characters for the nonce - encryptedDataBase64 = decodeForNumber.slice(42); // The remaining part is the encrypted data + // Check if we have a valid secret key for the extracted highestKey + if (!secretKeyObject[highestKey]) { + throw new Error( + i18n.t('auth:message.error.find_secret_key', { + postProcess: 'capitalizeFirstChar', + }) + ); } - } - // Convert Base64 strings to Uint8Array - const Uint8ArrayData = base64ToUint8Array(encryptedDataBase64); - const nonce = base64ToUint8Array(nonceBase64); - const messageKey = base64ToUint8Array(secretKeyEntry.messageKey); + const secretKeyEntry = secretKeyObject[highestKey]; - if (!(Uint8ArrayData instanceof Uint8Array)) { - throw new Error( - i18n.t('auth:message.error.invalid_uint8', { - postProcess: 'capitalizeFirstChar', - }) + let nonceBase64, encryptedDataBase64; + + // Determine if typeNumber exists by checking if the next 3 characters after keyStr are digits + const possibleTypeNumberStr = decodeForNumber.slice(10, 13); + const hasTypeNumber = /^\d{3}$/.test(possibleTypeNumberStr); // Check if next 3 characters are digits + + if (secretKeyEntry.nonce) { + // Old format: nonce is present in the secretKeyObject, so no type number exists + nonceBase64 = secretKeyEntry.nonce; + encryptedDataBase64 = decodeForNumber.slice(10); // The remaining part is the encrypted data + } else { + if (hasTypeNumber) { + // const typeNumberStr = new TextDecoder().decode(typeNumberBytes); + if (decodeForNumber.slice(10, 13) !== '001') { + const decodedBinary = base64ToUint8Array(decodedData); + const highestKeyBytes = decodedBinary.slice(0, 10); // if ASCII digits only + const highestKeyStr = new TextDecoder().decode(highestKeyBytes); + + const nonce = decodedBinary.slice(13, 13 + 24); + const encryptedData = decodedBinary.slice(13 + 24); + const highestKey = parseInt(highestKeyStr, 10); + + const messageKey = base64ToUint8Array( + secretKeyObject[+highestKey].messageKey + ); + const decryptedBytes = nacl.secretbox.open( + encryptedData, + nonce, + messageKey + ); + + // Check if decryption was successful + if (!decryptedBytes) { + throw new Error( + i18n.t('question:message.error.decryption_failed', { + postProcess: 'capitalizeFirstChar', + }) + ); + } + + // Convert the decrypted Uint8Array back to a Base64 string + return uint8ArrayToBase64(decryptedBytes); + } + // New format: Extract type number and nonce + nonceBase64 = decodeForNumber.slice(13, 45); // Extract nonce (next 32 characters after type number) + encryptedDataBase64 = decodeForNumber.slice(45); // The remaining part is the encrypted data + } else { + // Old format without type number (nonce is embedded in the message, first 32 characters after keyStr) + nonceBase64 = decodeForNumber.slice(10, 42); // First 32 characters for the nonce + encryptedDataBase64 = decodeForNumber.slice(42); // The remaining part is the encrypted data + } + } + + // Convert Base64 strings to Uint8Array + const Uint8ArrayData = base64ToUint8Array(encryptedDataBase64); + const nonce = base64ToUint8Array(nonceBase64); + const messageKey = base64ToUint8Array(secretKeyEntry.messageKey); + + if (!(Uint8ArrayData instanceof Uint8Array)) { + throw new Error( + i18n.t('auth:message.error.invalid_uint8', { + postProcess: 'capitalizeFirstChar', + }) + ); + } + + // Decrypt the data using the nonce and messageKey + const decryptedData = nacl.secretbox.open( + Uint8ArrayData, + nonce, + messageKey ); + + // Check if decryption was successful + if (!decryptedData) { + throw new Error( + i18n.t('question:message.error.decryption_failed', { + postProcess: 'capitalizeFirstChar', + }) + ); + } + + // Convert the decrypted Uint8Array back to a Base64 string + return uint8ArrayToBase64(decryptedData); } - // Decrypt the data using the nonce and messageKey - const decryptedData = nacl.secretbox.open(Uint8ArrayData, nonce, messageKey); - - // Check if decryption was successful - if (!decryptedData) { - throw new Error( - i18n.t('question:message.error.decryption_failed', { - postProcess: 'capitalizeFirstChar', - }) - ); - } - - // Convert the decrypted Uint8Array back to a Base64 string - return uint8ArrayToBase64(decryptedData); + return; }; export const decryptGroupEncryptionWithSharingKey = async ({