From f94151bd0ac3325fa384d48f98cb27c5d0d7f66b Mon Sep 17 00:00:00 2001 From: Wiktor Sieprawski Date: Mon, 13 Nov 2023 14:23:05 +0100 Subject: [PATCH] Fix/Use CSRs in mocking test data #1900 (#2053) * test: use factory-girl in users selectors tests * test: include csrs in factory-girl models * test: add tests for 'duplicate' label #1900 * fix: register username test * fix: public channel selectors test * fix: remaining tests * fix: lint * fix: rtl tests * fix: lint --- .../src/rtl-tests/community.join.test.tsx | 5 +- packages/identity/src/test/helpers.ts | 24 +-- .../registerUsername.saga.test.ts | 63 +++----- .../publicChannels.selectors.test.ts | 6 + .../src/sagas/users/users.selectors.test.ts | 139 +++++++++++------- .../src/sagas/users/users.selectors.ts | 11 +- .../src/sagas/users/users.slice.ts | 6 +- .../src/utils/tests/factories.ts | 73 ++++++--- 8 files changed, 200 insertions(+), 127 deletions(-) diff --git a/packages/desktop/src/rtl-tests/community.join.test.tsx b/packages/desktop/src/rtl-tests/community.join.test.tsx index 8768895ad5..aa6151d916 100644 --- a/packages/desktop/src/rtl-tests/community.join.test.tsx +++ b/packages/desktop/src/rtl-tests/community.join.test.tsx @@ -116,13 +116,14 @@ describe('User', () => { }, communityHelper.CA ) - const certificate = certificateHelper.userCert.userCertString + const certificate = certificateHelper.userCert?.userCertString const rootCa = communityHelper.CA?.rootCertString return socket.socketClient.emit(SocketActionTypes.SEND_USER_CERTIFICATE, { communityId: payload.communityId, payload: { + // @ts-expect-error - This is statically mocked data so it'll never be undefined certificate: certificate, - // @ts-expect-error + // @ts-expect-error - This is statically mocked data so it'll never be undefined rootCa: rootCa, peers: [], }, diff --git a/packages/identity/src/test/helpers.ts b/packages/identity/src/test/helpers.ts index 5a79e698ef..68760bfbb8 100644 --- a/packages/identity/src/test/helpers.ts +++ b/packages/identity/src/test/helpers.ts @@ -64,10 +64,10 @@ export const createUserCertificateTestHelper = async ( peerId: string dmPublicKey: string }, - rootCA: Pick + rootCA?: Pick | null ): Promise<{ - userCert: UserCert userCsr: UserCsr + userCert?: UserCert }> => { const userCsr = await createUserCsr({ nickname: user.nickname, @@ -77,13 +77,19 @@ export const createUserCertificateTestHelper = async ( signAlg: config.signAlg, hashAlg: config.hashAlg, }) - const userCert = await createUserCert( - rootCA.rootCertString, - rootCA.rootKeyString, - userCsr.userCsr, - notBeforeDate, - notAfterDate - ) + + let userCert + + if (rootCA) { + userCert = await createUserCert( + rootCA.rootCertString, + rootCA.rootKeyString, + userCsr.userCsr, + notBeforeDate, + notAfterDate + ) + } + return { userCsr, userCert, diff --git a/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.test.ts b/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.test.ts index f536ec15be..3a10b2ebda 100644 --- a/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.test.ts +++ b/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.test.ts @@ -11,11 +11,11 @@ import { type communitiesActions } from '../../communities/communities.slice' import { config } from '../../users/const/certFieldTypes' import { CertData, CreateUserCsrPayload, SocketActionTypes } from '@quiet/types' import { Socket } from '../../../types' -import { connectionActions } from '../../appConnection/connection.slice' describe('registerUsernameSaga', () => { it('create user csr', async () => { setupCrypto() + const socket = { emit: jest.fn(), on: jest.fn() } as unknown as Socket const store = prepareStore().store @@ -25,23 +25,15 @@ describe('registerUsernameSaga', () => { const community = await factory.create['payload']>( 'Community', { - id: '1', - name: 'rockets', - registrarUrl: 'registrarUrl', CA: null, - rootCa: 'rootCa', - peerList: [], - registrar: null, - onionAddress: '', - privateKey: '', - port: 0, + rootCa: 'rootCertString', } ) // Identity won't have userCsr as long as its corresponding community has no CA (factory specific logic) const identity = await factory.create['payload']>('Identity', { - nickname: undefined, id: community.id, + nickname: undefined, userCsr: null, }) @@ -59,6 +51,7 @@ describe('registerUsernameSaga', () => { signAlg: config.signAlg, hashAlg: config.hashAlg, } + const reducer = combineReducers(reducers) await expectSaga(registerUsernameSaga, socket, identityActions.registerUsername({ nickname: 'nickname' })) .withReducer(reducer) @@ -95,23 +88,12 @@ describe('registerUsernameSaga', () => { const factory = await getFactory(store) - const community = await factory.create['payload']>( - 'Community', - { - id: '1', - name: 'rockets', - registrarUrl: 'registrarUrl', - CA: null, - rootCa: 'rootCa', - peerList: [], - registrar: null, - onionAddress: '', - privateKey: '', - port: 0, - } - ) + const community = + await factory.create['payload']>('Community') + const oldNickname = 'john' const newNickname = 'paul' + const userCsr: UserCsr = { userCsr: 'userCsr', userKey: 'userKey', @@ -123,6 +105,7 @@ describe('registerUsernameSaga', () => { id: community.id, userCsr: userCsr, }) + if (!identity.userCsr?.userCsr) return const pubKey = 'pubKey' const privateKey = 'privateKey' @@ -140,6 +123,7 @@ describe('registerUsernameSaga', () => { publicKey: publicKey as unknown as CryptoKey, }, } + const reducer = combineReducers(reducers) await expectSaga( registerUsernameSaga, @@ -168,30 +152,19 @@ describe('registerUsernameSaga', () => { ) .run() }) - //outdated + + // Outdated it.skip("reuse existing csr if provided username hasn't changed", async () => { setupCrypto() + const socket = { emit: jest.fn(), on: jest.fn() } as unknown as Socket const store = prepareStore().store const factory = await getFactory(store) - const community = await factory.create['payload']>( - 'Community', - { - id: '1', - name: 'rockets', - registrarUrl: 'registrarUrl', - CA: null, - rootCa: 'rootCa', - peerList: [], - registrar: null, - onionAddress: '', - privateKey: '', - port: 0, - } - ) + const community = + await factory.create['payload']>('Community') const userCsr: UserCsr = { userCsr: 'userCsr', @@ -209,6 +182,7 @@ describe('registerUsernameSaga', () => { identity.userCsr = userCsr store.dispatch(identityActions.addNewIdentity(identity)) + const reducer = combineReducers(reducers) await expectSaga(registerUsernameSaga, socket, identityActions.registerUsername({ nickname: identity.nickname })) .withReducer(reducer) @@ -234,9 +208,11 @@ describe('registerUsernameSaga', () => { ) .run() }) - //outdated + + // Outdated it.skip("don't reuse existing csr if provided username has changed", async () => { setupCrypto() + const socket = { emit: jest.fn(), on: jest.fn() } as unknown as Socket const store = prepareStore().store @@ -290,6 +266,7 @@ describe('registerUsernameSaga', () => { signAlg: config.signAlg, hashAlg: config.hashAlg, } + const reducer = combineReducers(reducers) await expectSaga( registerUsernameSaga, diff --git a/packages/state-manager/src/sagas/publicChannels/publicChannels.selectors.test.ts b/packages/state-manager/src/sagas/publicChannels/publicChannels.selectors.test.ts index 2a2c205e8c..f392b997f3 100644 --- a/packages/state-manager/src/sagas/publicChannels/publicChannels.selectors.test.ts +++ b/packages/state-manager/src/sagas/publicChannels/publicChannels.selectors.test.ts @@ -59,14 +59,18 @@ describe('publicChannelsSelectors', () => { id: community.id, nickname: 'alice', }) + const generalChannelState = publicChannelsSelectors.generalChannel(store.getState()) if (generalChannelState) generalChannel = generalChannelState + expect(generalChannel).not.toBeUndefined() + channelIdes = [...channelIdes, generalChannel.id] john = await factory.create['payload']>('Identity', { id: community.id, nickname: 'john', }) + store.dispatch(publicChannelsActions.setCurrentChannel({ channelId: generalChannel.id })) // Setup channels const channelNames = ['croatia', 'allergies', 'sailing', 'pets', 'antiques'] @@ -317,6 +321,8 @@ describe('publicChannelsSelectors', () => { if (!elouise.userCertificate) throw new Error('no elouise.userCertificate') store.dispatch(usersActions.test_remove_user_certificate({ certificate: elouise.userCertificate })) + // @ts-expect-error - This is statically mocked data so it'll never be undefined + store.dispatch(usersActions.test_remove_user_csr({ csr: elouise.userCsr?.userCsr })) store.dispatch( publicChannelsActions.setCurrentChannel({ diff --git a/packages/state-manager/src/sagas/users/users.selectors.test.ts b/packages/state-manager/src/sagas/users/users.selectors.test.ts index af526fad92..50af782c63 100644 --- a/packages/state-manager/src/sagas/users/users.selectors.test.ts +++ b/packages/state-manager/src/sagas/users/users.selectors.test.ts @@ -1,67 +1,76 @@ -import { combineReducers, createStore, type Store } from '@reduxjs/toolkit' -import { StoreKeys } from '../store.keys' +import { Store } from '@reduxjs/toolkit' +import { prepareStore } from '../../utils/tests/prepareStore' -import { communitiesReducer, CommunitiesState } from '../communities/communities.slice' +import { FactoryGirl } from 'factory-girl' +import { getFactory } from '../../utils/tests/factories' -import { usersReducer, UsersState } from '../users/users.slice' +import { keyFromCertificate, parseCertificate, parseCertificationRequest } from '@quiet/identity' +import { Identity, Community } from '@quiet/types' + +import { communitiesActions, communitiesReducer, CommunitiesState } from '../communities/communities.slice' + +import { identityActions } from '../identity/identity.slice' -import { communitiesAdapter } from '../communities/communities.adapter' -import { certificatesAdapter } from '../users/users.adapter' -import { keyFromCertificate, parseCertificate } from '@quiet/identity' import { usersSelectors } from './users.selectors' -import { type Community } from '@quiet/types' describe('users selectors', () => { let store: Store + let factory: FactoryGirl - const quietcommunity: Community = { - // TODO CHECK - name: 'quietcommunity', - id: 'quietcommunity', - CA: { - rootCertString: - 'MIIBYDCCAQagAwIBAgIBATAKBggqhkjOPQQDAjAZMRcwFQYDVQQDEw5xdWlldGNvbW11bml0eTAeFw0xMDEyMjgxMDEwMTBaFw0zMDEyMjgxMDEwMTBaMBkxFzAVBgNVBAMTDnF1aWV0Y29tbXVuaXR5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER8nj5zrEqEvjOZe1hIGx7fwXXNF2AwklSh7zBNnZSZpQfAdyeBTCF76OMQoSroZKmHkOw6EtvLhDmDA31lnFfaM/MD0wDwYDVR0TBAgwBgEB/wIBAzALBgNVHQ8EBAMCAIYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAoGCCqGSM49BAMCA0gAMEUCIQCLh+vUNv1Czj6N+QGe1wXH/EK1EDpv7FhNQ7KoJLPUPgIgbkZZccoEQYIiK6fgdofZ1OIPWGQcazY6yfcUpGop8PQ=', - rootKeyString: - 'MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgzwEMy6znlS1amoN8tcrNUXTO7WGTagioyI5XwKj8mdygCgYIKoZIzj0DAQehRANCAARHyePnOsSoS+M5l7WEgbHt/Bdc0XYDCSVKHvME2dlJmlB8B3J4FMIXvo4xChKuhkqYeQ7DoS28uEOYMDfWWcV9', - }, - rootCa: '', - } + let community: Community - const userCertData = { - username: 'userName', + let alice: Identity + let alicePublicKey: string + + const aliceCertificateData = { + dmPublicKey: '0bfb475810c0e26c9fab590d47c3d60ec533bb3c451596acc3cd4f21602e9ad9', onionAddress: 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', peerId: 'Qmf3ySkYqLET9xtAtDzvAr5Pp3egK1H3C5iJAZm1SpLEp6', - dmPublicKey: '0bfb475810c0e26c9fab590d47c3d60ec533bb3c451596acc3cd4f21602e9ad9', + username: 'alice', } - const userCertString = - 'MIICaDCCAg6gAwIBAgIGAYBqyuV2MAoGCCqGSM49BAMCMBkxFzAVBgNVBAMTDnF1aWV0Y29tbXVuaXR5MB4XDTEwMTIyODEwMTAxMFoXDTMwMTIyODEwMTAxMFowSTFHMEUGA1UEAxM+bnFudzRrYzRjNzdmYjQ3bGs1Mm01bDU3aDR0Y3hjZW83eW14ZWtmbjd5aDVtNjZ0NGp2Mm9sYWQub25pb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQZBMmiVmRBRvw+QiL5DYg7WGFUVgA7u90KMpJg4qCaCJJNh7wH2tl0EDsN4FeGmR9AkvtCGd+5vYL0nGcX/oLdo4IBEDCCAQwwCQYDVR0TBAIwADALBgNVHQ8EBAMCAIAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMC8GCSqGSIb3DQEJDAQiBCAL+0dYEMDibJ+rWQ1Hw9YOxTO7PEUVlqzDzU8hYC6a2TAYBgorBgEEAYOMGwIBBAoTCHVzZXJOYW1lMD0GCSsGAQIBDwMBAQQwEy5RbWYzeVNrWXFMRVQ5eHRBdER6dkFyNVBwM2VnSzFIM0M1aUpBWm0xU3BMRXA2MEkGA1UdEQRCMECCPm5xbnc0a2M0Yzc3ZmI0N2xrNTJtNWw1N2g0dGN4Y2VvN3lteGVrZm43eWg1bTY2dDRqdjJvbGFkLm9uaW9uMAoGCCqGSM49BAMCA0gAMEUCIF63rnIq8vd86NT9RHSFj7borwwODqyfE7Pw64tGElpIAiEA5ZDSdrDd8OGf+kv7wxByM1Xgmc5m/aydUk+WorbO3Gg=' - const parsedCert = parseCertificate(userCertString) - const userPubKey = keyFromCertificate(parsedCert) - - beforeEach(() => { - store = createStore( - combineReducers({ - [StoreKeys.Communities]: communitiesReducer, - [StoreKeys.Users]: usersReducer, - }), - { - [StoreKeys.Communities]: { - ...new CommunitiesState(), - currentCommunity: 'communityId', - communities: communitiesAdapter.setAll(communitiesAdapter.getInitialState(), [quietcommunity]), - }, - [StoreKeys.Users]: { - ...new UsersState(), - certificates: certificatesAdapter.setAll(certificatesAdapter.getInitialState(), [parsedCert]), - }, - } - ) + let aliceUnregistered: Identity + let aliceUnregisteredPublicKey: string + + beforeAll(async () => { + store = prepareStore().store + + factory = await getFactory(store) + + community = await factory.create['payload']>('Community') + + alice = await factory.create['payload']>('Identity', { + id: community.id, + nickname: aliceCertificateData.username, + hiddenService: { + onionAddress: aliceCertificateData.onionAddress, + privateKey: '', + }, + peerId: { + id: aliceCertificateData.peerId, + }, + dmKeys: { + publicKey: aliceCertificateData.dmPublicKey, + privateKey: '', + }, + }) + + const parsedAliceCertificate = parseCertificate(alice.userCertificate!) + alicePublicKey = keyFromCertificate(parsedAliceCertificate) + + aliceUnregistered = await factory.create['payload']>('Identity', { + id: community.id, + nickname: aliceCertificateData.username, + userCertificate: null, + }) + + const parsedAliceUnregisteredCertificationRequest = parseCertificationRequest(aliceUnregistered.userCsr!.userCsr) + aliceUnregisteredPublicKey = keyFromCertificate(parsedAliceUnregisteredCertificationRequest) }) it('get proper user certificate from store', async () => { const certificates = usersSelectors.certificates(store.getState()) - const userCertificate = certificates[userPubKey] || null + const userCertificate = certificates[alicePublicKey] || null expect(userCertificate).not.toBeNull() }) @@ -69,17 +78,47 @@ describe('users selectors', () => { it('get proper fields from user certificate', async () => { const usersData = usersSelectors.certificatesMapping(store.getState()) - expect(usersData[userPubKey]).toEqual(userCertData) + expect(usersData[alicePublicKey]).toEqual(aliceCertificateData) - expect(usersData[userPubKey]).toMatchInlineSnapshot(` + expect(usersData[alicePublicKey]).toMatchInlineSnapshot(` Object { "dmPublicKey": "0bfb475810c0e26c9fab590d47c3d60ec533bb3c451596acc3cd4f21602e9ad9", "onionAddress": "nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion", "peerId": "Qmf3ySkYqLET9xtAtDzvAr5Pp3egK1H3C5iJAZm1SpLEp6", - "username": "userName", + "username": "alice", } `) }) + + it("gets registered user with proper 'isRegistered' prop", async () => { + const users = usersSelectors.allUsers(store.getState()) + + expect(users[alicePublicKey]).toMatchObject({ + isRegistered: true, + }) + }) + + it("gets unregistered user with proper 'isRegistered' prop", async () => { + const users = usersSelectors.allUsers(store.getState()) + + expect(users[aliceUnregisteredPublicKey]).toMatchObject({ + isRegistered: false, + }) + }) + + it("gets all users (registered users don't get 'duplicate' label over unregistered ones)", async () => { + const users = usersSelectors.allUsers(store.getState()) + + expect(users[alicePublicKey]).toMatchObject({ + isDuplicated: false, + isRegistered: true, + }) + + expect(users[aliceUnregisteredPublicKey]).toMatchObject({ + isDuplicated: true, + isRegistered: false, + }) + }) }) export {} diff --git a/packages/state-manager/src/sagas/users/users.selectors.ts b/packages/state-manager/src/sagas/users/users.selectors.ts index 1b8914a1a4..c3104fb523 100644 --- a/packages/state-manager/src/sagas/users/users.selectors.ts +++ b/packages/state-manager/src/sagas/users/users.selectors.ts @@ -47,6 +47,7 @@ export const certificatesMapping = createSelector(certificates, certs => { export const csrsMapping = createSelector(csrs, csrs => { const mapping: Record = {} + Object.keys(csrs).map(pubKey => { const csr = csrs[pubKey] if (!csr || csr.subject.typesAndValues.length < 1) { @@ -70,13 +71,15 @@ export const csrsMapping = createSelector(csrs, csrs => { dmPublicKey, }) }) + return mapping }) export const allUsers = createSelector(csrsMapping, certificatesMapping, (csrs, certs) => { const users: Record = {} + const allUsernames: string[] = Object.values(csrs).map(u => u.username) - const duplicateUsernames: string[] = allUsernames.filter((val, index) => allUsernames.indexOf(val) !== index) + const duplicatedUsernames: string[] = allUsernames.filter((val, index) => allUsernames.indexOf(val) !== index) // Temporary backward compatiblility! Old communities do not have csrs Object.keys(certs).map(pubKey => { @@ -97,17 +100,20 @@ export const allUsers = createSelector(csrsMapping, certificatesMapping, (csrs, if (certs[pubKey]?.username) { isDuplicated = false } else { - isDuplicated = duplicateUsernames.includes(username) + isDuplicated = duplicatedUsernames.includes(username) } const isRegistered = Boolean(certs[pubKey]) + console.log('Unregistered Debug - allUsers selector - csrs - certs[pubKey]', certs[pubKey]) + users[pubKey] = { ...csrs[pubKey], isRegistered, isDuplicated, pubKey, } + console.log('Unregistered Debug - allUsers selector - csrs - user', users[pubKey]) }) @@ -150,6 +156,7 @@ export const duplicateCerts = createSelector(certificatesMapping, certs => { }) export const usersSelectors = { + csrs, certificates, certificatesMapping, csrsMapping, diff --git a/packages/state-manager/src/sagas/users/users.slice.ts b/packages/state-manager/src/sagas/users/users.slice.ts index 27ecdf1e65..41add27d6e 100644 --- a/packages/state-manager/src/sagas/users/users.slice.ts +++ b/packages/state-manager/src/sagas/users/users.slice.ts @@ -17,8 +17,7 @@ export const usersSlice = createSlice({ storeUserCertificate: (state, action: PayloadAction<{ certificate: string }>) => { certificatesAdapter.addOne(state.certificates, parseCertificate(action.payload.certificate)) }, - responseSendCertificates: (state, action: PayloadAction) => {}, - + responseSendCertificates: (state, _action: PayloadAction) => state, setAllCerts: (state, action: PayloadAction) => { certificatesAdapter.setAll( state.certificates, @@ -48,6 +47,9 @@ export const usersSlice = createSlice({ keyFromCertificate(parseCertificate(action.payload.certificate)) ) }, + test_remove_user_csr: (state, action: PayloadAction<{ csr: string }>) => { + certificatesAdapter.removeOne(state.csrs, keyFromCertificate(parseCertificationRequest(action.payload.csr))) + }, }, }) diff --git a/packages/state-manager/src/utils/tests/factories.ts b/packages/state-manager/src/utils/tests/factories.ts index 3dc543e68c..f59eb396d6 100644 --- a/packages/state-manager/src/utils/tests/factories.ts +++ b/packages/state-manager/src/utils/tests/factories.ts @@ -1,22 +1,28 @@ import factoryGirl from 'factory-girl' + import { CustomReduxAdapter } from './reduxAdapter' -import { type Store } from '../../sagas/store.types' -import { communities, identity, messages, publicChannels, users, errors } from '../..' + +import { Store } from '../../sagas/store.types' + import { createMessageSignatureTestHelper, createPeerIdTestHelper } from './helpers' -import { getCrypto } from 'pkijs' + +import { CertificationRequest, getCrypto } from 'pkijs' import { stringToArrayBuffer } from 'pvutils' import { DateTime } from 'luxon' -import { messagesActions } from '../../sagas/messages/messages.slice' -import { publicChannelsActions } from '../../sagas/publicChannels/publicChannels.slice' + +import { communities, identity, messages, publicChannels, users, errors } from '../..' + import { generateChannelId } from '@quiet/common' + import { createRootCertificateTestHelper, createUserCertificateTestHelper, keyObjectFromString, verifySignature, } from '@quiet/identity' -import { type ChannelMessage, type FileMetadata, MessageType, SendingStatus } from '@quiet/types' + +import { ChannelMessage, FileMetadata, MessageType, SendingStatus } from '@quiet/types' export const generateMessageFactoryContentWithId = ( channelId: string, @@ -91,31 +97,55 @@ export const getFactory = async (store: Store) => { privateKey: '4dcebbf395c0e9415bc47e52c96fcfaf4bd2485a516f45118c2477036b45fc0b', }, nickname: factory.sequence('Identity.nickname', (n: number) => `user_${n}`), + userCsr: undefined, userCertificate: undefined, // 21.09.2022 - may be useful for testing purposes joinTimestamp: 1663747464000, }, { afterBuild: async (action: ReturnType) => { + const createCsr = action.payload.userCsr === undefined const requestCertificate = action.payload.userCertificate === undefined - const community = communities.selectors.selectEntities(store.getState())[action.payload.id] - if (requestCertificate && community?.CA) { - const userCertData = await createUserCertificateTestHelper( - { - nickname: action.payload.nickname, - commonName: action.payload.hiddenService.onionAddress, - peerId: action.payload.peerId.id, - dmPublicKey: action.payload.dmKeys.publicKey, - }, - community.CA - ) + + const community = communities.selectors.selectEntities(store.getState())[action.payload.id]! + + const userCertData = await createUserCertificateTestHelper( + { + nickname: action.payload.nickname, + commonName: action.payload.hiddenService.onionAddress, + peerId: action.payload.peerId.id, + dmPublicKey: action.payload.dmKeys.publicKey, + }, + community.CA + ) + + if (createCsr) { action.payload.userCsr = userCertData.userCsr + + const csrsObjects = users.selectors.csrs(store.getState()) + + // TODO: Converting CertificationRequest to string can be an util method + const csrsStrings = Object.values(csrsObjects) + .map(obj => { + if (!(obj instanceof CertificationRequest)) return + return Buffer.from(obj.toSchema(true).toBER(false)).toString('base64') + }) + .filter(Boolean) // Filter out possible `undefined` values + + await factory.create('UserCSR', { + csrs: csrsStrings.concat([userCertData.userCsr.userCsr]), + }) + } + + if (requestCertificate && userCertData.userCert?.userCertString) { action.payload.userCertificate = userCertData.userCert.userCertString + // Store user's certificate even if the user won't be stored itself // (to be able to display messages sent by this user) await factory.create('UserCertificate', { certificate: action.payload.userCertificate, }) + if (!community.ownerCertificate) { store.dispatch( communities.actions.addOwnerCertificate({ @@ -125,11 +155,16 @@ export const getFactory = async (store: Store) => { ) } } + return action }, } ) + factory.define('UserCSR', users.actions.storeCsrs, { + csrs: [], + }) + factory.define('UserCertificate', users.actions.storeUserCertificate, { certificate: factory.assoc('Identity', 'userCertificate'), }) @@ -224,7 +259,7 @@ export const getFactory = async (store: Store) => { }, afterCreate: async (payload: ReturnType['payload']) => { store.dispatch( - messagesActions.incomingMessages({ + messages.actions.incomingMessages({ messages: [payload.message], }) ) @@ -234,7 +269,7 @@ export const getFactory = async (store: Store) => { } ) - factory.define('CacheMessages', publicChannelsActions.cacheMessages, { + factory.define('CacheMessages', publicChannels.actions.cacheMessages, { messages: [], channelId: factory.assoc('PublicChannel', 'id'), communityId: factory.assoc('Community', 'id'),