diff --git a/lib/backup/use-user-data-restore.js b/lib/backup/use-user-data-restore.js --- a/lib/backup/use-user-data-restore.js +++ b/lib/backup/use-user-data-restore.js @@ -4,7 +4,7 @@ import { runRestoredBackupMigrations } from './restored-migrations.js'; import { setClientDBStoreActionType } from '../actions/client-db-store-actions.js'; -import { useDebugLogs } from '../components/debug-logs-context.js'; +import { logTypes, useDebugLogs } from '../components/debug-logs-context.js'; import { databaseIdentifier } from '../types/database-identifier-types.js'; import type { IdentityAuthResult } from '../types/identity-service-types.js'; import { syncedMetadataNames } from '../types/synced-metadata-types.js'; @@ -40,6 +40,7 @@ 'User Data Restore', `Main and restored database versions are equal: ` + `${mainDatabaseVersion}, skipping schema migrations.`, + new Set([logTypes.BACKUP]), ); } else if (mainDatabaseVersion > restoredDatabaseVersion) { addLog( @@ -47,6 +48,7 @@ `Main database version (${mainDatabaseVersion}) is higher ` + `than restored database version (${restoredDatabaseVersion}), ` + `migrating schema.`, + new Set([logTypes.BACKUP]), ); await sqliteAPI.migrateBackupSchema(); } else if (mainDatabaseVersion < restoredDatabaseVersion) { @@ -55,6 +57,7 @@ `Main database version (${mainDatabaseVersion}) is lower ` + `than restored database version (${restoredDatabaseVersion}), ` + ` aborting.`, + new Set([logTypes.BACKUP, logTypes.ERROR]), ); throw new Error('backup_is_newer'); } @@ -74,6 +77,7 @@ }) or restored store version (${ restoredStoreVersionString ?? 'undefined' }) are undefined`, + new Set([logTypes.BACKUP, logTypes.ERROR]), ); return; } @@ -85,12 +89,14 @@ 'User Data Restore', `Main and restored store versions are equal: ${mainStoreVersion}, ` + `skipping data migrations`, + new Set([logTypes.BACKUP]), ); } else if (mainStoreVersion > restoredStoreVersion) { addLog( 'User Data Restore', `Main store version (${mainStoreVersion}) is higher than ` + `restored store version (${restoredStoreVersion}), migrating data`, + new Set([logTypes.BACKUP]), ); await runRestoredBackupMigrations(); } else if (mainStoreVersion < restoredStoreVersion) { @@ -98,6 +104,7 @@ 'User Data Restore', `Main store version (${mainStoreVersion}) is lower than ` + `restored store version (${restoredStoreVersion}), aborting`, + new Set([logTypes.BACKUP, logTypes.ERROR]), ); throw new Error('backup_is_newer'); } diff --git a/lib/components/debug-logs-context-provider.react.js b/lib/components/debug-logs-context-provider.react.js --- a/lib/components/debug-logs-context-provider.react.js +++ b/lib/components/debug-logs-context-provider.react.js @@ -2,7 +2,11 @@ import * as React from 'react'; -import { type DebugLog, DebugLogsContext } from './debug-logs-context.js'; +import { + type DebugLog, + DebugLogsContext, + type LogType, +} from './debug-logs-context.js'; import { useIsCurrentUserStaff } from '../shared/staff-utils.js'; import { isDev } from '../utils/dev-utils.js'; @@ -15,7 +19,7 @@ const isCurrentUserStaff = useIsCurrentUserStaff(); const addLog = React.useCallback( - (title: string, message: string) => { + (title: string, message: string, logTypes: $ReadOnlySet) => { console.log(`${title}: ${message}`); if (!isCurrentUserStaff && !isDev) { @@ -28,6 +32,7 @@ title, message, timestamp: Date.now(), + logTypes, }, ]); }, diff --git a/lib/components/debug-logs-context.js b/lib/components/debug-logs-context.js --- a/lib/components/debug-logs-context.js +++ b/lib/components/debug-logs-context.js @@ -6,15 +6,30 @@ import type { OlmEncryptedMessageTypes } from '../types/crypto-types.js'; import { type OutboundP2PMessageStatuses } from '../types/sqlite-types.js'; +const logTypes = Object.freeze({ + ERROR: 'error', + DM_OPS: 'dm_ops', + OLM: 'olm', + TUNNELBROKER: 'tunnelbroker', + BACKUP: 'backup', +}); + +export type LogType = $Values; + export type DebugLog = { +title: string, +message: string, +timestamp: number, + +logTypes: $ReadOnlySet, }; export type DebugLogsContextType = { +logs: $ReadOnlyArray, - +addLog: (title: string, message: string) => mixed, + +addLog: ( + title: string, + message: string, + logTypes: $ReadOnlySet, + ) => mixed, +clearLogs: () => mixed, }; @@ -107,9 +122,22 @@ function useOlmDebugLogs(): (olmLog: OlmDebugLog) => mixed { const { addLog } = useDebugLogs(); return React.useCallback( - (olmLog: OlmDebugLog) => addLog('Olm LOG', JSON.stringify(olmLog)), + (olmLog: OlmDebugLog) => { + if ( + olmLog.operation !== 'sendingAlreadyEncryptedMessage' && + !olmLog.success + ) { + addLog( + 'Olm Error', + JSON.stringify(olmLog), + new Set([logTypes.ERROR, logTypes.OLM]), + ); + } else { + addLog('Olm LOG', JSON.stringify(olmLog), new Set([logTypes.OLM])); + } + }, [addLog], ); } -export { DebugLogsContext, useDebugLogs, useOlmDebugLogs }; +export { DebugLogsContext, useDebugLogs, useOlmDebugLogs, logTypes }; diff --git a/lib/components/secondary-device-qr-auth-context-provider.react.js b/lib/components/secondary-device-qr-auth-context-provider.react.js --- a/lib/components/secondary-device-qr-auth-context-provider.react.js +++ b/lib/components/secondary-device-qr-auth-context-provider.react.js @@ -3,7 +3,7 @@ import invariant from 'invariant'; import * as React from 'react'; -import { useDebugLogs } from './debug-logs-context.js'; +import { logTypes, useDebugLogs } from './debug-logs-context.js'; import { useUserDataRestore } from '../backup/use-user-data-restore.js'; import { qrCodeLinkURL } from '../facts/links.js'; import { useSecondaryDeviceLogIn } from '../hooks/login-hooks.js'; @@ -203,6 +203,7 @@ addLog( 'Error when restoring User Data', getMessageForException(e) ?? 'unknown error', + new Set([logTypes.BACKUP, logTypes.ERROR]), ); onLogInError(e); } diff --git a/lib/shared/dm-ops/process-dm-ops.js b/lib/shared/dm-ops/process-dm-ops.js --- a/lib/shared/dm-ops/process-dm-ops.js +++ b/lib/shared/dm-ops/process-dm-ops.js @@ -18,7 +18,7 @@ } from './dm-op-utils.js'; import { useProcessBlobHolders } from '../../actions/holder-actions.js'; import { processNewUserIDsActionType } from '../../actions/user-actions.js'; -import { useDebugLogs } from '../../components/debug-logs-context.js'; +import { logTypes, useDebugLogs } from '../../components/debug-logs-context.js'; import { useGetLatestMessageEdit } from '../../hooks/latest-message-edit.js'; import { useDispatchWithMetadata } from '../../hooks/ops-hooks.js'; import { mergeUpdatesWithMessageInfos } from '../../reducers/message-reducer.js'; @@ -71,6 +71,7 @@ addLog( 'Ignored DMOperation because logged out', JSON.stringify(dmOperationSpecification.op), + new Set([logTypes.DM_OPS]), ); return; } @@ -120,6 +121,7 @@ addLog( "This operation type isn't supported by this code version", JSON.stringify(dmOp), + new Set([logTypes.DM_OPS]), ); return; } @@ -162,6 +164,7 @@ addLog( "Ignoring operation because it doesn't pass validation", JSON.stringify(dmOp), + new Set([logTypes.ERROR, logTypes.DM_OPS]), ); await confirmPeerToPeerMessage(dispatchMetadata); return; @@ -177,6 +180,7 @@ addLog( 'Ignoring operation because it is invalid', JSON.stringify(dmOp), + new Set([logTypes.ERROR, logTypes.DM_OPS]), ); await confirmPeerToPeerMessage(dispatchMetadata); return; @@ -209,11 +213,13 @@ addLog( `Adding operation to the ${condition.type} queue`, JSON.stringify(dmOp), + new Set([logTypes.DM_OPS]), ); } else { addLog( 'Operation should be added to a queue but its type is missing', JSON.stringify(dmOp), + new Set([logTypes.ERROR, logTypes.DM_OPS]), ); } dispatchWithMetadata( diff --git a/lib/tunnelbroker/peer-to-peer-context.js b/lib/tunnelbroker/peer-to-peer-context.js --- a/lib/tunnelbroker/peer-to-peer-context.js +++ b/lib/tunnelbroker/peer-to-peer-context.js @@ -9,6 +9,8 @@ useTunnelbroker, } from './tunnelbroker-context.js'; import { + type LogType, + logTypes, type OlmDebugLog, useDebugLogs, useOlmDebugLogs, @@ -73,7 +75,11 @@ async function createMissingSession( userDevicesWithoutSession: { [userID: string]: Array }, peerOlmSessionsCreator: CreateOlmSessionsWithUser, - addLog: (title: string, message: string) => mixed, + addLog: ( + title: string, + message: string, + logTypes: $ReadOnlySet, + ) => mixed, ): Promise { const creatingSessionPromises = entries(userDevicesWithoutSession).map( async ([userID, devices]) => { @@ -89,6 +95,7 @@ addLog( `Error while creating missing session with ${userID}`, getMessageForException(e) ?? 'unknown error', + new Set([logTypes.ERROR, logTypes.OLM]), ); } }, @@ -125,7 +132,11 @@ peerOlmSessionsCreator: CreateOlmSessionsWithUser, messageIDs: ?$ReadOnlyArray, allPeerDevices: $ReadOnlySet, - addLog: (title: string, message: string) => mixed, + addLog: ( + title: string, + message: string, + logTypes: $ReadOnlySet, + ) => mixed, olmDebugLog: (olmLog: OlmDebugLog) => mixed, ): Promise { let authMetadata; diff --git a/lib/tunnelbroker/peer-to-peer-message-handler.js b/lib/tunnelbroker/peer-to-peer-message-handler.js --- a/lib/tunnelbroker/peer-to-peer-message-handler.js +++ b/lib/tunnelbroker/peer-to-peer-message-handler.js @@ -7,7 +7,7 @@ useHandleOlmMessageToDevice, usePeerToPeerMessageHandler, } from './use-peer-to-peer-message-handler.js'; -import { useDebugLogs } from '../components/debug-logs-context.js'; +import { logTypes, useDebugLogs } from '../components/debug-logs-context.js'; import { useLoggedInUserInfo } from '../hooks/account-hooks.js'; import { useActionsQueue } from '../hooks/actions-queue.js'; import { usePersistedStateLoaded } from '../selectors/app-state-selectors.js'; @@ -92,7 +92,11 @@ }; if (doesSocketExist()) { socketSend(JSON.stringify(confirmation)); - addLog('Tunnelbroker', `Confirmed a message with ID: ${messageID}`); + addLog( + 'Tunnelbroker', + `Confirmed a message with ID: ${messageID}`, + new Set([logTypes.TUNNELBROKER]), + ); } } } @@ -135,6 +139,7 @@ addLog( 'Tunnelbroker', `Confirmed an incorrect message with ID: ${message.messageID}`, + new Set([logTypes.ERROR, logTypes.TUNNELBROKER]), ); return; } @@ -147,6 +152,7 @@ addLog( 'Tunnelbroker', `Confirmed an invalid message with ID: ${message.messageID}`, + new Set([logTypes.ERROR, logTypes.TUNNELBROKER]), ); return; } diff --git a/lib/tunnelbroker/tunnelbroker-context.js b/lib/tunnelbroker/tunnelbroker-context.js --- a/lib/tunnelbroker/tunnelbroker-context.js +++ b/lib/tunnelbroker/tunnelbroker-context.js @@ -9,7 +9,7 @@ import { PeerToPeerMessageHandler } from './peer-to-peer-message-handler.js'; import type { SecondaryTunnelbrokerConnection } from './secondary-tunnelbroker-connection.js'; import { useInvalidCSATLogOut } from '../actions/user-actions.js'; -import { useDebugLogs } from '../components/debug-logs-context.js'; +import { logTypes, useDebugLogs } from '../components/debug-logs-context.js'; import { PeerOlmSessionCreatorProvider } from '../components/peer-olm-session-creator-provider.react.js'; import { tunnnelbrokerURL } from '../facts/tunnelbroker.js'; import { DMOpsQueueHandler } from '../shared/dm-ops/dm-ops-queue-handler.react.js'; @@ -364,6 +364,7 @@ addLog( 'Tunnelbroker', `A new session created with counter=${socketSessionCounter.current}`, + new Set([logTypes.TUNNELBROKER]), ); } catch (err) { console.log('Tunnelbroker connection error:', err); @@ -521,7 +522,11 @@ type: deviceToTunnelbrokerMessageTypes.MESSAGE_RECEIVE_CONFIRMATION, messageIDs: [messageID], }; - addLog('Tunnelbroker', `Confirmed a message with ID: ${messageID}`); + addLog( + 'Tunnelbroker', + `Confirmed a message with ID: ${messageID}`, + new Set([logTypes.TUNNELBROKER]), + ); socket.current?.send(JSON.stringify(confirmation)); }, [addLog], diff --git a/lib/tunnelbroker/use-peer-to-peer-message-handler.js b/lib/tunnelbroker/use-peer-to-peer-message-handler.js --- a/lib/tunnelbroker/use-peer-to-peer-message-handler.js +++ b/lib/tunnelbroker/use-peer-to-peer-message-handler.js @@ -11,6 +11,7 @@ import { invalidateTunnelbrokerDeviceTokenActionType } from '../actions/tunnelbroker-actions.js'; import { logOutActionTypes, useBaseLogOut } from '../actions/user-actions.js'; import { + logTypes, type OlmDebugLog, useDebugLogs, useOlmDebugLogs, @@ -231,6 +232,7 @@ 'Error creating inbound session with device', `${senderDeviceID}: No keys for the device, ` + `session version: ${sessionVersion}`, + new Set([logTypes.ERROR, logTypes.OLM]), ); return; } @@ -413,6 +415,7 @@ addLog( 'Error decrypting message from device', `${message.senderInfo.deviceID}: ${errorMessage}`, + new Set([logTypes.ERROR, logTypes.OLM]), ); resultDescription = diff --git a/native/account/qr-auth/primary-device-qr-auth-context-provider.js b/native/account/qr-auth/primary-device-qr-auth-context-provider.js --- a/native/account/qr-auth/primary-device-qr-auth-context-provider.js +++ b/native/account/qr-auth/primary-device-qr-auth-context-provider.js @@ -4,7 +4,7 @@ import invariant from 'invariant'; import * as React from 'react'; -import { useDebugLogs } from 'lib/components/debug-logs-context.js'; +import { logTypes, useDebugLogs } from 'lib/components/debug-logs-context.js'; import { parseDataFromDeepLink } from 'lib/facts/links.js'; import { useWaitForConnection } from 'lib/hooks/wait-for-connection.js'; import { @@ -192,6 +192,7 @@ `Error while replacing device ${keyserverDeviceID ?? ''}` + ` with ${targetDeviceID}: `, getMessageForException(err) ?? 'unknown error', + new Set([logTypes.ERROR]), ); if (keyserverHasBeenReplaced) { ignorePromiseRejections( @@ -248,6 +249,7 @@ addLog( `Error adding device ${targetDeviceID ?? ''}`, getMessageForException(err) ?? 'unknown error', + new Set([logTypes.ERROR]), ); if (targetDeviceID && deviceListHasBeenUpdated) { ignorePromiseRejections( diff --git a/native/account/restore.js b/native/account/restore.js --- a/native/account/restore.js +++ b/native/account/restore.js @@ -8,7 +8,7 @@ type RestoreUserResult, } from 'lib/actions/user-actions.js'; import { useUserDataRestore } from 'lib/backup/use-user-data-restore.js'; -import { useDebugLogs } from 'lib/components/debug-logs-context.js'; +import { logTypes, useDebugLogs } from 'lib/components/debug-logs-context.js'; import { useLogIn, usePasswordLogIn, @@ -217,6 +217,7 @@ addLog( 'Error when restoring User Data', messageForException ?? 'unknown error', + new Set([logTypes.ERROR, logTypes.BACKUP]), ); if (messageForException === 'backup_is_newer') { Alert.alert(