From a52ccad0637d89dc8d95f48c82072ca9daa172b9 Mon Sep 17 00:00:00 2001 From: Kacper Michalik Date: Fri, 17 Nov 2023 14:35:08 +0100 Subject: [PATCH] fix: code review --- packages/common/src/index.ts | 1 + packages/common/src/messages.test.ts | 50 ++++++ packages/common/src/messages.ts | 15 ++ .../src/tests/invitationLink.test.ts | 6 +- .../saveCommunityMetadata.saga.ts | 8 +- .../sagas/messages/messages.selectors.test.ts | 54 +------ .../src/sagas/messages/messages.selectors.ts | 17 --- .../verifyMessage/verifyMessages.saga.test.ts | 143 +++++++++++++++++- .../verifyMessage/verifyMessages.saga.ts | 45 +++--- .../sendInitialChannelMessage.saga.ts | 5 +- .../deleteChannel/deleteChannel.saga.test.ts | 19 +-- .../deleteChannel/deleteChannel.saga.ts | 2 +- .../sendUnregisteredInfoMessage.saga.ts | 3 +- .../src/sagas/users/users.selectors.ts | 8 +- packages/types/src/message.ts | 3 - 15 files changed, 252 insertions(+), 127 deletions(-) create mode 100644 packages/common/src/messages.test.ts create mode 100644 packages/common/src/messages.ts diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index bd92483eb7..19dcfce623 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -9,3 +9,4 @@ export * from './naming' export * from './fileData' export * from './libp2p' export * from './tests' +export * from './messages' diff --git a/packages/common/src/messages.test.ts b/packages/common/src/messages.test.ts new file mode 100644 index 0000000000..1b6dc825e1 --- /dev/null +++ b/packages/common/src/messages.test.ts @@ -0,0 +1,50 @@ +import { PublicChannelStorage } from '@quiet/types' +import { generateChannelId } from './channelAddress' +import { userCreatedChannelMessage, userJoinedMessage, verifyUserInfoMessage } from './messages' + +describe('messages helper', () => { + const username = 'johnny' + + const generalChannel: PublicChannelStorage = { + name: 'general', + description: 'Welcome to #general', + timestamp: 1, + owner: username, + id: generateChannelId('general'), + messages: { ids: [], entities: {} }, + } + + const sportChannel: PublicChannelStorage = { + name: 'sport', + description: 'Welcome to #sport', + timestamp: 1, + owner: username, + id: generateChannelId('sport'), + messages: { ids: [], entities: {} }, + } + it('userCreatedChannelMessage', () => { + const expectedMessage = '@johnny created #sport' + const message = userCreatedChannelMessage(username, sportChannel.name) + expect(message).toEqual(expectedMessage) + }) + + it('userJoinedMessage', () => { + const expectedMessage = + '**@johnny** has joined and will be registered soon. 🎉 [Learn more](https://github.com/TryQuiet/quiet/wiki/Quiet-FAQ#how-does-username-registration-work)' + const message = userJoinedMessage(username) + expect(message).toEqual(expectedMessage) + }) + + it('verifyUserInfoMessage - general channel', () => { + const expectedMessage = + '**@johnny** has joined and will be registered soon. 🎉 [Learn more](https://github.com/TryQuiet/quiet/wiki/Quiet-FAQ#how-does-username-registration-work)' + const message = verifyUserInfoMessage(username, generalChannel) + expect(message).toEqual(expectedMessage) + }) + + it('verifyUserInfoMessage - other channel', () => { + const expectedMessage = '@johnny created #sport' + const message = verifyUserInfoMessage(username, sportChannel) + expect(message).toEqual(expectedMessage) + }) +}) diff --git a/packages/common/src/messages.ts b/packages/common/src/messages.ts new file mode 100644 index 0000000000..900baa6313 --- /dev/null +++ b/packages/common/src/messages.ts @@ -0,0 +1,15 @@ +import { PublicChannelStorage } from '@quiet/types' + +export const userCreatedChannelMessage = (username: string, channelName: string) => + `@${username} created #${channelName}` + +export const userJoinedMessage = (username: string) => + `**@${username}** has joined and will be registered soon. 🎉 [Learn more](https://github.com/TryQuiet/quiet/wiki/Quiet-FAQ#how-does-username-registration-work)` + +export const verifyUserInfoMessage = (username: string, channel: PublicChannelStorage) => { + if (channel.name === 'general') { + return userJoinedMessage(username) + } else { + return userCreatedChannelMessage(username, channel.name) + } +} diff --git a/packages/e2e-tests/src/tests/invitationLink.test.ts b/packages/e2e-tests/src/tests/invitationLink.test.ts index 343ad1e70d..8956672981 100644 --- a/packages/e2e-tests/src/tests/invitationLink.test.ts +++ b/packages/e2e-tests/src/tests/invitationLink.test.ts @@ -9,7 +9,7 @@ import { Sidebar, WarningModal, } from '../selectors' -import { capitalizeFirstLetter, composeInvitationDeepUrl, parseInvitationCode } from '@quiet/common' +import { capitalizeFirstLetter, composeInvitationDeepUrl, parseInvitationCode, userJoinedMessage } from '@quiet/common' import { execSync } from 'child_process' import { type SupportedPlatformDesktop } from '@quiet/types' @@ -182,12 +182,12 @@ describe('New user joins using invitation link while having app opened', () => { it('Owner sees that guest joined community', async () => { console.log('Invitation Link', 21) - const generalChannel = new Channel(guestApp.driver, 'general') + const generalChannel = new Channel(ownerApp.driver, 'general') await generalChannel.element.isDisplayed() const hasMessage = await generalChannel.waitForUserMessage( joiningUserUsername, - `@${joiningUserUsername} has joined and will be registered soon. 🎉 Learn more` + userJoinedMessage(joiningUserUsername) ) const isMessageDisplayed = await hasMessage?.isDisplayed() expect(isMessageDisplayed).toBeTruthy() diff --git a/packages/state-manager/src/sagas/communities/saveCommunityMetadata/saveCommunityMetadata.saga.ts b/packages/state-manager/src/sagas/communities/saveCommunityMetadata/saveCommunityMetadata.saga.ts index d30541e0a4..2e35ff1790 100644 --- a/packages/state-manager/src/sagas/communities/saveCommunityMetadata/saveCommunityMetadata.saga.ts +++ b/packages/state-manager/src/sagas/communities/saveCommunityMetadata/saveCommunityMetadata.saga.ts @@ -25,10 +25,6 @@ export function* saveCommunityMetadataSaga( ) const community = yield* select(communitiesSelectors.currentCommunity) - if (!community) return - const isOwner = community.CA - - if (!isOwner) { - yield* put(publicChannelsActions.sendUnregisteredInfoMessage()) - } + if (community?.CA) return + yield* put(publicChannelsActions.sendUnregisteredInfoMessage()) } diff --git a/packages/state-manager/src/sagas/messages/messages.selectors.test.ts b/packages/state-manager/src/sagas/messages/messages.selectors.test.ts index eb07fc034a..8d2bf0282c 100644 --- a/packages/state-manager/src/sagas/messages/messages.selectors.test.ts +++ b/packages/state-manager/src/sagas/messages/messages.selectors.test.ts @@ -2,7 +2,7 @@ import { keyFromCertificate, parseCertificate, pubKeyFromCsr, setupCrypto } from import { type Store } from '../store.types' import { getFactory, publicChannels } from '../..' import { prepareStore } from '../../utils/tests/prepareStore' -import { getMessagesFromChannelIdByPubKey, validCurrentPublicChannelMessagesEntries } from './messages.selectors' +import { validCurrentPublicChannelMessagesEntries } from './messages.selectors' import { type communitiesActions } from '../communities/communities.slice' import { type identityActions } from '../identity/identity.slice' import { type FactoryGirl } from 'factory-girl' @@ -117,56 +117,4 @@ describe('messagesSelectors', () => { expect(messages[0].id).toBe(authenticMessage.id) }) - - describe('getMessagesFromChannelIdByPubKey - return messages related to pubkey from the specific channel in chronological order', () => { - const generateMessage = async (identity: Identity, channelId: string) => { - await factory.create['payload']>('Message', { - identity, - message: { - ...( - await factory.build('Message', { - identity, - }) - ).payload.message, - id: Math.random().toString(36).substr(2.9), - channelId, - createdAt: getCurrentTime(), - }, - verifyAutomatically: true, - }) - } - it('return only Alice messages from general channel - included John messages', async () => { - const aliceCsr = alice.userCsr?.userCsr - if (!aliceCsr) return - - const arrLength = 3 - - for await (const _i of new Array(arrLength)) { - await new Promise(resolve => setTimeout(() => resolve(), 500)) - await generateMessage(alice, generalChannel.id) - await generateMessage(john, generalChannel.id) - } - - const messages = getMessagesFromChannelIdByPubKey(generalChannel.id, pubKeyFromCsr(aliceCsr))(store.getState()) - expect(messages.length).toEqual(arrLength) - expect(messages[0].createdAt).toBeLessThan(messages[2].createdAt) - }) - - it('return only Alice messages from general channel - included Alice messages on other channel', async () => { - const aliceCsr = alice.userCsr?.userCsr - if (!aliceCsr) return - - const arrLength = 3 - - for await (const _i of new Array(arrLength)) { - await new Promise(resolve => setTimeout(() => resolve(), 500)) - await generateMessage(alice, generalChannel.id) - await generateMessage(alice, devChannel.id) - } - - const messages = getMessagesFromChannelIdByPubKey(generalChannel.id, pubKeyFromCsr(aliceCsr))(store.getState()) - expect(messages.length).toEqual(arrLength) - expect(messages[0].createdAt).toBeLessThan(messages[2].createdAt) - }) - }) }) diff --git a/packages/state-manager/src/sagas/messages/messages.selectors.ts b/packages/state-manager/src/sagas/messages/messages.selectors.ts index 7bf7bb378e..d6b4db01bd 100644 --- a/packages/state-manager/src/sagas/messages/messages.selectors.ts +++ b/packages/state-manager/src/sagas/messages/messages.selectors.ts @@ -45,22 +45,6 @@ export const publicChannelMessagesEntities = (address: string) => return channelMessagesAdapter.getSelectors().selectEntities(channelMessagesBase.messages) }) -export const getMessagesFromChannelIdByPubKey = (channelId: string, pubkey: string) => - createSelector(publicChannelsMessagesBase, base => { - if (!base) return [] - - const generalMessagesBase = base[channelId] - if (!generalMessagesBase) return [] - - const channelMessages = channelMessagesAdapter.getSelectors().selectAll(generalMessagesBase.messages) - - const messagesFromPubKey = channelMessages.filter(mess => mess.pubKey === pubkey) - - const sortedMessages = messagesFromPubKey.sort((a, b) => a.createdAt - b.createdAt) - - return sortedMessages - }) - export const messageSendingStatusById = (messageId: string) => createSelector(messagesSlice, reducerState => { return messageSendingStatusAdapter.getSelectors().selectById(reducerState.messageSendingStatus, messageId) @@ -140,5 +124,4 @@ export const messagesSelectors = { messagesVerificationStatus, messagesSendingStatus, messageSendingStatusById, - getMessagesFromChannelIdByPubKey, } diff --git a/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.test.ts b/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.test.ts index b6d6a51b26..6092703f43 100644 --- a/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.test.ts +++ b/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.test.ts @@ -7,7 +7,7 @@ import { expectSaga } from 'redux-saga-test-plan' import { type communitiesActions } from '../../communities/communities.slice' import { type identityActions } from '../../identity/identity.slice' import { type FactoryGirl } from 'factory-girl' -import { generateChannelId } from '@quiet/common' +import { generateChannelId, userCreatedChannelMessage, userJoinedMessage, verifyUserInfoMessage } from '@quiet/common' import { publicChannelsActions } from '../../publicChannels/publicChannels.slice' import { DateTime } from 'luxon' import { @@ -17,7 +17,6 @@ import { type PublicChannel, ChannelMessage, IncomingMessages, - userJoinedMessage, } from '@quiet/types' import { verifyMessagesSaga } from './verifyMessages.saga' import { messagesActions } from '../messages.slice' @@ -33,6 +32,7 @@ describe('verifyMessage saga test', () => { let bob: Identity let generalChannel: PublicChannel + let sportChannel: PublicChannel beforeAll(async () => { setupCrypto() @@ -64,6 +64,18 @@ describe('verifyMessage saga test', () => { }, }) ).channel + + sportChannel = ( + await factory.create['payload']>('PublicChannel', { + channel: { + name: 'sport', + description: 'Welcome to #sport', + timestamp: DateTime.utc().valueOf(), + owner: alice.nickname, + id: generateChannelId('sport'), + }, + }) + ).channel }) it('verify standard message ', async () => { @@ -89,9 +101,7 @@ describe('verifyMessage saga test', () => { await expectSaga(verifyMessagesSaga, messagesActions.incomingMessages(payload)) .withReducer(reducer) .withState(store.getState()) - .not.select(messagesSelectors.getMessagesFromChannelIdByPubKey) - .not.select(usersSelectors.allUsers) - .not.call(userJoinedMessage) + .not.call(verifyUserInfoMessage) .put( messagesActions.addMessageVerificationStatus({ publicKey: message.pubKey, @@ -125,7 +135,7 @@ describe('verifyMessage saga test', () => { await expectSaga(verifyMessagesSaga, messagesActions.incomingMessages(payload)) .withReducer(reducer) .withState(store.getState()) - .not.call(userJoinedMessage) + .not.call(verifyUserInfoMessage) .put( messagesActions.addMessageVerificationStatus({ publicKey: message.pubKey, @@ -136,7 +146,7 @@ describe('verifyMessage saga test', () => { .run() }) - it('verify info message from user on general', async () => { + it('verify info message from user on general - fail', async () => { if (!bob.userCsr?.userCsr) throw Error('no bob userCsr') const message: ChannelMessage = { @@ -160,7 +170,10 @@ describe('verifyMessage saga test', () => { await expectSaga(verifyMessagesSaga, messagesActions.incomingMessages(payload)) .withReducer(reducer) .withState(store.getState()) - .call(userJoinedMessage, 'bob') + .call(verifyUserInfoMessage, 'bob', { + ...generalChannel, + messages: { ids: [], entities: {} }, + }) .not.put( messagesActions.addMessageVerificationStatus({ publicKey: message.pubKey, @@ -170,4 +183,118 @@ describe('verifyMessage saga test', () => { ) .run() }) + + it('verify info message from user on general - success', async () => { + if (!bob.userCsr?.userCsr) throw Error('no bob userCsr') + + const message: ChannelMessage = { + id: 'id1', + type: MessageType.Info, + message: userJoinedMessage(bob.nickname), + createdAt: 24, + channelId: generalChannel.id, + signature: 'signature', + pubKey: pubKeyFromCsr(bob.userCsr?.userCsr), + media: undefined, + } + + const payload: IncomingMessages = { + messages: [message], + isVerified: true, + } + + store.dispatch(messagesActions.incomingMessages({ messages: [message] })) + const reducer = combineReducers(reducers) + await expectSaga(verifyMessagesSaga, messagesActions.incomingMessages(payload)) + .withReducer(reducer) + .withState(store.getState()) + .call(verifyUserInfoMessage, 'bob', { + ...generalChannel, + messages: { ids: [], entities: {} }, + }) + .put( + messagesActions.addMessageVerificationStatus({ + publicKey: message.pubKey, + signature: message.signature, + isVerified: true, + }) + ) + .run() + }) + + it('verify info message from user on other channel - fail', async () => { + if (!bob.userCsr?.userCsr) throw Error('no bob userCsr') + + const message: ChannelMessage = { + id: 'id1', + type: MessageType.Info, + message: 'message', + createdAt: 24, + channelId: sportChannel.id, + signature: 'signature', + pubKey: pubKeyFromCsr(bob.userCsr?.userCsr), + media: undefined, + } + + const payload: IncomingMessages = { + messages: [message], + isVerified: true, + } + + store.dispatch(messagesActions.incomingMessages({ messages: [message] })) + const reducer = combineReducers(reducers) + await expectSaga(verifyMessagesSaga, messagesActions.incomingMessages(payload)) + .withReducer(reducer) + .withState(store.getState()) + .call(verifyUserInfoMessage, 'bob', { + ...sportChannel, + messages: { ids: [], entities: {} }, + }) + .not.put( + messagesActions.addMessageVerificationStatus({ + publicKey: message.pubKey, + signature: message.signature, + isVerified: true, + }) + ) + .run() + }) + + it('verify info message from user on other channel - success', async () => { + if (!bob.userCsr?.userCsr) throw Error('no bob userCsr') + + const message: ChannelMessage = { + id: 'id1', + type: MessageType.Info, + message: userCreatedChannelMessage(bob.nickname, sportChannel.name), + createdAt: 24, + channelId: sportChannel.id, + signature: 'signature', + pubKey: pubKeyFromCsr(bob.userCsr?.userCsr), + media: undefined, + } + + const payload: IncomingMessages = { + messages: [message], + isVerified: true, + } + + store.dispatch(messagesActions.incomingMessages({ messages: [message] })) + const reducer = combineReducers(reducers) + await expectSaga(verifyMessagesSaga, messagesActions.incomingMessages(payload)) + .withReducer(reducer) + .withState(store.getState()) + .call(verifyUserInfoMessage, 'bob', { + ...sportChannel, + messages: { ids: [], entities: {} }, + }) + .put( + messagesActions.addMessageVerificationStatus({ + publicKey: message.pubKey, + signature: message.signature, + isVerified: true, + }) + ) + .run() + }) }) diff --git a/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.ts b/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.ts index 020bf37f6b..d20ab206ba 100644 --- a/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.ts +++ b/packages/state-manager/src/sagas/messages/verifyMessage/verifyMessages.saga.ts @@ -1,11 +1,11 @@ import { type PayloadAction } from '@reduxjs/toolkit' import { select, call, put, delay } from 'typed-redux-saga' import { messagesActions } from '../messages.slice' -import { MessageType, userJoinedMessage, type MessageVerificationStatus } from '@quiet/types' +import { MessageType, type MessageVerificationStatus } from '@quiet/types' import { publicChannelsSelectors } from '../../publicChannels/publicChannels.selectors' -import { messagesSelectors } from '../messages.selectors' + import { usersSelectors } from '../../users/users.selectors' -import { communitiesSelectors } from '../../communities/communities.selectors' +import { verifyUserInfoMessage } from '@quiet/common' export function* verifyMessagesSaga( action: PayloadAction>['payload'] @@ -13,35 +13,34 @@ export function* verifyMessagesSaga( const messages = action.payload.messages for (const message of messages) { - const generalChannel = yield* select(publicChannelsSelectors.generalChannel) - if (!generalChannel) return - - if (message.type === MessageType.Info && message.channelId === generalChannel.id) { - const getMessagesFromGeneralByPubKey = yield* select( - messagesSelectors.getMessagesFromChannelIdByPubKey(generalChannel.id, message.pubKey) - ) + let ownerData = yield* select(usersSelectors.ownerData) - const allUsers = yield* select(usersSelectors.allUsers) - - const username = allUsers[message.pubKey].username + while (true) { + ownerData = yield* select(usersSelectors.ownerData) + if (ownerData?.pubKey) { + break + } + yield* delay(500) + } - let ownerNickname = yield* select(communitiesSelectors.ownerNickname) + if (message.type === MessageType.Info && message.pubKey !== ownerData.pubKey) { + let user = yield* select(usersSelectors.getUserByPubKey(message.pubKey)) while (true) { - ownerNickname = yield* select(communitiesSelectors.ownerNickname) - if (ownerNickname) { + user = yield* select(usersSelectors.getUserByPubKey(message.pubKey)) + if (user) { break } yield* delay(500) } + const channel = yield* select(publicChannelsSelectors.getChannelById(message.channelId)) + if (!channel) return - if (username !== ownerNickname) { - const expectedMessage = yield* call(userJoinedMessage, username) - // Checking first info message from user on general channel to check if he was trying to send a fake malicious if so, we do not process this message further - if (getMessagesFromGeneralByPubKey[0].message !== expectedMessage) { - console.error(`${username} tried to send a malicious info message`) - return - } + const expectedMessage = yield* call(verifyUserInfoMessage, user.username, channel) + + if (message.message !== expectedMessage) { + console.error(`${user.username} tried to send a malicious info message`) + return } } diff --git a/packages/state-manager/src/sagas/publicChannels/createGeneralChannel/sendInitialChannelMessage.saga.ts b/packages/state-manager/src/sagas/publicChannels/createGeneralChannel/sendInitialChannelMessage.saga.ts index 9607e72e79..04e3d0afc0 100644 --- a/packages/state-manager/src/sagas/publicChannels/createGeneralChannel/sendInitialChannelMessage.saga.ts +++ b/packages/state-manager/src/sagas/publicChannels/createGeneralChannel/sendInitialChannelMessage.saga.ts @@ -1,10 +1,11 @@ import { type PayloadAction } from '@reduxjs/toolkit' -import { put, select } from 'typed-redux-saga' +import { put, select, call } from 'typed-redux-saga' import { messagesActions } from '../../messages/messages.slice' import { publicChannelsSelectors } from '../publicChannels.selectors' import { publicChannelsActions } from '../publicChannels.slice' import { MessageType, type WriteMessagePayload } from '@quiet/types' import { identitySelectors } from '../../identity/identity.selectors' +import { userCreatedChannelMessage } from '@quiet/common' export function* sendInitialChannelMessageSaga( action: PayloadAction['payload']> @@ -21,7 +22,7 @@ export function* sendInitialChannelMessageSaga( const message = pendingGeneralChannelRecreation && isGeneral ? `@${user?.nickname} deleted all messages in #general` - : `@${user?.nickname} created #${channelName}` + : yield* call(userCreatedChannelMessage, user?.nickname || '', channelName) const payload: WriteMessagePayload = { type: MessageType.Info, diff --git a/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.test.ts b/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.test.ts index 8d47221e7c..3883dc8f1d 100644 --- a/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.test.ts +++ b/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.test.ts @@ -29,11 +29,12 @@ describe('deleteChannelSaga', () => { let generalChannel: PublicChannel let ownerData: { - peerId: any - username?: string | null - onionAddress?: string | null - dmPublicKey?: string | null - } + username: string | null + onionAddress: string | null + peerId: string | null + dmPublicKey: string | null + pubKey: string + } | null const socket = { emit: jest.fn(), on: jest.fn() } as unknown as Socket @@ -79,7 +80,7 @@ describe('deleteChannelSaga', () => { SocketActionTypes.DELETE_CHANNEL, { channelId, - ownerPeerId: ownerData.peerId, + ownerPeerId: ownerData?.peerId, }, ]) .put(publicChannelsActions.setCurrentChannel({ channelId: generalChannel.id })) @@ -98,7 +99,7 @@ describe('deleteChannelSaga', () => { SocketActionTypes.DELETE_CHANNEL, { channelId, - ownerPeerId: ownerData.peerId, + ownerPeerId: ownerData?.peerId, }, ]) .put(filesActions.deleteFilesFromChannel({ channelId })) @@ -117,7 +118,7 @@ describe('deleteChannelSaga', () => { SocketActionTypes.DELETE_CHANNEL, { channelId, - ownerPeerId: ownerData.peerId, + ownerPeerId: ownerData?.peerId, }, ]) .not.put(publicChannelsActions.setCurrentChannel({ channelId: generalChannel.id })) @@ -136,7 +137,7 @@ describe('deleteChannelSaga', () => { SocketActionTypes.DELETE_CHANNEL, { channelId, - ownerPeerId: ownerData.peerId, + ownerPeerId: ownerData?.peerId, }, ]) .put(publicChannelsActions.disableChannel({ channelId })) diff --git a/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.ts b/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.ts index e22dd4436d..4536101b9c 100644 --- a/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.ts +++ b/packages/state-manager/src/sagas/publicChannels/deleteChannel/deleteChannel.saga.ts @@ -34,7 +34,7 @@ export function* deleteChannelSaga( socket.emit, applyEmitParams(SocketActionTypes.DELETE_CHANNEL, { channelId, - ownerPeerId: ownerData.peerId, + ownerPeerId: ownerData?.peerId, }) ) diff --git a/packages/state-manager/src/sagas/publicChannels/sendUnregisteredInfoMessage/sendUnregisteredInfoMessage.saga.ts b/packages/state-manager/src/sagas/publicChannels/sendUnregisteredInfoMessage/sendUnregisteredInfoMessage.saga.ts index 2e8ab4d02d..c12bb9a00c 100644 --- a/packages/state-manager/src/sagas/publicChannels/sendUnregisteredInfoMessage/sendUnregisteredInfoMessage.saga.ts +++ b/packages/state-manager/src/sagas/publicChannels/sendUnregisteredInfoMessage/sendUnregisteredInfoMessage.saga.ts @@ -1,9 +1,10 @@ import { put, select, call } from 'typed-redux-saga' import { messagesActions } from '../../messages/messages.slice' import { publicChannelsSelectors } from '../publicChannels.selectors' -import { WriteMessagePayload, MessageType, userJoinedMessage } from '@quiet/types' +import { WriteMessagePayload, MessageType } from '@quiet/types' import { communitiesSelectors } from '../../communities/communities.selectors' import { identitySelectors } from '../../identity/identity.selectors' +import { userJoinedMessage } from '@quiet/common' export function* sendUnregisteredInfoMessage(): Generator { const community = yield* select(communitiesSelectors.currentCommunity) diff --git a/packages/state-manager/src/sagas/users/users.selectors.ts b/packages/state-manager/src/sagas/users/users.selectors.ts index c3104fb523..059c053e3b 100644 --- a/packages/state-manager/src/sagas/users/users.selectors.ts +++ b/packages/state-manager/src/sagas/users/users.selectors.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit' -import { getCertFieldValue, getReqFieldValue } from '@quiet/identity' +import { getCertFieldValue, getReqFieldValue, keyFromCertificate } from '@quiet/identity' import { CertFieldsTypes } from './const/certFieldTypes' import { StoreKeys } from '../store.keys' import { certificatesAdapter } from './users.adapter' @@ -120,6 +120,8 @@ export const allUsers = createSelector(csrsMapping, certificatesMapping, (csrs, return users }) +export const getUserByPubKey = (pubKey: string) => createSelector(allUsers, users => users[pubKey]) + export const getOldestParsedCerificate = createSelector(certificates, certs => { const getTimestamp = (cert: Certificate) => new Date(cert.notBefore.value).getTime() let certificates: Certificate[] = [] @@ -136,16 +138,19 @@ export const getOldestParsedCerificate = createSelector(certificates, certs => { }) export const ownerData = createSelector(getOldestParsedCerificate, ownerCert => { + if (!ownerCert) return null const username = getCertFieldValue(ownerCert, CertFieldsTypes.nickName) const onionAddress = getCertFieldValue(ownerCert, CertFieldsTypes.commonName) const peerId = getCertFieldValue(ownerCert, CertFieldsTypes.peerId) const dmPublicKey = getCertFieldValue(ownerCert, CertFieldsTypes.dmPublicKey) + const pubKey = keyFromCertificate(ownerCert) return { username, onionAddress, peerId, dmPublicKey, + pubKey, } }) @@ -164,4 +169,5 @@ export const usersSelectors = { ownerData, allUsers, duplicateCerts, + getUserByPubKey, } diff --git a/packages/types/src/message.ts b/packages/types/src/message.ts index f19ba1aa0c..19f0969194 100644 --- a/packages/types/src/message.ts +++ b/packages/types/src/message.ts @@ -100,6 +100,3 @@ export interface TestMessage { identity: Identity verifyAutomatically: boolean } - -export const userJoinedMessage = (username: string) => - `**@${username}** has joined and will be registered soon. 🎉 [Learn more](https://github.com/TryQuiet/quiet/wiki/Quiet-FAQ#how-does-username-registration-work)`