Skip to content

Commit

Permalink
Fix/using custom protocol multiple times causes wrong invitation code…
Browse files Browse the repository at this point in the history
…s being stored #1847 (#2068)

* fix: mock store readyness for mobile tests

* test: deep linking on mobile

* test: deep linking on desktop

* fix: correct store data injecting #1847

* test: remove component from rendering

* chore: update CHANGELOG

* test: adjust tests after merging psk work

* chore: refactor invitation data mocking

* fix: lint

* fix: test snapshot for mobile deep linking

* chore: skip mobile splash screen tests due to changes made to data mocking
  • Loading branch information
siepra authored Nov 15, 2023
1 parent ba5fd3e commit de4dc66
Show file tree
Hide file tree
Showing 15 changed files with 209 additions and 50 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[unreleased]

* Fix network data proceeding when using custom protocol multiple times #1847

* Backward incompatible change: use pre shared key as connection protector in libp2p. Add libp2p psk to invitation link

[2.0.3-alpha.1]
Expand Down
41 changes: 27 additions & 14 deletions packages/common/src/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,32 @@ import { InvitationData } from '@quiet/types'
import { composeInvitationDeepUrl, composeInvitationShareUrl } from './invitationCode'
import { QUIET_JOIN_PAGE } from './static'

const validInvitationCodeTestData: InvitationData = {
pairs: [
{
onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd',
peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE',
},
],
psk: 'BNlxfE2WBF7LrlpIX0CvECN5o1oZtA16PkAb7GYiwYw=',
}
export const validInvitationCodeTestData: InvitationData[] = [
{
pairs: [
{
onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd',
peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE',
},
],
psk: 'BNlxfE2WBF7LrlpIX0CvECN5o1oZtA16PkAb7GYiwYw=',
},
{
pairs: [
{
onionAddress: 'pgzlcstu4ljvma7jqyalimcxlvss5bwlbba3c3iszgtwxee4qjdlgeqd',
peerId: 'QmaRchXhkPWq8iLiMZwFfd2Yi4iESWhAYYJt8cTCVXSwpG',
},
],
psk: '5T9GBVpDoRpKJQK4caDTz5e5nym2zprtoySL2oLrzr4=',
},
]

export const validInvitationUrlTestData = {
shareUrl: () => composeInvitationShareUrl(validInvitationCodeTestData),
deepUrl: () => composeInvitationDeepUrl(validInvitationCodeTestData),
code: () => composeInvitationShareUrl(validInvitationCodeTestData).split(QUIET_JOIN_PAGE + '#')[1],
data: validInvitationCodeTestData,
export const getValidInvitationUrlTestData = (data: InvitationData) => {
return {
shareUrl: () => composeInvitationShareUrl(data),
deepUrl: () => composeInvitationDeepUrl(data),
code: () => composeInvitationShareUrl(data).split(QUIET_JOIN_PAGE + '#')[1],
data: data,
}
}
4 changes: 2 additions & 2 deletions packages/desktop/src/main/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { autoUpdater } from 'electron-updater'
import { BrowserWindow, app, ipcMain, Menu } from 'electron'
import { waitFor } from '@testing-library/dom'
import path from 'path'
import { composeInvitationDeepUrl, validInvitationUrlTestData } from '@quiet/common'
import { composeInvitationDeepUrl, getValidInvitationUrlTestData, validInvitationCodeTestData } from '@quiet/common'
import { InvitationData } from '@quiet/types'

// eslint-disable-next-line
Expand Down Expand Up @@ -241,7 +241,7 @@ describe('Invitation code', () => {
let codes: InvitationData

beforeEach(() => {
codes = { ...validInvitationUrlTestData.data }
codes = { ...getValidInvitationUrlTestData(validInvitationCodeTestData[0]).data }
})

it('handles invitation code on open-url event (on macos)', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ import PerformCommunityActionComponent from '../PerformCommunityActionComponent'
import { inviteLinkField } from '../../../forms/fields/communityFields'
import { InviteLinkErrors } from '../../../forms/fieldsErrors'
import { CommunityOwnership } from '@quiet/types'
import { Site, QUIET_JOIN_PAGE, validInvitationUrlTestData, PSK_PARAM_KEY } from '@quiet/common'
import {
Site,
QUIET_JOIN_PAGE,
validInvitationCodeTestData,
getValidInvitationUrlTestData,
PSK_PARAM_KEY,
} from '@quiet/common'

describe('join community', () => {
const validCode = validInvitationUrlTestData.code()
const validData = validInvitationUrlTestData.data
const psk = validInvitationUrlTestData.data.psk
const { code, data } = getValidInvitationUrlTestData(validInvitationCodeTestData[0])

const validCode = code()

it('users switches from join to create', async () => {
const { store } = await prepareStore({
Expand Down Expand Up @@ -127,7 +133,7 @@ describe('join community', () => {
expect(submitButton).toBeEnabled()
await userEvent.click(submitButton)

await waitFor(() => expect(handleCommunityAction).toBeCalledWith(validData))
await waitFor(() => expect(handleCommunityAction).toBeCalledWith(data))
})

it.each([[`${QUIET_JOIN_PAGE}#${validCode}`], [`${QUIET_JOIN_PAGE}/#${validCode}`]])(
Expand Down Expand Up @@ -161,7 +167,7 @@ describe('join community', () => {
expect(submitButton).toBeEnabled()
await userEvent.click(submitButton)

await waitFor(() => expect(handleCommunityAction).toBeCalledWith(validData))
await waitFor(() => expect(handleCommunityAction).toBeCalledWith(data))
}
)

Expand Down Expand Up @@ -194,12 +200,12 @@ describe('join community', () => {
expect(submitButton).toBeEnabled()
await userEvent.click(submitButton)

await waitFor(() => expect(handleCommunityAction).toBeCalledWith(validData))
await waitFor(() => expect(handleCommunityAction).toBeCalledWith(data))
})

it.each([
[`http://${validCode}`, InviteLinkErrors.InvalidCode],
[`QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=bbb&${PSK_PARAM_KEY}=${psk}`, InviteLinkErrors.InvalidCode],
[`QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=bbb&${PSK_PARAM_KEY}=${data.psk}`, InviteLinkErrors.InvalidCode],
['bbb=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', InviteLinkErrors.InvalidCode],
['QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE= ', InviteLinkErrors.InvalidCode],
['nqnw4kc4c77fb47lk52m5l57h4tc', InviteLinkErrors.InvalidCode],
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src/renderer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ ipcRenderer.on('force-save-state', async _event => {
ipcRenderer.on('invitation', (_event, invitation: { data: InvitationData }) => {
if (!invitation.data) return
console.log('invitation', invitation.data.pairs, 'dispatching action')
store.dispatch(communities.actions.handleInvitationCodes(invitation.data))
store.dispatch(communities.actions.customProtocol(invitation.data))
})

const container = document.getElementById('root')
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop/src/renderer/sagas/index.saga.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { communities } from '@quiet/state-manager'
import { all, takeEvery } from 'redux-saga/effects'
import { handleInvitationCodeSaga } from './invitation/handleInvitationCode.saga'
import { customProtocolSaga } from './invitation/customProtocol.saga'
import { startConnectionSaga } from './socket/socket.saga'
import { socketActions } from './socket/socket.slice'

export default function* root(): Generator {
const dataPort = new URLSearchParams(window.location.search).get('dataPort') || ''
yield all([
takeEvery(communities.actions.handleInvitationCodes.type, handleInvitationCodeSaga),
takeEvery(communities.actions.customProtocol.type, customProtocolSaga),
startConnectionSaga(
socketActions.startConnection({
dataPort: parseInt(dataPort),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { communities, getFactory, Store } from '@quiet/state-manager'
import { Community, CommunityOwnership, CreateNetworkPayload, InvitationData } from '@quiet/types'
import { FactoryGirl } from 'factory-girl'
import { expectSaga } from 'redux-saga-test-plan'
import { handleInvitationCodeSaga } from './handleInvitationCode.saga'
import { customProtocolSaga } from './customProtocol.saga'
import { SocketState } from '../socket/socket.slice'
import { prepareStore } from '../../testUtils/prepareStore'
import { StoreKeys } from '../../store/store.keys'
import { modalsActions } from '../modals/modals.slice'
import { ModalName } from '../modals/modals.types'
import { validInvitationUrlTestData } from '@quiet/common'
import { validInvitationCodeTestData, getValidInvitationUrlTestData } from '@quiet/common'

describe('Handle invitation code', () => {
let store: Store
Expand All @@ -27,7 +27,8 @@ describe('Handle invitation code', () => {
).store

factory = await getFactory(store)
validInvitationData = validInvitationUrlTestData.data

validInvitationData = getValidInvitationUrlTestData(validInvitationCodeTestData[0]).data
})

it('creates network if code is valid', async () => {
Expand All @@ -36,7 +37,7 @@ describe('Handle invitation code', () => {
peers: validInvitationData.pairs,
psk: validInvitationData.psk,
}
await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCodes(validInvitationData))
await expectSaga(customProtocolSaga, communities.actions.customProtocol(validInvitationData))
.withState(store.getState())
.put(communities.actions.createNetwork(payload))
.run()
Expand All @@ -50,7 +51,7 @@ describe('Handle invitation code', () => {
psk: validInvitationData.psk,
}

await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCodes(validInvitationData))
await expectSaga(customProtocolSaga, communities.actions.customProtocol(validInvitationData))
.withState(store.getState())
.put(
modalsActions.openModal({
Expand All @@ -72,8 +73,8 @@ describe('Handle invitation code', () => {
}

await expectSaga(
handleInvitationCodeSaga,
communities.actions.handleInvitationCodes({
customProtocolSaga,
communities.actions.customProtocol({
pairs: [],
psk: '12345',
})
Expand All @@ -100,8 +101,8 @@ describe('Handle invitation code', () => {
}

await expectSaga(
handleInvitationCodeSaga,
communities.actions.handleInvitationCodes({
customProtocolSaga,
communities.actions.customProtocol({
pairs: validInvitationData.pairs,
psk: '',
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { socketSelectors } from '../socket/socket.selectors'
import { ModalName } from '../modals/modals.types'
import { modalsActions } from '../modals/modals.slice'

export function* handleInvitationCodeSaga(
action: PayloadAction<ReturnType<typeof communities.actions.handleInvitationCodes>['payload']>
export function* customProtocolSaga(
action: PayloadAction<ReturnType<typeof communities.actions.customProtocol>['payload']>
): Generator {
while (true) {
const connected = yield* select(socketSelectors.isConnected)
Expand All @@ -17,8 +17,8 @@ export function* handleInvitationCodeSaga(
yield* delay(500)
}

const currentCommunityId = yield* select(communities.selectors.currentCommunityId)
if (currentCommunityId) {
const community = yield* select(communities.selectors.currentCommunity)
if (community) {
yield* put(
modalsActions.openModal({
name: ModalName.warningModal,
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src/rtl-tests/customProtocol.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('Opening app through custom protocol', () => {
psk: '12345',
}

store.dispatch(communities.actions.handleInvitationCodes(invitationCodes))
store.dispatch(communities.actions.customProtocol(invitationCodes))

store.dispatch(modalsActions.openModal({ name: ModalName.joinCommunityModal }))

Expand Down
61 changes: 61 additions & 0 deletions packages/desktop/src/rtl-tests/deep.linking.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react'
import '@testing-library/jest-dom/extend-expect'
import { act } from 'react-dom/test-utils'
import { AnyAction } from 'redux'
import { take } from 'typed-redux-saga'
import MockedSocket from 'socket.io-mock'
import { ioMock } from '../shared/setupTests'
import { prepareStore } from '../renderer/testUtils/prepareStore'
import { renderComponent } from '../renderer/testUtils/renderComponent'
import { validInvitationCodeTestData } from '@quiet/common'
import { communities } from '@quiet/state-manager'

describe('Deep linking', () => {
let socket: MockedSocket

beforeEach(async () => {
socket = new MockedSocket()
ioMock.mockImplementation(() => socket)
})

test('does not override network data if triggered twice', async () => {
const { store, runSaga } = await prepareStore({}, socket)

// Log all the dispatched actions in order
const actions: AnyAction[] = []
runSaga(function* (): Generator {
while (true) {
const action = yield* take()
actions.push(action.type)
}
})

renderComponent(<></>, store)

store.dispatch(communities.actions.customProtocol(validInvitationCodeTestData[0]))
await act(async () => {})

const originalPair = communities.selectors.invitationCodes(store.getState())

// Redo the action to provoke renewed saga runs
store.dispatch(communities.actions.customProtocol(validInvitationCodeTestData[1]))
await act(async () => {})

const currentPair = communities.selectors.invitationCodes(store.getState())

expect(originalPair).toEqual(currentPair)

expect(actions).toMatchInlineSnapshot(`
Array [
"Communities/customProtocol",
"Communities/createNetwork",
"Communities/setInvitationCodes",
"Communities/savePSK",
"Communities/addNewCommunity",
"Communities/setCurrentCommunity",
"Communities/customProtocol",
"Modals/openModal",
]
`)
})
})
10 changes: 7 additions & 3 deletions packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import { navigationActions } from '../../navigation/navigation.slice'
import { ScreenNames } from '../../../const/ScreenNames.enum'
import { deepLinkSaga } from './deepLink.saga'
import { type Community, CommunityOwnership, ConnectionProcessInfo, type Identity, InvitationData } from '@quiet/types'
import { composeInvitationShareUrl, validInvitationUrlTestData } from '@quiet/common'
import { composeInvitationShareUrl, validInvitationCodeTestData, getValidInvitationUrlTestData } from '@quiet/common'

describe('deepLinkSaga', () => {
let store: Store

const { code, data } = getValidInvitationUrlTestData(validInvitationCodeTestData[0])

const validCode = code()
const validData = data

const id = '00d045ab'
const validData: InvitationData = validInvitationUrlTestData.data
const validCode = validInvitationUrlTestData.code()

const community: Community = {
id,
name: '',
Expand Down
Loading

0 comments on commit de4dc66

Please sign in to comment.