From 8ba87a5e5027fdbbaf58b08e08195123f082b333 Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 3 Aug 2023 21:26:51 +0200 Subject: [PATCH 01/28] Implement utils for parsing and creating invitation code with multiple addresses --- .../src/nest/storage/storage.service.ts | 2 +- packages/common/src/invitationCode.ts | 69 +++++++- packages/desktop/src/main/invitation.ts | 7 +- packages/desktop/src/main/main.ts | 9 +- .../JoinCommunity/JoinCommunity.tsx | 6 +- .../PerformCommunityActionComponent.tsx | 26 ++- packages/desktop/src/renderer/index.tsx | 5 + .../handleInvitationCode.saga.test.ts | 158 +++++++++--------- .../invitation/handleInvitationCode.saga.ts | 39 ++--- .../JoinCommunity/JoinCommunity.component.tsx | 10 +- .../JoinCommunity/JoinCommunity.types.ts | 4 +- packages/state-manager/src/index.ts | 2 +- .../sagas/communities/communities.slice.ts | 10 +- .../createNetwork/createNetwork.saga.ts | 2 +- .../invitationCode/invitationCode.test.ts | 23 ++- .../invitationCode/invitationCode.ts | 65 +++++-- packages/types/src/community.ts | 3 +- packages/types/src/network.ts | 5 + 18 files changed, 287 insertions(+), 158 deletions(-) diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index d740373e64..7524b13bd3 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -171,7 +171,7 @@ export class StorageService extends EventEmitter { return } for (const a of addr) { - this.logger(`Pubsub - subscribe to ${addr}`) + this.logger(`Pubsub - subscribe to ${a}`) // @ts-ignore await this.orbitDb._pubsub.subscribe( a, diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index 6d17e38251..b43cb2053f 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -1,3 +1,4 @@ +import { InvitationPair } from '@quiet/types' import { InvitationParams, Site } from './static' export const retrieveInvitationCode = (url: string): string => { @@ -20,20 +21,78 @@ export const retrieveInvitationCode = (url: string): string => { return '' } -export const argvInvitationCode = (argv: string[]): string => { +export const retrieveInvitationCodePairs = (url: string): InvitationPair[] => { + /** + * Extract invitation code from deep url. + * Valid format: quiet://?=&= + */ + let data: URL + try { + data = new URL(url) + } catch (e) { + return [] + } + if (!data || data.protocol !== 'quiet:') return [] + const params = data.searchParams + const codes: InvitationPair[] = [] + for (const [peerId, address] of params) { + // TODO: basic check if peerid and address have proper format? + if (peerId.length !== 46 || address.length !== 56) { + console.log(`peerId '${peerId}' or address ${address} is not valid`) + continue + } + codes.push({ + peerId, + address, + }) + } + console.log('Retrieved codes:', codes) + return codes +} + +export const invitationShareUrlMultipleAddresses = (pairs: InvitationPair[] = []): string => { + // Valid format: https://tryquiet.org/join/#=&= + const code = pairs.map(pair => `${pair.peerId}=${pair.address}`).join('&') + const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${code}`) + return url.href +} + +export const invitationDeepUrlMultipleAddresses = (pairs: InvitationPair[] = []): string => { + const url = new URL('quiet://') + for (const pair of pairs) { + url.searchParams.append(pair.peerId, pair.address) + } + return url.href +} + +export const argvInvitationCode = (argv: string[]): InvitationPair[] => { /** * Extract invitation code from deep url if url is present in argv */ - let invitationCode = '' + let invitationCodes = [] for (const arg of argv) { - invitationCode = retrieveInvitationCode(arg) - if (invitationCode) { + invitationCodes = retrieveInvitationCodePairs(arg) + if (invitationCodes.length > 0) { break } } - return invitationCode + return invitationCodes } +// export const argvInvitationCode = (argv: string[]): string => { +// /** +// * Extract invitation code from deep url if url is present in argv +// */ +// let invitationCode = '' +// for (const arg of argv) { +// invitationCode = retrieveInvitationCode(arg) +// if (invitationCode) { +// break +// } +// } +// return invitationCode +// } + export const invitationDeepUrl = (code = ''): string => { const url = new URL('quiet://') url.searchParams.append(InvitationParams.CODE, code) diff --git a/packages/desktop/src/main/invitation.ts b/packages/desktop/src/main/invitation.ts index 23f61c847e..59ac09262c 100644 --- a/packages/desktop/src/main/invitation.ts +++ b/packages/desktop/src/main/invitation.ts @@ -3,11 +3,12 @@ import path from 'path' import os from 'os' import { execSync } from 'child_process' import { BrowserWindow } from 'electron' +import { InvitationPair } from '@quiet/types' -export const processInvitationCode = (mainWindow: BrowserWindow, code: string) => { - if (!code) return +export const processInvitationCode = (mainWindow: BrowserWindow, codes: InvitationPair[]) => { + if (codes.length === 0) return mainWindow.webContents.send('invitation', { - code, + codes, }) } diff --git a/packages/desktop/src/main/main.ts b/packages/desktop/src/main/main.ts index 932780c8e0..bbb35bf6ac 100644 --- a/packages/desktop/src/main/main.ts +++ b/packages/desktop/src/main/main.ts @@ -11,9 +11,8 @@ import { Crypto } from '@peculiar/webcrypto' import logger from './logger' import { DATA_DIR, DEV_DATA_DIR } from '../shared/static' import { fork, ChildProcess } from 'child_process' -import { getFilesData } from '@quiet/common' +import { argvInvitationCode, getFilesData, retrieveInvitationCodePairs } from '@quiet/common' import { updateDesktopFile, processInvitationCode } from './invitation' -import { argvInvitationCode, retrieveInvitationCode } from '@quiet/common' const ElectronStore = require('electron-store') ElectronStore.initRenderer() @@ -148,7 +147,7 @@ app.on('open-url', (event, url) => { event.preventDefault() if (mainWindow) { invitationUrl = null - const invitationCode = retrieveInvitationCode(url) + const invitationCode = retrieveInvitationCodePairs(url) processInvitationCode(mainWindow, invitationCode) } }) @@ -475,12 +474,12 @@ app.on('ready', async () => { throw new Error(`mainWindow is on unexpected type ${mainWindow}`) } if (process.platform === 'darwin' && invitationUrl) { - const invitationCode = retrieveInvitationCode(invitationUrl) + const invitationCode = retrieveInvitationCodePairs(invitationUrl) processInvitationCode(mainWindow, invitationCode) invitationUrl = null } if (process.platform !== 'darwin' && process.argv) { - const invitationCode = argvInvitationCode(process.argv) + const invitationCode = argvInvitationCodeMultipleAddresses(process.argv) processInvitationCode(mainWindow, invitationCode) } diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx index 38df07e800..9ed4991099 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { socketSelectors } from '../../../sagas/socket/socket.selectors' -import { CommunityOwnership, CreateNetworkPayload, TOR_BOOTSTRAP_COMPLETE } from '@quiet/types' +import { CommunityOwnership, CreateNetworkPayload, InvitationPair, TOR_BOOTSTRAP_COMPLETE } from '@quiet/types' import { communities, identity, connection } from '@quiet/state-manager' import PerformCommunityActionComponent from '../../../components/CreateJoinCommunity/PerformCommunityActionComponent' import { ModalName } from '../../../sagas/modals/modals.types' @@ -41,10 +41,10 @@ const JoinCommunity = () => { } }, [currentCommunity]) - const handleCommunityAction = (address: string) => { + const handleCommunityAction = (address: InvitationPair[]) => { const payload: CreateNetworkPayload = { ownership: CommunityOwnership.User, - registrar: address, + peers: address, } dispatch(communities.actions.createNetwork(payload)) } diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx index e0442790ae..1b7f20dc23 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx @@ -21,7 +21,7 @@ import { IconButton, InputAdornment } from '@mui/material' import VisibilityOff from '@mui/icons-material/VisibilityOff' import Visibility from '@mui/icons-material/Visibility' import { ONION_ADDRESS_REGEX, parseName } from '@quiet/common' -import { getInvitationCode } from '@quiet/state-manager' +import { getInvitationCodes } from '@quiet/state-manager' const PREFIX = 'PerformCommunityActionComponent' @@ -129,7 +129,7 @@ interface PerformCommunityActionFormValues { export interface PerformCommunityActionProps { open: boolean communityOwnership: CommunityOwnership - handleCommunityAction: (value: string) => void + handleCommunityAction: (value: any) => void handleRedirection: () => void handleClose: () => void isConnectionReady?: boolean @@ -178,22 +178,30 @@ export const PerformCommunityActionComponent: React.FC submitForm(handleCommunityAction, values, setFormSent) const submitForm = ( - handleSubmit: (value: string) => void, + handleSubmit: (value: any) => void, values: PerformCommunityActionFormValues, setFormSent: (value: boolean) => void ) => { - let submitValue = communityOwnership === CommunityOwnership.Owner ? parseName(values.name) : values.name.trim() + if (communityOwnership === CommunityOwnership.Owner) { + setFormSent(true) + handleSubmit(parseName(values.name)) + return + } + + // let submitValue = communityOwnership === CommunityOwnership.Owner ? parseName(values.name) : values.name.trim() if (communityOwnership === CommunityOwnership.User) { - submitValue = getInvitationCode(submitValue) - if (!submitValue || !submitValue.match(ONION_ADDRESS_REGEX)) { + const codes = getInvitationCodes(values.name.trim()) + if (!codes.length) { + // if (!submitValue || !submitValue.match(ONION_ADDRESS_REGEX)) { // TODO: add basic validation setError('name', { message: InviteLinkErrors.InvalidCode }) return + // } } - } - setFormSent(true) - handleSubmit(submitValue) + setFormSent(true) + handleSubmit(codes) + } } const onChange = (name: string) => { diff --git a/packages/desktop/src/renderer/index.tsx b/packages/desktop/src/renderer/index.tsx index a56c5f0931..bf35aea3bc 100644 --- a/packages/desktop/src/renderer/index.tsx +++ b/packages/desktop/src/renderer/index.tsx @@ -25,6 +25,11 @@ ipcRenderer.on('invitation', (_event, invitation) => { store.dispatch(communities.actions.handleInvitationCode(invitation.code)) }) +ipcRenderer.on('invitationMA', (_event, invitation) => { + console.log('invitation', invitation, 'dispatching action') + store.dispatch(communities.actions.handleInvitationCodes(invitation.codes)) +}) + const container = document.getElementById('root') if (!container) throw new Error('No root html element!') let root = createRoot(container) diff --git a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts index 470a0ae044..82cd8afd50 100644 --- a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts +++ b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts @@ -1,87 +1,87 @@ -import { communities, getFactory, Store } from '@quiet/state-manager' -import { Community, CommunityOwnership, CreateNetworkPayload } from '@quiet/types' -import { FactoryGirl } from 'factory-girl' -import { expectSaga } from 'redux-saga-test-plan' -import { handleInvitationCodeSaga } from './handleInvitationCode.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 { communities, getFactory, Store } from '@quiet/state-manager' +// import { Community, CommunityOwnership, CreateNetworkPayload } from '@quiet/types' +// import { FactoryGirl } from 'factory-girl' +// import { expectSaga } from 'redux-saga-test-plan' +// import { handleInvitationCodeSaga } from './handleInvitationCode.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' -describe('Handle invitation code', () => { - let store: Store - let factory: FactoryGirl - let community: Community - let validInvitationCode: string +// describe('Handle invitation code', () => { +// let store: Store +// let factory: FactoryGirl +// let community: Community +// let validInvitationCode: string - beforeEach(async () => { - store = ( - await prepareStore({ - [StoreKeys.Socket]: { - ...new SocketState(), - isConnected: true, - }, - }) - ).store +// beforeEach(async () => { +// store = ( +// await prepareStore({ +// [StoreKeys.Socket]: { +// ...new SocketState(), +// isConnected: true, +// }, +// }) +// ).store - factory = await getFactory(store) - validInvitationCode = 'bb5wacaftixjl3yhq2cp3ls2ife2e5wlwct3hjlb4lyk4iniypmgozyd' - }) +// factory = await getFactory(store) +// validInvitationCode = 'bb5wacaftixjl3yhq2cp3ls2ife2e5wlwct3hjlb4lyk4iniypmgozyd' +// }) - it('creates network if code is valid', async () => { - const payload: CreateNetworkPayload = { - ownership: CommunityOwnership.User, - registrar: validInvitationCode, - } - await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(validInvitationCode)) - .withState(store.getState()) - .put(communities.actions.createNetwork(payload)) - .run() - }) +// it('creates network if code is valid', async () => { +// const payload: CreateNetworkPayload = { +// ownership: CommunityOwnership.User, +// registrar: validInvitationCode, +// } +// await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(validInvitationCode)) +// .withState(store.getState()) +// .put(communities.actions.createNetwork(payload)) +// .run() +// }) - it('does not try to create network if user is already in community', async () => { - community = await factory.create['payload']>('Community') - const payload: CreateNetworkPayload = { - ownership: CommunityOwnership.User, - registrar: validInvitationCode, - } +// it('does not try to create network if user is already in community', async () => { +// community = await factory.create['payload']>('Community') +// const payload: CreateNetworkPayload = { +// ownership: CommunityOwnership.User, +// registrar: validInvitationCode, +// } - await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(validInvitationCode)) - .withState(store.getState()) - .put( - modalsActions.openModal({ - name: ModalName.warningModal, - args: { - title: 'You already belong to a community', - subtitle: "We're sorry but for now you can only be a member of a single community at a time.", - }, - }) - ) - .not.put(communities.actions.createNetwork(payload)) - .run() - }) +// await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(validInvitationCode)) +// .withState(store.getState()) +// .put( +// modalsActions.openModal({ +// name: ModalName.warningModal, +// args: { +// title: 'You already belong to a community', +// subtitle: "We're sorry but for now you can only be a member of a single community at a time.", +// }, +// }) +// ) +// .not.put(communities.actions.createNetwork(payload)) +// .run() +// }) - it('does not try to create network if code is invalid', async () => { - const code = 'invalid' - const payload: CreateNetworkPayload = { - ownership: CommunityOwnership.User, - registrar: code, - } +// it('does not try to create network if code is invalid', async () => { +// const code = 'invalid' +// const payload: CreateNetworkPayload = { +// ownership: CommunityOwnership.User, +// peers: code, +// } - await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(code)) - .withState(store.getState()) - .put(communities.actions.clearInvitationCode()) - .put( - modalsActions.openModal({ - name: ModalName.warningModal, - args: { - title: 'Invalid link', - subtitle: 'The invite link you received is not valid. Please check it and try again.', - }, - }) - ) - .not.put(communities.actions.createNetwork(payload)) - .run() - }) -}) +// await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(code)) +// .withState(store.getState()) +// .put(communities.actions.clearInvitationCode()) +// .put( +// modalsActions.openModal({ +// name: ModalName.warningModal, +// args: { +// title: 'Invalid link', +// subtitle: 'The invite link you received is not valid. Please check it and try again.', +// }, +// }) +// ) +// .not.put(communities.actions.createNetwork(payload)) +// .run() +// }) +// }) diff --git a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts index 5fab99fb8d..1a88cce5ca 100644 --- a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts +++ b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts @@ -8,7 +8,7 @@ import { ModalName } from '../modals/modals.types' import { modalsActions } from '../modals/modals.slice' export function* handleInvitationCodeSaga( - action: PayloadAction['payload']> + action: PayloadAction['payload']> ): Generator { while (true) { const connected = yield* select(socketSelectors.isConnected) @@ -32,26 +32,27 @@ export function* handleInvitationCodeSaga( return } - const code = action.payload.trim() + // const code = action.payload.trim() - if (code.match(ONION_ADDRESS_REGEX)) { - const payload: CreateNetworkPayload = { - ownership: CommunityOwnership.User, - registrar: code, - } - yield* put(communities.actions.createNetwork(payload)) - return + // if (code.match(ONION_ADDRESS_REGEX)) { + const payload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + peers: action.payload, } + yield* put(communities.actions.createNetwork(payload)) + return + // } - yield* put(communities.actions.clearInvitationCode()) + // TODO: handle invalid code + // yield* put(communities.actions.clearInvitationCode()) - yield* put( - modalsActions.openModal({ - name: ModalName.warningModal, - args: { - title: 'Invalid link', - subtitle: 'The invite link you received is not valid. Please check it and try again.', - }, - }) - ) + // yield* put( + // modalsActions.openModal({ + // name: ModalName.warningModal, + // args: { + // title: 'Invalid link', + // subtitle: 'The invite link you received is not valid. Please check it and try again.', + // }, + // }) + // ) } diff --git a/packages/mobile/src/components/JoinCommunity/JoinCommunity.component.tsx b/packages/mobile/src/components/JoinCommunity/JoinCommunity.component.tsx index 1f4b90c4aa..96dbf5f5fe 100644 --- a/packages/mobile/src/components/JoinCommunity/JoinCommunity.component.tsx +++ b/packages/mobile/src/components/JoinCommunity/JoinCommunity.component.tsx @@ -7,7 +7,7 @@ import { Typography } from '../Typography/Typography.component' import { TextWithLink } from '../TextWithLink/TextWithLink.component' import { JoinCommunityProps } from './JoinCommunity.types' -import { getInvitationCode } from '@quiet/state-manager' +import { getInvitationCodes } from '@quiet/state-manager' import { ONION_ADDRESS_REGEX } from '@quiet/common' export const JoinCommunity: FC = ({ @@ -32,16 +32,14 @@ export const JoinCommunity: FC = ({ Keyboard.dismiss() setLoading(true) - let submitValue: string | undefined = joinCommunityInput - - if (submitValue === undefined || submitValue?.length === 0) { + if (joinCommunityInput === undefined || joinCommunityInput?.length === 0) { setLoading(false) setInputError('Community address can not be empty') return } - submitValue = getInvitationCode(submitValue.trim()) - if (!submitValue || !submitValue.match(ONION_ADDRESS_REGEX)) { + const submitValue = getInvitationCodes(joinCommunityInput.trim()) + if (!submitValue?.length) { setLoading(false) setInputError('Please check your invitation code and try again') return diff --git a/packages/mobile/src/components/JoinCommunity/JoinCommunity.types.ts b/packages/mobile/src/components/JoinCommunity/JoinCommunity.types.ts index fb07d60ca6..3086a86790 100644 --- a/packages/mobile/src/components/JoinCommunity/JoinCommunity.types.ts +++ b/packages/mobile/src/components/JoinCommunity/JoinCommunity.types.ts @@ -1,5 +1,7 @@ +import { InvitationPair } from '@quiet/types' + export interface JoinCommunityProps { - joinCommunityAction: (address: string) => void + joinCommunityAction: (address: InvitationPair[]) => void redirectionAction: () => void networkCreated: boolean invitationCode?: string diff --git a/packages/state-manager/src/index.ts b/packages/state-manager/src/index.ts index 3f6b0da070..b247ed9833 100644 --- a/packages/state-manager/src/index.ts +++ b/packages/state-manager/src/index.ts @@ -83,7 +83,7 @@ export { formatBytes } from './utils/functions/formatBytes/formatBytes' export { sortPeers } from './utils/functions/sortPeers/sortPeers' -export { getInvitationCode } from './utils/functions/invitationCode/invitationCode' +export { getInvitationCodes } from './utils/functions/invitationCode/invitationCode' export type { Socket } from './types' diff --git a/packages/state-manager/src/sagas/communities/communities.slice.ts b/packages/state-manager/src/sagas/communities/communities.slice.ts index 41072e01d6..af67c8b8ab 100644 --- a/packages/state-manager/src/sagas/communities/communities.slice.ts +++ b/packages/state-manager/src/sagas/communities/communities.slice.ts @@ -2,6 +2,7 @@ import { createSlice, type EntityState, type PayloadAction } from '@reduxjs/tool import { StoreKeys } from '../store.keys' import { communitiesAdapter } from './communities.adapter' import { + InvitationPair, type AddOwnerCertificatePayload, type Community as CommunityType, type CreateNetworkPayload, @@ -14,6 +15,7 @@ import { export class CommunitiesState { public invitationCode: string | undefined = undefined + public invitationCodes: InvitationPair[] = [] public currentCommunity = '' public communities: EntityState = communitiesAdapter.getInitialState() } @@ -93,7 +95,13 @@ export const communitiesSlice = createSlice({ state.invitationCode = action.payload }, clearInvitationCode: state => { - state.invitationCode = undefined + state.invitationCode = '' + }, + handleInvitationCodes: (state, action: PayloadAction) => { + state.invitationCodes = action.payload + }, + clearInvitationCodes: state => { + state.invitationCodes = [] }, addOwnerCertificate: (state, action: PayloadAction) => { const { communityId, ownerCertificate } = action.payload diff --git a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts index 028efd328e..bb84e67e3e 100644 --- a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts +++ b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts @@ -29,7 +29,7 @@ export function* createNetworkSaga( const id = yield* call(generateId) - const registrarUrl = action.payload.registrar ? `http://${action.payload.registrar}.onion` : undefined + // const registrarUrl = action.payload.registrar ? `http://${action.payload.registrar}.onion` : undefined const payload: Community = { id, diff --git a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts index 31c99bf1e5..8acc98f561 100644 --- a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts +++ b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts @@ -1,14 +1,25 @@ -import { getInvitationCode } from './invitationCode' +import { getInvitationCodes } from './invitationCode' import { Site } from '@quiet/common' describe('Invitation code helper', () => { it('retrieves invitation code if url is a proper share url', () => { - const result = getInvitationCode(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#validCode`) - expect(result).toEqual('validCode') + const result = getInvitationCodes(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#peerId1=address1&peerId2=address2`) + expect(result).toEqual([ + { peerId: 'peerId1', address: 'address1' }, + { peerId: 'peerId2', address: 'address2' }, + ]) }) - it('returns passed value if url is not a proper share url', () => { - const result = getInvitationCode('validCode') - expect(result).toEqual('validCode') + it('returns empty list if code is not a proper share url nor a code', () => { + const result = getInvitationCodes('invalidCode') + expect(result).toEqual([]) + }) + + it('retrieves invitation code if url is a proper code', () => { + const result = getInvitationCodes(`peerId1=address1&peerId2=address2`) + expect(result).toEqual([ + { peerId: 'peerId1', address: 'address1' }, + { peerId: 'peerId2', address: 'address2' }, + ]) }) }) diff --git a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts index e2abc314cb..cd85cedd48 100644 --- a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts +++ b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts @@ -1,37 +1,68 @@ import { Site } from '@quiet/common' +import { InvitationPair } from '@quiet/types' -export const getInvitationCode = (codeOrUrl: string): string => { +const getInvitationPairs = (code: string) => { + const pairs = code.split('&') + const codes: InvitationPair[] = [] + for (const pair of pairs) { + const [peerId, address] = pair.split('=') + if (!peerId || !address) continue + codes.push({ + peerId: peerId, + address: address, + }) + } + return codes +} + +export const getInvitationCodes = (codeOrUrl: string): InvitationPair[] => { /** - * Extract code from invitation share url or return passed value for further validation + * Extract codes from invitation share url or return passed value for further validation */ - let code = '' + let codes: InvitationPair[] = [] + let potentialCode let validUrl: URL | null = null try { validUrl = new URL(codeOrUrl) } catch (e) { - code = codeOrUrl + // It may be just code, not URL + potentialCode = codeOrUrl } + if (validUrl && validUrl.host === Site.DOMAIN && validUrl.pathname.includes(Site.JOIN_PAGE)) { const hash = validUrl.hash + // const params = validUrl.searchParams + // TODO: I don't think handling params is needed here as we only accept url with '#' and code without url - let invitationCode: string = hash.substring(1) + // if (params) { + // // Type 'URLSearchParams' must have a '[Symbol.iterator]()' method that returns an iterator + // for (const [peerId, address] of params) { + // // TODO: basic check if peerid and address have proper format? + // if (peerId.length !== 46 || address.length !== 56) { + // console.log(`peerId '${peerId}' or address ${address} is not valid`) + // continue + // } + // codes.push({ + // peerId, + // address, + // }) + // } + // } - // Ensure backward compatibility - if (hash.includes('code=')) { - // Mix of old and new link - invitationCode = hash.substring(6) - } else if (validUrl.searchParams.has('code')) { - // Old link - invitationCode = validUrl.searchParams.get('code') || '' + if (hash) { + // Parse hash + const pairs = hash.substring(1) + codes = getInvitationPairs(pairs) } - - code = invitationCode + } else if (potentialCode) { + // Parse code just as hash value + codes = getInvitationPairs(potentialCode) } - if (!code) { - console.warn(`No invitation code. Code/url passed: ${codeOrUrl}`) + if (codes.length === 0) { + console.warn(`No invitation codes. Code/url passed: ${codeOrUrl}`) } - return code + return codes } diff --git a/packages/types/src/community.ts b/packages/types/src/community.ts index ee7c0467a2..0f2077e5c5 100644 --- a/packages/types/src/community.ts +++ b/packages/types/src/community.ts @@ -1,4 +1,5 @@ import { type HiddenService, type PeerId, type Identity } from './identity' +import { InvitationPair } from './network' export interface Community { id: string @@ -34,7 +35,7 @@ export interface NetworkData { export interface CreateNetworkPayload { ownership: CommunityOwnership name?: string - registrar?: string + peers?: InvitationPair[] } export interface ResponseCreateNetworkPayload { diff --git a/packages/types/src/network.ts b/packages/types/src/network.ts index 7795ea5b5f..beb1058ac9 100644 --- a/packages/types/src/network.ts +++ b/packages/types/src/network.ts @@ -2,3 +2,8 @@ export enum LoadingPanelType { StartingApplication = 'Starting Quiet', Joining = 'Connecting to peers', } + +export type InvitationPair = { + peerId: string + address: string +} From 7510cab527330ae1ee11258e502643c347c9f563 Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 10 Aug 2023 11:13:39 +0200 Subject: [PATCH 02/28] Adjust code to multiple addresses --- packages/common/package-lock.json | 298 +++++++++++++++++- packages/common/package.json | 1 + packages/common/src/invitationCode.test.ts | 28 +- packages/common/src/invitationCode.ts | 91 ++++-- packages/common/tsconfig.build.json | 1 + packages/common/tsconfig.json | 2 +- packages/desktop/src/main/main.test.ts | 7 +- packages/desktop/src/main/main.ts | 8 +- packages/desktop/src/renderer/index.tsx | 10 +- .../communities/communities.selectors.test.ts | 52 +-- .../communities/communities.selectors.ts | 8 +- .../createNetwork/createNetwork.saga.test.ts | 2 +- .../createNetwork/createNetwork.saga.ts | 2 +- 13 files changed, 429 insertions(+), 81 deletions(-) diff --git a/packages/common/package-lock.json b/packages/common/package-lock.json index c02a9138ae..650f4c3902 100644 --- a/packages/common/package-lock.json +++ b/packages/common/package-lock.json @@ -10,7 +10,8 @@ "license": "ISC", "dependencies": { "cross-env": "^5.2.0", - "debug": "^4.3.1" + "debug": "^4.3.1", + "multiaddr": "^10.0.1" }, "devDependencies": { "@types/jest": "^26.0.23", @@ -4052,6 +4053,178 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/multiaddr": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.1.tgz", + "integrity": "sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg==", + "deprecated": "This module is deprecated, please upgrade to @multiformats/multiaddr", + "dependencies": { + "dns-over-http-resolver": "^1.2.3", + "err-code": "^3.0.1", + "is-ip": "^3.1.0", + "multiformats": "^9.4.5", + "uint8arrays": "^3.0.0", + "varint": "^6.0.0" + } + }, + "node_modules/multiaddr/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/multiaddr/node_modules/dns-over-http-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz", + "integrity": "sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==", + "dependencies": { + "debug": "^4.3.1", + "native-fetch": "^3.0.0", + "receptacle": "^1.3.2" + } + }, + "node_modules/multiaddr/node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "node_modules/multiaddr/node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "peer": true, + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/multiaddr/node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "peer": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/multiaddr/node_modules/ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/multiaddr/node_modules/is-ip": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", + "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", + "dependencies": { + "ip-regex": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/multiaddr/node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "node_modules/multiaddr/node_modules/native-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-3.0.0.tgz", + "integrity": "sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==", + "peerDependencies": { + "node-fetch": "*" + } + }, + "node_modules/multiaddr/node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "peer": true, + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/multiaddr/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "peer": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/multiaddr/node_modules/receptacle": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", + "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/multiaddr/node_modules/uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "dependencies": { + "multiformats": "^9.4.2" + } + }, + "node_modules/multiaddr/node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" + }, + "node_modules/multiaddr/node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "peer": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -9351,6 +9524,129 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "multiaddr": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.1.tgz", + "integrity": "sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg==", + "requires": { + "dns-over-http-resolver": "^1.2.3", + "err-code": "^3.0.1", + "is-ip": "^3.1.0", + "multiformats": "^9.4.5", + "uint8arrays": "^3.0.0", + "varint": "^6.0.0" + }, + "dependencies": { + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "peer": true + }, + "dns-over-http-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz", + "integrity": "sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==", + "requires": { + "debug": "^4.3.1", + "native-fetch": "^3.0.0", + "receptacle": "^1.3.2" + } + }, + "err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "peer": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "peer": true, + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==" + }, + "is-ip": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", + "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", + "requires": { + "ip-regex": "^4.0.0" + } + }, + "multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "native-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-3.0.0.tgz", + "integrity": "sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==", + "requires": {} + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "peer": true + }, + "node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "peer": true, + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "receptacle": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", + "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", + "requires": { + "ms": "^2.1.1" + } + }, + "uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "requires": { + "multiformats": "^9.4.2" + } + }, + "varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" + }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "peer": true + } + } + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", diff --git a/packages/common/package.json b/packages/common/package.json index d320789a04..5818f4b888 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -26,6 +26,7 @@ }, "dependencies": { "@quiet/types": "^1.6.0", + "multiaddr": "^10.0.1", "cross-env": "^5.2.0", "debug": "^4.3.1" }, diff --git a/packages/common/src/invitationCode.test.ts b/packages/common/src/invitationCode.test.ts index 78bd1420c1..1f49410df5 100644 --- a/packages/common/src/invitationCode.test.ts +++ b/packages/common/src/invitationCode.test.ts @@ -3,22 +3,42 @@ import { Site } from './static' describe('Invitation code helper', () => { it('retrieves invitation code from argv', () => { + const expectedCodes = [ + { peerId: 'peerID1', address: 'address1' }, + { peerId: 'peerID2', address: 'address2' }, + ] const result = argvInvitationCode([ 'something', 'quiet:/invalid', 'zbay://invalid', 'quiet://invalid', 'quiet://?param=invalid', - invitationDeepUrl('validCode'), + invitationDeepUrl(expectedCodes), ]) - expect(result).toBe('validCode') + expect(result).toBe(expectedCodes) }) it('builds proper invitation deep url', () => { - expect(invitationDeepUrl('validCode')).toEqual('quiet://?code=validCode') + expect( + invitationDeepUrl([ + { peerId: 'peerID1', address: 'address1' }, + { peerId: 'peerID2', address: 'address2' }, + ]) + ).toEqual('quiet://?peerID1=address1&peerID2=address2') }) + // it('builds proper invitation share url', () => { + // expect(invitationShareUrl('validCode')).toEqual(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#validCode`) + // }) + it('builds proper invitation share url', () => { - expect(invitationShareUrl('validCode')).toEqual(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#validCode`) + const peerList = [ + '/dns4/gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad.onion/tcp/443/wss/p2p/QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + 'invalidAddress', + '/dns4/somethingElse.onion/tcp/443/wss/p2p/QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA', + ] + expect(invitationShareUrl(peerList)).toEqual( + `https://${Site.DOMAIN}/${Site.JOIN_PAGE}#QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad&QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA=somethingElse` + ) }) }) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index b43cb2053f..b3b83b53e6 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -1,27 +1,28 @@ import { InvitationPair } from '@quiet/types' import { InvitationParams, Site } from './static' +import { multiaddr } from 'multiaddr' -export const retrieveInvitationCode = (url: string): string => { - /** - * Extract invitation code from deep url. - * Valid format: quiet://?code= - */ - let data: URL - try { - data = new URL(url) - } catch (e) { - return '' - } - if (!data || data.protocol !== 'quiet:') return '' - const code = data.searchParams.get(InvitationParams.CODE) - if (code) { - console.log('Retrieved code:', code) - return code - } - return '' -} +// export const retrieveInvitationCode = (url: string): string => { +// /** +// * Extract invitation code from deep url. +// * Valid format: quiet://?code= +// */ +// let data: URL +// try { +// data = new URL(url) +// } catch (e) { +// return '' +// } +// if (!data || data.protocol !== 'quiet:') return '' +// const code = data.searchParams.get(InvitationParams.CODE) +// if (code) { +// console.log('Retrieved code:', code) +// return code +// } +// return '' +// } -export const retrieveInvitationCodePairs = (url: string): InvitationPair[] => { +export const retrieveInvitationCode = (url: string): InvitationPair[] => { /** * Extract invitation code from deep url. * Valid format: quiet://?=&= @@ -50,14 +51,34 @@ export const retrieveInvitationCodePairs = (url: string): InvitationPair[] => { return codes } -export const invitationShareUrlMultipleAddresses = (pairs: InvitationPair[] = []): string => { +export const invitationShareUrl = (peers: string[] = []): string => { // Valid format: https://tryquiet.org/join/#=&= - const code = pairs.map(pair => `${pair.peerId}=${pair.address}`).join('&') - const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${code}`) + const pairs = [] + for (const peerAddress of peers) { + let addr + try { + addr = multiaddr(peerAddress) + } catch (e) { + console.error(`Could not add peer address '${peerAddress}' to invitation url. Reason: ${e.message}`) + continue + } + + const peerId = addr.getPeerId() + const address: string = addr.nodeAddress().address + if (!peerId || !address) { + console.error('NO PEER ID OR ADDRESS IN', peerAddress) + continue + } + const rawAddress = address.endsWith('.onion') ? address.split('.')[0] : address + pairs.push(`${peerId}=${rawAddress}`) + } + + console.log('CODE', pairs.join('&')) + const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${pairs.join('&')}`) return url.href } -export const invitationDeepUrlMultipleAddresses = (pairs: InvitationPair[] = []): string => { +export const invitationDeepUrl = (pairs: InvitationPair[] = []): string => { const url = new URL('quiet://') for (const pair of pairs) { url.searchParams.append(pair.peerId, pair.address) @@ -67,11 +88,11 @@ export const invitationDeepUrlMultipleAddresses = (pairs: InvitationPair[] = []) export const argvInvitationCode = (argv: string[]): InvitationPair[] => { /** - * Extract invitation code from deep url if url is present in argv + * Extract invitation codes from deep url if url is present in argv */ let invitationCodes = [] for (const arg of argv) { - invitationCodes = retrieveInvitationCodePairs(arg) + invitationCodes = retrieveInvitationCode(arg) if (invitationCodes.length > 0) { break } @@ -93,13 +114,13 @@ export const argvInvitationCode = (argv: string[]): InvitationPair[] => { // return invitationCode // } -export const invitationDeepUrl = (code = ''): string => { - const url = new URL('quiet://') - url.searchParams.append(InvitationParams.CODE, code) - return url.href -} +// export const invitationDeepUrl = (code = ''): string => { +// const url = new URL('quiet://') +// url.searchParams.append(InvitationParams.CODE, code) +// return url.href +// } -export const invitationShareUrl = (code = ''): string => { - const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${code}`) - return url.href -} +// export const invitationShareUrl = (code = ''): string => { +// const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${code}`) +// return url.href +// } diff --git a/packages/common/tsconfig.build.json b/packages/common/tsconfig.build.json index 4c2fe1bc29..b889234c8b 100644 --- a/packages/common/tsconfig.build.json +++ b/packages/common/tsconfig.build.json @@ -1,6 +1,7 @@ { "extends": "../../tsconfig.build.json", "compilerOptions": { + "target": "ES2020", "rootDir": "./src", "outDir": "./lib", "typeRoots": [ diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json index afd02831cc..6adb0ef8de 100644 --- a/packages/common/tsconfig.json +++ b/packages/common/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "target": "es2017", + "target": "ES2020", "outDir": "./lib", "typeRoots": [ "../@types", diff --git a/packages/desktop/src/main/main.test.ts b/packages/desktop/src/main/main.test.ts index faa8e913fc..ad6203d06c 100644 --- a/packages/desktop/src/main/main.test.ts +++ b/packages/desktop/src/main/main.test.ts @@ -243,14 +243,17 @@ describe('Invitation code', () => { const code = 'invitationCode' expect(mockAppOnCalls[1][0]).toBe('open-url') const event = { preventDefault: () => {} } - mockAppOnCalls[1][1](event, invitationDeepUrl(code)) + mockAppOnCalls[1][1](event, invitationDeepUrl([{ peerId: 'peerId1', address: 'address' }])) expect(mockWindowWebContentsSend).toHaveBeenCalledWith('invitation', { code: code }) }) it('process invitation code on second-instance event', async () => { const code = 'invitationCodeArgv' await mockAppOnCalls[2][1]() - const commandLine = ['/tmp/.mount_Quiet-TVQc6s/quiet', invitationDeepUrl(code)] + const commandLine = [ + '/tmp/.mount_Quiet-TVQc6s/quiet', + invitationDeepUrl([{ peerId: 'peerId1', address: 'address' }]), + ] expect(mockAppOnCalls[0][0]).toBe('second-instance') const event = { preventDefault: () => {} } mockAppOnCalls[0][1](event, commandLine) diff --git a/packages/desktop/src/main/main.ts b/packages/desktop/src/main/main.ts index bbb35bf6ac..b8c20310f4 100644 --- a/packages/desktop/src/main/main.ts +++ b/packages/desktop/src/main/main.ts @@ -11,7 +11,7 @@ import { Crypto } from '@peculiar/webcrypto' import logger from './logger' import { DATA_DIR, DEV_DATA_DIR } from '../shared/static' import { fork, ChildProcess } from 'child_process' -import { argvInvitationCode, getFilesData, retrieveInvitationCodePairs } from '@quiet/common' +import { argvInvitationCode, getFilesData, retrieveInvitationCode } from '@quiet/common' import { updateDesktopFile, processInvitationCode } from './invitation' const ElectronStore = require('electron-store') ElectronStore.initRenderer() @@ -147,7 +147,7 @@ app.on('open-url', (event, url) => { event.preventDefault() if (mainWindow) { invitationUrl = null - const invitationCode = retrieveInvitationCodePairs(url) + const invitationCode = retrieveInvitationCode(url) processInvitationCode(mainWindow, invitationCode) } }) @@ -474,12 +474,12 @@ app.on('ready', async () => { throw new Error(`mainWindow is on unexpected type ${mainWindow}`) } if (process.platform === 'darwin' && invitationUrl) { - const invitationCode = retrieveInvitationCodePairs(invitationUrl) + const invitationCode = retrieveInvitationCode(invitationUrl) processInvitationCode(mainWindow, invitationCode) invitationUrl = null } if (process.platform !== 'darwin' && process.argv) { - const invitationCode = argvInvitationCodeMultipleAddresses(process.argv) + const invitationCode = argvInvitationCode(process.argv) processInvitationCode(mainWindow, invitationCode) } diff --git a/packages/desktop/src/renderer/index.tsx b/packages/desktop/src/renderer/index.tsx index bf35aea3bc..02942c0c46 100644 --- a/packages/desktop/src/renderer/index.tsx +++ b/packages/desktop/src/renderer/index.tsx @@ -21,15 +21,15 @@ ipcRenderer.on('force-save-state', async _event => { }) ipcRenderer.on('invitation', (_event, invitation) => { - console.log('invitation', invitation, 'dispatching action') - store.dispatch(communities.actions.handleInvitationCode(invitation.code)) -}) - -ipcRenderer.on('invitationMA', (_event, invitation) => { console.log('invitation', invitation, 'dispatching action') store.dispatch(communities.actions.handleInvitationCodes(invitation.codes)) }) +// ipcRenderer.on('invitationMA', (_event, invitation) => { +// console.log('invitation', invitation, 'dispatching action') +// store.dispatch(communities.actions.handleInvitationCodes(invitation.codes)) +// }) + const container = document.getElementById('root') if (!container) throw new Error('No root html element!') let root = createRoot(container) diff --git a/packages/state-manager/src/sagas/communities/communities.selectors.test.ts b/packages/state-manager/src/sagas/communities/communities.selectors.test.ts index c77232b733..2a582a3c32 100644 --- a/packages/state-manager/src/sagas/communities/communities.selectors.test.ts +++ b/packages/state-manager/src/sagas/communities/communities.selectors.test.ts @@ -97,32 +97,32 @@ describe('communitiesSelectors', () => { expect(invitationUrl).toEqual('') }) - it('returns proper invitation url if registrationUrl is in old format', async () => { - const code = 'aznu6kiyutsgjhdue4i4xushjzey6boxf4i4isd53admsibvbt6qyiyd' - const registrarUrl = `http://${code}` - const { store } = prepareStore() - const factory = await getFactory(store) - await factory.create['payload']>('Community', { - registrarUrl, - port: 0, - onionAddress: '', - }) - const invitationUrl = communitiesSelectors.invitationUrl(store.getState()) - expect(invitationUrl).toEqual(invitationShareUrl(code)) - }) - - it('returns proper invitation url if registrationUrl is just onion address', async () => { - const code = 'aznu6kiyutsgjhdue4i4xushjzey6boxf4i4isd53admsibvbt6qyiyd' - const { store } = prepareStore() - const factory = await getFactory(store) - await factory.create['payload']>('Community', { - registrarUrl: code, - port: 0, - onionAddress: '', - }) - const invitationUrl = communitiesSelectors.invitationUrl(store.getState()) - expect(invitationUrl).toEqual(invitationShareUrl(code)) - }) + // it('returns proper invitation url if registrationUrl is in old format', async () => { + // const code = 'aznu6kiyutsgjhdue4i4xushjzey6boxf4i4isd53admsibvbt6qyiyd' + // const registrarUrl = `http://${code}` + // const { store } = prepareStore() + // const factory = await getFactory(store) + // await factory.create['payload']>('Community', { + // registrarUrl, + // port: 0, + // onionAddress: '', + // }) + // const invitationUrl = communitiesSelectors.invitationUrl(store.getState()) + // expect(invitationUrl).toEqual(invitationShareUrl(code)) + // }) + + // it('returns proper invitation url if registrationUrl is just onion address', async () => { + // const code = 'aznu6kiyutsgjhdue4i4xushjzey6boxf4i4isd53admsibvbt6qyiyd' + // const { store } = prepareStore() + // const factory = await getFactory(store) + // await factory.create['payload']>('Community', { + // registrarUrl: code, + // port: 0, + // onionAddress: '', + // }) + // const invitationUrl = communitiesSelectors.invitationUrl(store.getState()) + // expect(invitationUrl).toEqual(invitationShareUrl(code)) + // }) it('returns proper ownerNickname - ownerCertificate exist', async () => { const { store } = prepareStore() diff --git a/packages/state-manager/src/sagas/communities/communities.selectors.ts b/packages/state-manager/src/sagas/communities/communities.selectors.ts index 4a1d44c232..8e2e3c0e4c 100644 --- a/packages/state-manager/src/sagas/communities/communities.selectors.ts +++ b/packages/state-manager/src/sagas/communities/communities.selectors.ts @@ -58,6 +58,12 @@ export const invitationCode = createSelector(communitiesSlice, reducerState => { }) export const invitationUrl = createSelector(currentCommunity, community => { + const peerList = community?.peerList + if (!peerList || peerList?.length === 0) return + const initialPeers = peerList.slice(0, 4) + + console.log('invitationUrl INITIAL PEERS', initialPeers) + if (!community?.registrarUrl) return '' let registrarUrl = '' try { @@ -66,7 +72,7 @@ export const invitationUrl = createSelector(currentCommunity, community => { } catch (e) { registrarUrl = community.registrarUrl } - return invitationShareUrl(registrarUrl) + return invitationShareUrl(initialPeers) }) export const registrationAttempts = (communityId: string) => diff --git a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts index 551daff58e..c23dd92a7f 100644 --- a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts +++ b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts @@ -28,7 +28,7 @@ describe('createNetwork', () => { createNetworkSaga, communitiesActions.createNetwork({ ownership: CommunityOwnership.User, - registrar: 'registrarUrl', + peers: [{ peerId: 'peerId', address: 'address' }], }) ) .withReducer(reducer) diff --git a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts index bb84e67e3e..1fa5b13771 100644 --- a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts +++ b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts @@ -34,7 +34,7 @@ export function* createNetworkSaga( const payload: Community = { id, name: action.payload.name, - registrarUrl, + // registrarUrl, CA, rootCa: CA?.rootCertString, } From 525383acb4c9e5efcc12fc7872c34bef5e821529 Mon Sep 17 00:00:00 2001 From: Emi Date: Fri, 11 Aug 2023 16:31:21 +0200 Subject: [PATCH 03/28] Adjust code to display multiple addresses in invitation url tsconfig - change target to es2020, add dom.iterable to lib options --- packages/common/src/invitationCode.ts | 6 +- .../invitation/handleInvitationCode.saga.ts | 1 - packages/desktop/tsconfig.json | 1 + packages/logger/tsconfig.json | 2 +- .../menus/InvitationContextMenu.container.tsx | 2 +- .../JoinCommunity/JoinCommunity.screen.tsx | 6 +- .../store/init/deepLink/deepLink.saga.test.ts | 436 +++++++++--------- .../src/store/init/deepLink/deepLink.saga.ts | 19 +- .../communities/communities.selectors.ts | 18 +- tsconfig.build.json | 5 +- tsconfig.json | 7 +- 11 files changed, 253 insertions(+), 250 deletions(-) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index b3b83b53e6..8ed1a54b2a 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -24,7 +24,7 @@ import { multiaddr } from 'multiaddr' export const retrieveInvitationCode = (url: string): InvitationPair[] => { /** - * Extract invitation code from deep url. + * Extract invitation codes from deep url. * Valid format: quiet://?=&= */ let data: URL @@ -36,7 +36,7 @@ export const retrieveInvitationCode = (url: string): InvitationPair[] => { if (!data || data.protocol !== 'quiet:') return [] const params = data.searchParams const codes: InvitationPair[] = [] - for (const [peerId, address] of params) { + for (const [peerId, address] of params.entries()) { // TODO: basic check if peerid and address have proper format? if (peerId.length !== 46 || address.length !== 56) { console.log(`peerId '${peerId}' or address ${address} is not valid`) @@ -90,7 +90,7 @@ export const argvInvitationCode = (argv: string[]): InvitationPair[] => { /** * Extract invitation codes from deep url if url is present in argv */ - let invitationCodes = [] + let invitationCodes: InvitationPair[] = [] for (const arg of argv) { invitationCodes = retrieveInvitationCode(arg) if (invitationCodes.length > 0) { diff --git a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts index 1a88cce5ca..d2bd74f864 100644 --- a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts +++ b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts @@ -3,7 +3,6 @@ import { select, put, delay } from 'typed-redux-saga' import { CommunityOwnership, CreateNetworkPayload } from '@quiet/types' import { communities } from '@quiet/state-manager' import { socketSelectors } from '../socket/socket.selectors' -import { ONION_ADDRESS_REGEX } from '@quiet/common' import { ModalName } from '../modals/modals.types' import { modalsActions } from '../modals/modals.slice' diff --git a/packages/desktop/tsconfig.json b/packages/desktop/tsconfig.json index 7a5f655f77..0186a73548 100644 --- a/packages/desktop/tsconfig.json +++ b/packages/desktop/tsconfig.json @@ -10,6 +10,7 @@ "allowJs": true, "lib": [ "ES2020", + "DOM.Iterable", "dom" ], "typeRoots": [ diff --git a/packages/logger/tsconfig.json b/packages/logger/tsconfig.json index afd02831cc..6adb0ef8de 100644 --- a/packages/logger/tsconfig.json +++ b/packages/logger/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "target": "es2017", + "target": "ES2020", "outDir": "./lib", "typeRoots": [ "../@types", diff --git a/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx b/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx index f28feff2da..19b5398145 100644 --- a/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx +++ b/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx @@ -22,7 +22,7 @@ export const InvitationContextMenu: FC = () => { const screen = useSelector(navigationSelectors.currentScreen) - const community = useSelector(communities.selectors.currentCommunity) + // const community = useSelector(communities.selectors.currentCommunity) const invitationLink = useSelector(communities.selectors.invitationUrl) const invitationContextMenu = useContextMenu(MenuName.Invitation) diff --git a/packages/mobile/src/screens/JoinCommunity/JoinCommunity.screen.tsx b/packages/mobile/src/screens/JoinCommunity/JoinCommunity.screen.tsx index 2cf924a853..b73ef07e52 100644 --- a/packages/mobile/src/screens/JoinCommunity/JoinCommunity.screen.tsx +++ b/packages/mobile/src/screens/JoinCommunity/JoinCommunity.screen.tsx @@ -2,7 +2,7 @@ import React, { FC, useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { identity, communities } from '@quiet/state-manager' -import { CommunityOwnership, CreateNetworkPayload } from '@quiet/types' +import { CommunityOwnership, CreateNetworkPayload, InvitationPair } from '@quiet/types' import { JoinCommunity } from '../../components/JoinCommunity/JoinCommunity.component' import { navigationActions } from '../../store/navigation/navigation.slice' import { ScreenNames } from '../../const/ScreenNames.enum' @@ -35,10 +35,10 @@ export const JoinCommunityScreen: FC = ({ route }) => }, [dispatch, community, route.params?.code]) const joinCommunityAction = useCallback( - (address: string) => { + (pairs: InvitationPair[]) => { const payload: CreateNetworkPayload = { ownership: CommunityOwnership.User, - registrar: address, + peers: pairs, } dispatch(communities.actions.createNetwork(payload)) dispatch( diff --git a/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts b/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts index a2fb46277e..366c83c1f7 100644 --- a/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts +++ b/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts @@ -1,218 +1,218 @@ -import { expectSaga } from 'redux-saga-test-plan' -import { combineReducers } from '@reduxjs/toolkit' -import { reducers } from '../../root.reducer' -import { Store } from '../../store.types' -import { prepareStore } from '../../../tests/utils/prepareStore' -import { communities, Community, connection, identity } from '@quiet/state-manager' -import { initActions } from '../init.slice' -import { navigationActions } from '../../navigation/navigation.slice' -import { ScreenNames } from '../../../const/ScreenNames.enum' -import { deepLinkSaga } from './deepLink.saga' -import { CommunityOwnership, ConnectionProcessInfo, Identity } from '@quiet/types' - -describe('deepLinkSaga', () => { - let store: Store - - const id = '00d045ab' - - const community: Community = { - id, - name: '', - CA: { - rootCertString: '', - rootKeyString: '', - }, - rootCa: '', - peerList: [], - registrar: { - privateKey: '', - address: '', - }, - registrarUrl: 'https://bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd.onion', - onionAddress: '', - privateKey: '', - port: 0, - registrationAttempts: 0, - ownerCertificate: '', - } - - const _identity: Partial = { - id, - nickname: '', - userCsr: null, - userCertificate: null, - joinTimestamp: 0, - } - - beforeEach(async () => { - store = (await prepareStore()).store - }) - - test('joins community', async () => { - store.dispatch( - initActions.setWebsocketConnected({ - dataPort: 5001, - }) - ) - - const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - - const reducer = combineReducers(reducers) - await expectSaga(deepLinkSaga, initActions.deepLink(code)) - .withReducer(reducer) - .withState(store.getState()) - .put( - navigationActions.replaceScreen({ - screen: ScreenNames.JoinCommunityScreen, - params: { - code, - }, - }) - ) - .put( - communities.actions.createNetwork({ - ownership: CommunityOwnership.User, - registrar: code, - }) - ) - .run() - }) - - test('opens channel list screen if the same url has been used', async () => { - store.dispatch( - initActions.setWebsocketConnected({ - dataPort: 5001, - }) - ) - - store.dispatch(communities.actions.addNewCommunity(community)) - - store.dispatch( - // @ts-expect-error - identity.actions.addNewIdentity({ ..._identity, userCertificate: 'certificate' }) - ) - - store.dispatch(communities.actions.setCurrentCommunity(community.id)) - - const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - - const reducer = combineReducers(reducers) - await expectSaga(deepLinkSaga, initActions.deepLink(code)) - .withReducer(reducer) - .withState(store.getState()) - .put( - navigationActions.replaceScreen({ - screen: ScreenNames.ChannelListScreen, - }) - ) - .not.put( - communities.actions.createNetwork({ - ownership: CommunityOwnership.User, - registrar: code, - }) - ) - .run() - }) - - test('displays error if user already belongs to a community', async () => { - store.dispatch( - initActions.setWebsocketConnected({ - dataPort: 5001, - }) - ) - - store.dispatch(communities.actions.addNewCommunity(community)) - - store.dispatch(communities.actions.setCurrentCommunity(community.id)) - - const code = 'ctbebt3ixybtu4ty2dr3ychjtxpkhuun4neuavkjjhplgzfde5vgelad' - - const reducer = combineReducers(reducers) - await expectSaga(deepLinkSaga, initActions.deepLink(code)) - .withReducer(reducer) - .withState(store.getState()) - .not.put( - communities.actions.createNetwork({ - ownership: CommunityOwnership.User, - registrar: code, - }) - ) - .run() - }) - - test('continues if link used mid registration', async () => { - store.dispatch( - initActions.setWebsocketConnected({ - dataPort: 5001, - }) - ) - - store.dispatch(communities.actions.addNewCommunity(community)) - - store.dispatch( - // @ts-expect-error - identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) - ) - - store.dispatch(communities.actions.setCurrentCommunity(community.id)) - - const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - - const reducer = combineReducers(reducers) - await expectSaga(deepLinkSaga, initActions.deepLink(code)) - .withReducer(reducer) - .withState(store.getState()) - .put( - navigationActions.replaceScreen({ - screen: ScreenNames.UsernameRegistrationScreen, - params: undefined, - }) - ) - .not.put( - communities.actions.createNetwork({ - ownership: CommunityOwnership.User, - registrar: code, - }) - ) - .run() - }) - - test('continues if link used mid registration and locks input while waiting for server response', async () => { - store.dispatch( - initActions.setWebsocketConnected({ - dataPort: 5001, - }) - ) - - store.dispatch(communities.actions.addNewCommunity(community)) - - store.dispatch( - // @ts-expect-error - identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) - ) - - store.dispatch(communities.actions.setCurrentCommunity(community.id)) - - store.dispatch(connection.actions.setTorConnectionProcess(ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE)) - - const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - - const reducer = combineReducers(reducers) - await expectSaga(deepLinkSaga, initActions.deepLink(code)) - .withReducer(reducer) - .withState(store.getState()) - .put( - navigationActions.replaceScreen({ - screen: ScreenNames.UsernameRegistrationScreen, - params: { fetching: true }, - }) - ) - .not.put( - communities.actions.createNetwork({ - ownership: CommunityOwnership.User, - registrar: code, - }) - ) - .run() - }) -}) +// import { expectSaga } from 'redux-saga-test-plan' +// import { combineReducers } from '@reduxjs/toolkit' +// import { reducers } from '../../root.reducer' +// import { Store } from '../../store.types' +// import { prepareStore } from '../../../tests/utils/prepareStore' +// import { communities, Community, connection, identity } from '@quiet/state-manager' +// import { initActions } from '../init.slice' +// import { navigationActions } from '../../navigation/navigation.slice' +// import { ScreenNames } from '../../../const/ScreenNames.enum' +// import { deepLinkSaga } from './deepLink.saga' +// import { CommunityOwnership, ConnectionProcessInfo, Identity } from '@quiet/types' + +// describe('deepLinkSaga', () => { +// let store: Store + +// const id = '00d045ab' + +// const community: Community = { +// id, +// name: '', +// CA: { +// rootCertString: '', +// rootKeyString: '', +// }, +// rootCa: '', +// peerList: [], +// registrar: { +// privateKey: '', +// address: '', +// }, +// registrarUrl: 'https://bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd.onion', +// onionAddress: '', +// privateKey: '', +// port: 0, +// registrationAttempts: 0, +// ownerCertificate: '', +// } + +// const _identity: Partial = { +// id, +// nickname: '', +// userCsr: null, +// userCertificate: null, +// joinTimestamp: 0, +// } + +// beforeEach(async () => { +// store = (await prepareStore()).store +// }) + +// test('joins community', async () => { +// store.dispatch( +// initActions.setWebsocketConnected({ +// dataPort: 5001, +// }) +// ) + +// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' + +// const reducer = combineReducers(reducers) +// await expectSaga(deepLinkSaga, initActions.deepLink(code)) +// .withReducer(reducer) +// .withState(store.getState()) +// .put( +// navigationActions.replaceScreen({ +// screen: ScreenNames.JoinCommunityScreen, +// params: { +// code, +// }, +// }) +// ) +// .put( +// communities.actions.createNetwork({ +// ownership: CommunityOwnership.User, +// peers: code, +// }) +// ) +// .run() +// }) + +// test('opens channel list screen if the same url has been used', async () => { +// store.dispatch( +// initActions.setWebsocketConnected({ +// dataPort: 5001, +// }) +// ) + +// store.dispatch(communities.actions.addNewCommunity(community)) + +// store.dispatch( +// // @ts-expect-error +// identity.actions.addNewIdentity({ ..._identity, userCertificate: 'certificate' }) +// ) + +// store.dispatch(communities.actions.setCurrentCommunity(community.id)) + +// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' + +// const reducer = combineReducers(reducers) +// await expectSaga(deepLinkSaga, initActions.deepLink(code)) +// .withReducer(reducer) +// .withState(store.getState()) +// .put( +// navigationActions.replaceScreen({ +// screen: ScreenNames.ChannelListScreen, +// }) +// ) +// .not.put( +// communities.actions.createNetwork({ +// ownership: CommunityOwnership.User, +// registrar: code, +// }) +// ) +// .run() +// }) + +// test('displays error if user already belongs to a community', async () => { +// store.dispatch( +// initActions.setWebsocketConnected({ +// dataPort: 5001, +// }) +// ) + +// store.dispatch(communities.actions.addNewCommunity(community)) + +// store.dispatch(communities.actions.setCurrentCommunity(community.id)) + +// const code = 'ctbebt3ixybtu4ty2dr3ychjtxpkhuun4neuavkjjhplgzfde5vgelad' + +// const reducer = combineReducers(reducers) +// await expectSaga(deepLinkSaga, initActions.deepLink(code)) +// .withReducer(reducer) +// .withState(store.getState()) +// .not.put( +// communities.actions.createNetwork({ +// ownership: CommunityOwnership.User, +// registrar: code, +// }) +// ) +// .run() +// }) + +// test('continues if link used mid registration', async () => { +// store.dispatch( +// initActions.setWebsocketConnected({ +// dataPort: 5001, +// }) +// ) + +// store.dispatch(communities.actions.addNewCommunity(community)) + +// store.dispatch( +// // @ts-expect-error +// identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) +// ) + +// store.dispatch(communities.actions.setCurrentCommunity(community.id)) + +// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' + +// const reducer = combineReducers(reducers) +// await expectSaga(deepLinkSaga, initActions.deepLink(code)) +// .withReducer(reducer) +// .withState(store.getState()) +// .put( +// navigationActions.replaceScreen({ +// screen: ScreenNames.UsernameRegistrationScreen, +// params: undefined, +// }) +// ) +// .not.put( +// communities.actions.createNetwork({ +// ownership: CommunityOwnership.User, +// registrar: code, +// }) +// ) +// .run() +// }) + +// test('continues if link used mid registration and locks input while waiting for server response', async () => { +// store.dispatch( +// initActions.setWebsocketConnected({ +// dataPort: 5001, +// }) +// ) + +// store.dispatch(communities.actions.addNewCommunity(community)) + +// store.dispatch( +// // @ts-expect-error +// identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) +// ) + +// store.dispatch(communities.actions.setCurrentCommunity(community.id)) + +// store.dispatch(connection.actions.setTorConnectionProcess(ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE)) + +// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' + +// const reducer = combineReducers(reducers) +// await expectSaga(deepLinkSaga, initActions.deepLink(code)) +// .withReducer(reducer) +// .withState(store.getState()) +// .put( +// navigationActions.replaceScreen({ +// screen: ScreenNames.UsernameRegistrationScreen, +// params: { fetching: true }, +// }) +// ) +// .not.put( +// communities.actions.createNetwork({ +// ownership: CommunityOwnership.User, +// registrar: code, +// }) +// ) +// .run() +// }) +// }) diff --git a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts index a999979007..ca965b064a 100644 --- a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts +++ b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts @@ -9,6 +9,7 @@ import { appImages } from '../../../assets' import { replaceScreen } from '../../../RootNavigation' import { UsernameRegistrationRouteProps } from '../../../route.params' import { CommunityOwnership, ConnectionProcessInfo, CreateNetworkPayload } from '@quiet/types' +import { retrieveInvitationCode } from '@quiet/common' export function* deepLinkSaga(action: PayloadAction['payload']>): Generator { const code = action.payload @@ -48,14 +49,14 @@ export function* deepLinkSaga(action: PayloadAction { export const invitationUrl = createSelector(currentCommunity, community => { const peerList = community?.peerList - if (!peerList || peerList?.length === 0) return + if (!peerList || peerList?.length === 0) return '' const initialPeers = peerList.slice(0, 4) console.log('invitationUrl INITIAL PEERS', initialPeers) - if (!community?.registrarUrl) return '' - let registrarUrl = '' - try { - const url = new URL(community.registrarUrl) - registrarUrl = url.hostname.split('.')[0] - } catch (e) { - registrarUrl = community.registrarUrl - } + // if (!community?.registrarUrl) return '' + // let registrarUrl = '' + // try { + // const url = new URL(community.registrarUrl) + // registrarUrl = url.hostname.split('.')[0] + // } catch (e) { + // registrarUrl = community.registrarUrl + // } return invitationShareUrl(initialPeers) }) diff --git a/tsconfig.build.json b/tsconfig.build.json index cbe3d6e834..533d6c77ee 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,7 +1,7 @@ { "compilerOptions": { "baseUrl": ".", - "target": "es6", + "target": "ES2020", "module": "commonjs", "declaration": true, "esModuleInterop": true, @@ -13,7 +13,8 @@ "./node_modules/@types" ], "lib": [ - "es6", + "ES2020", + "DOM.Iterable", "dom" ] } diff --git a/tsconfig.json b/tsconfig.json index 5116cd30c1..8eafb17145 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es6", + "target": "ES2020", "baseUrl": ".", "paths": { "@quiet/identity": ["packages/identity/src/index.ts"], @@ -18,8 +18,9 @@ "experimentalDecorators": true, "moduleResolution": "node", "lib": [ - "es6", - "dom" + "dom", + "DOM.Iterable", + "ES2020" ] } } From b3e59c56a53785103d7888d7f3d7960f1aa3b7b3 Mon Sep 17 00:00:00 2001 From: Emi Date: Mon, 21 Aug 2023 19:29:33 +0200 Subject: [PATCH 04/28] Do not launch registrar, do not wait for certificates to join community --- packages/backend/src/nest/common/utils.ts | 9 +- .../connections-manager.service.tor.spec.ts | 10 +- .../connections-manager.service.ts | 98 ++++++++++++------- .../backend/src/nest/libp2p/libp2p.service.ts | 3 +- .../backend/src/nest/libp2p/libp2p.types.ts | 6 +- .../nest/registration/registration.service.ts | 5 +- .../backend/src/nest/socket/socket.service.ts | 10 +- .../src/nest/tor/tor-control.service.ts | 13 ++- .../websocketOverTor.tor.spec.ts | 9 +- packages/common/src/index.ts | 1 + packages/common/src/invitationCode.test.ts | 11 ++- packages/common/src/invitationCode.ts | 23 ++++- packages/common/src/libp2p.ts | 8 ++ .../JoinCommunity/JoinCommunity.tsx | 3 +- .../PerformCommunityActionComponent.tsx | 11 ++- .../CreateUsername/CreateUsername.tsx | 6 +- .../components/LoadingPanel/LoadingPanel.tsx | 2 +- .../renderer/forms/fields/communityFields.ts | 8 +- packages/desktop/src/renderer/index.tsx | 5 - .../desktop/src/renderer/sagas/index.saga.ts | 2 +- .../invitation/handleInvitationCode.saga.ts | 4 +- .../src/rtl-tests/customProtocol.test.tsx | 7 +- .../sagas/appConnection/connection.slice.ts | 1 + .../communities/communities.master.saga.ts | 2 +- .../communities/communities.selectors.ts | 5 + .../sagas/communities/communities.slice.ts | 15 +-- .../createNetwork/createNetwork.saga.ts | 10 +- .../launchCommunity/launchCommunity.saga.ts | 22 +++-- .../responseCreateNetwork.saga.test.ts | 2 +- .../responseCreateNetwork.saga.ts | 1 - .../startConnection/startConnection.saga.ts | 44 +++++---- packages/types/src/community.ts | 2 +- 32 files changed, 219 insertions(+), 139 deletions(-) create mode 100644 packages/common/src/libp2p.ts diff --git a/packages/backend/src/nest/common/utils.ts b/packages/backend/src/nest/common/utils.ts index 22e843a62c..f6e2901627 100644 --- a/packages/backend/src/nest/common/utils.ts +++ b/packages/backend/src/nest/common/utils.ts @@ -12,6 +12,7 @@ import { TestConfig } from '../const' import logger from './logger' import { createCertificatesTestHelper } from './client-server' import { Libp2pNodeParams } from '../libp2p/libp2p.types' +import { createLibp2pAddress, createLibp2pListenAddress } from '@quiet/common' const log = logger('test') export interface Ports { @@ -143,14 +144,6 @@ export const torDirForPlatform = (basePath?: string): string => { return torPath } -export const createLibp2pAddress = (address: string, peerId: string) => { - return `/dns4/${address}/tcp/80/ws/p2p/${peerId}` -} - -export const createLibp2pListenAddress = (address: string) => { - return `/dns4/${address}/tcp/80/ws` -} - export const getUsersAddresses = async (users: User[]): Promise => { const peers = users.map(async (userData: User) => { return createLibp2pAddress(userData.onionAddress, userData.peerId) diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts index e88e7151b2..8c759f8571 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts @@ -4,14 +4,7 @@ import crypto from 'crypto' import { CustomEvent } from '@libp2p/interfaces/events' import { jest, beforeEach, describe, it, expect, afterEach } from '@jest/globals' import { communities, getFactory, identity, prepareStore, Store } from '@quiet/state-manager' -import { - createLibp2pAddress, - createPeerId, - createTmpDir, - libp2pInstanceParams, - removeFilesFromDir, - tmpQuietDirPath, -} from '../common/utils' +import { createPeerId, createTmpDir, libp2pInstanceParams, removeFilesFromDir, tmpQuietDirPath } from '../common/utils' import { NetworkStats, type Community, type Identity, type InitCommunityPayload } from '@quiet/types' import { LazyModuleLoader } from '@nestjs/core' @@ -37,6 +30,7 @@ import { DateTime } from 'luxon' import waitForExpect from 'wait-for-expect' import { Libp2pEvents } from '../libp2p/libp2p.types' import { sleep } from '../common/sleep' +import { createLibp2pAddress } from '@quiet/common' jest.setTimeout(100_000) diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index 1f9b88290c..f7b280470b 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -174,9 +174,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI if (community) { await this.launchCommunity(community) } - if (registrarData) { - await this.registrationService.launchRegistrar(registrarData) - } } public async closeAllServices(options: { saveTor: boolean } = { saveTor: false }) { @@ -282,12 +279,14 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI } public async createCommunity(payload: InitCommunityPayload) { + console.log('ConnectionsManager.createCommunity peers:', payload.peers) await this.launchCommunity(payload) this.logger(`Created and launched community ${payload.id}`) this.serverIoProvider.io.emit(SocketActionTypes.NEW_COMMUNITY, { id: payload.id }) } public async launchCommunity(payload: InitCommunityPayload) { + console.log('ConnectionsManager.launchCommunity peers:', payload.peers) this.communityState = ServiceState.LAUNCHING const communityData: InitCommunityPayload = await this.localDbService.get(LocalDBKeys.COMMUNITY) if (!communityData) { @@ -336,6 +335,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI const _peerId = await peerIdFromKeys(restoredRsa.marshalPubKey(), restoredRsa.marshalPrivKey()) let peers = payload.peers + console.log('LAUNCH COMMUNITY PAYLOAD PEERS', peers) if (!peers || peers.length === 0) { peers = [this.libp2pService.createLibp2pAddress(onionAddress, _peerId.toString())] } @@ -344,9 +344,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI peerId: _peerId, listenAddresses: [this.libp2pService.createLibp2pListenAddress(onionAddress)], agent: this.socksProxyAgent, - cert: payload.certs.certificate, - key: payload.certs.key, - ca: payload.certs.CA, localAddress: this.libp2pService.createLibp2pAddress(onionAddress, _peerId.toString()), targetPort: this.ports.libp2pHiddenService, peers, @@ -387,6 +384,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI }) this.registrationService.on(SocketActionTypes.CONNECTION_PROCESS_INFO, data => { + console.log('CONNECTION_PROCESS_INFO', data) this.serverIoProvider.io.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, data) }) } @@ -395,24 +393,27 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI this.registrarState = payload }) this.registrationService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload => { + console.log('SAVED_OWNER_CERTIFICATE', payload) this.serverIoProvider.io.emit(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload) }) - this.registrationService.on(RegistrationEvents.SPAWN_HS_FOR_REGISTRAR, async payload => { - await this.tor.spawnHiddenService({ - targetPort: payload.port, - privKey: payload.privateKey, - virtPort: payload.targetPort, - }) - }) + // this.registrationService.on(RegistrationEvents.SPAWN_HS_FOR_REGISTRAR, async payload => { + // await this.tor.spawnHiddenService({ + // targetPort: payload.port, + // privKey: payload.privateKey, + // virtPort: payload.targetPort, + // }) + // }) this.registrationService.on(RegistrationEvents.ERROR, payload => { emitError(this.serverIoProvider.io, payload) }) - this.registrationService.on(SocketActionTypes.SEND_USER_CERTIFICATE, payload => { - this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, payload) - }) - this.registrationService.on(RegistrationEvents.NEW_USER, async payload => { - await this.storageService?.saveCertificate(payload) - }) + // this.registrationService.on(SocketActionTypes.SEND_USER_CERTIFICATE, payload => { + // console.log('SEND_USER_CERTIFICATE', payload) + // this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, payload) + // }) + // this.registrationService.on(RegistrationEvents.NEW_USER, async payload => { + // console.log('NEW_USER', payload) + // await this.storageService?.saveCertificate(payload) + // }) } private attachsocketServiceListeners() { // Community @@ -434,9 +435,11 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI } }) this.socketService.on(SocketActionTypes.CREATE_NETWORK, async (args: Community) => { + console.log('SocketActionTypes.CREATE_NETWORK') await this.createNetwork(args) }) this.socketService.on(SocketActionTypes.CREATE_COMMUNITY, async (args: InitCommunityPayload) => { + console.log('SocketActionTypes.CREATE_COMMUNITY') await this.createCommunity(args) }) this.socketService.on(SocketActionTypes.LAUNCH_COMMUNITY, async (args: InitCommunityPayload) => { @@ -446,19 +449,20 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI await this.launchCommunity(args) }) // Registration - this.socketService.on(SocketActionTypes.LAUNCH_REGISTRAR, async (args: LaunchRegistrarPayload) => { - this.logger(`socketService - ${SocketActionTypes.LAUNCH_REGISTRAR}`) - - const communityData = await this.localDbService.get(LocalDBKeys.REGISTRAR) - if (!communityData) { - await this.localDbService.put(LocalDBKeys.REGISTRAR, args) - } - console.log('this.registrarState', this.registrarState) - if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.registrarState)) return - this.registrarState = ServiceState.LAUNCHING - await this.registrationService.launchRegistrar(args) - }) + // this.socketService.on(SocketActionTypes.LAUNCH_REGISTRAR, async (args: LaunchRegistrarPayload) => { + // this.logger(`socketService - ${SocketActionTypes.LAUNCH_REGISTRAR}`) + + // const communityData = await this.localDbService.get(LocalDBKeys.REGISTRAR) + // if (!communityData) { + // await this.localDbService.put(LocalDBKeys.REGISTRAR, args) + // } + // console.log('this.registrarState', this.registrarState) + // if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.registrarState)) return + // this.registrarState = ServiceState.LAUNCHING + // await this.registrationService.launchRegistrar(args) + // }) this.socketService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, async (args: SaveOwnerCertificatePayload) => { + console.log('SAVED_OWNER_CERTIFICATE') const saveCertificatePayload: SaveCertificatePayload = { certificate: args.certificate, rootPermsData: args.permsData, @@ -466,17 +470,35 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI await this.storageService?.saveCertificate(saveCertificatePayload) }) this.socketService.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (args: RegisterUserCertificatePayload) => { + console.log('!!!! REGISTER_USER_CERTIFICATE') // if (!this.socksProxyAgent) { // this.createAgent() // } - await this.registrationService.sendCertificateRegistrationRequest( - args.serviceAddress, - args.userCsr, - args.communityId, - 120_000, - this.socksProxyAgent - ) + // await this.registrationService.sendCertificateRegistrationRequest( + // args.serviceAddress, + // args.userCsr, + // args.communityId, + // 120_000, + // this.socksProxyAgent + // ) + // const response = await this.registrationService.registerUser(args.userCsr) + this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CONNECTING_TO_COMMUNITY) + console.log('emitting SocketActionTypes.SEND_USER_CERTIFICATE') + this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, { + // TEMPORARY + communityId: args.communityId, + payload: { + peers: [], + }, + }) + // this.emit(SocketActionTypes.SEND_USER_CERTIFICATE, { + // // TEMPORARY + // communityId: args.communityId, + // payload: { + // peers: [], + // }, + // }) }) this.socketService.on( SocketActionTypes.REGISTER_OWNER_CERTIFICATE, diff --git a/packages/backend/src/nest/libp2p/libp2p.service.ts b/packages/backend/src/nest/libp2p/libp2p.service.ts index fa98820843..643ec011d5 100644 --- a/packages/backend/src/nest/libp2p/libp2p.service.ts +++ b/packages/backend/src/nest/libp2p/libp2p.service.ts @@ -15,10 +15,10 @@ import { multiaddr } from '@multiformats/multiaddr' import { ConnectionProcessInfo, PeerId, SocketActionTypes } from '@quiet/types' import { SERVER_IO_PROVIDER, SOCKS_PROXY_AGENT } from '../const' import { ServerIoProviderTypes } from '../types' -import { createLibp2pListenAddress, createLibp2pAddress } from './libp2p.utils' import Logger from '../common/logger' import { webSockets } from '../websocketOverTor' import { all } from '../websocketOverTor/filters' +import { createLibp2pAddress, createLibp2pListenAddress } from '@quiet/common' @Injectable() export class Libp2pService extends EventEmitter { @@ -45,6 +45,7 @@ export class Libp2pService extends EventEmitter { } public async createInstance(params: Libp2pNodeParams): Promise { + console.log('Libp2p.createInstance::: peers:::', params.peers) if (this.libp2pInstance) { return this.libp2pInstance } diff --git a/packages/backend/src/nest/libp2p/libp2p.types.ts b/packages/backend/src/nest/libp2p/libp2p.types.ts index a912015c23..b8bd0f95a7 100644 --- a/packages/backend/src/nest/libp2p/libp2p.types.ts +++ b/packages/backend/src/nest/libp2p/libp2p.types.ts @@ -11,9 +11,9 @@ export interface Libp2pNodeParams { peerId: any listenAddresses: string[] agent: Agent - cert: string - key: string - ca: string[] + cert?: string + key?: string + ca?: string[] localAddress: string targetPort: number peers: string[] diff --git a/packages/backend/src/nest/registration/registration.service.ts b/packages/backend/src/nest/registration/registration.service.ts index c3d8a9b172..4b294c2ae5 100644 --- a/packages/backend/src/nest/registration/registration.service.ts +++ b/packages/backend/src/nest/registration/registration.service.ts @@ -30,7 +30,7 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { private _server: Server private _port: number public registrationService: any - public certificates: string[] + public certificates: string[] = [] private _permsData: PermsData private _ownerCertificate: string @@ -40,6 +40,7 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { onModuleInit() { this.on(RegistrationEvents.SET_CERTIFICATES, certs => { + console.log('SET CERTIFICATES', certs) this.setCertificates(certs) }) this.setRouting() @@ -123,7 +124,7 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { this.emit(response.eventType, response.data) } - private async registerUser(csr: string): Promise<{ status: number; body: any }> { + public async registerUser(csr: string): Promise<{ status: number; body: any }> { const result = await registerUser(csr, this._permsData, this.certificates, this._ownerCertificate) if (result?.status === 200) { this.emit(RegistrationEvents.NEW_USER, { certificate: result.body.certificate, rootPermsData: this._permsData }) diff --git a/packages/backend/src/nest/socket/socket.service.ts b/packages/backend/src/nest/socket/socket.service.ts index 4936e4a32a..202a118817 100644 --- a/packages/backend/src/nest/socket/socket.service.ts +++ b/packages/backend/src/nest/socket/socket.service.ts @@ -101,7 +101,7 @@ export class SocketService extends EventEmitter implements OnModuleInit { }) socket.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (payload: RegisterUserCertificatePayload) => { - this.logger(`Registering user certificate (${payload.communityId}) on ${payload.serviceAddress}`) + this.logger(`Registering user CSR (${payload.communityId}) on ${payload.serviceAddress}`) this.emit(SocketActionTypes.REGISTER_USER_CERTIFICATE, payload) await new Promise(resolve => setTimeout(() => resolve(), 2000)) this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE) @@ -124,10 +124,10 @@ export class SocketService extends EventEmitter implements OnModuleInit { this.emit(SocketActionTypes.LAUNCH_COMMUNITY, payload) this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.LAUNCHING_COMMUNITY) }) - socket.on(SocketActionTypes.LAUNCH_REGISTRAR, async (payload: LaunchRegistrarPayload) => { - this.logger(`Launching registrar for community ${payload.id}, user ${payload.peerId}`) - this.emit(SocketActionTypes.LAUNCH_REGISTRAR, payload) - }) + // socket.on(SocketActionTypes.LAUNCH_REGISTRAR, async (payload: LaunchRegistrarPayload) => { + // this.logger(`Launching registrar for community ${payload.id}, user ${payload.peerId}`) + // this.emit(SocketActionTypes.LAUNCH_REGISTRAR, payload) + // }) socket.on(SocketActionTypes.CREATE_NETWORK, async (community: Community) => { this.logger(`Creating network for community ${community.id}`) this.emit(SocketActionTypes.CREATE_NETWORK, community) diff --git a/packages/backend/src/nest/tor/tor-control.service.ts b/packages/backend/src/nest/tor/tor-control.service.ts index f8dcec17b2..2f7087f7dc 100644 --- a/packages/backend/src/nest/tor/tor-control.service.ts +++ b/packages/backend/src/nest/tor/tor-control.service.ts @@ -52,7 +52,7 @@ export class TorControl implements OnModuleInit { }) } - private async disconnect() { + private disconnect() { try { this.connection?.end() } catch (e) { @@ -63,12 +63,19 @@ export class TorControl implements OnModuleInit { // eslint-disable-next-line @typescript-eslint/ban-types private async _sendCommand(command: string, resolve: Function, reject: Function) { - await this.connect() + try { + await this.connect() + } catch (e) { + console.error(`ERROR for ${command}`, e) + this.disconnect() + await this.connect() + } + const connectionTimeout = setTimeout(() => { reject('TOR: Send command timeout') }, 5000) this.connection?.on('data', async data => { - await this.disconnect() + this.disconnect() const dataArray = data.toString().split(/\r?\n/) if (dataArray[0].startsWith('250')) { resolve({ code: 250, messages: dataArray }) diff --git a/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts b/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts index 0ac6482471..fa18cfb8af 100644 --- a/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts +++ b/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts @@ -4,13 +4,7 @@ import { multiaddr } from '@multiformats/multiaddr' import getPort from 'get-port' import { type DirResult } from 'tmp' import { jest, describe, it, expect, afterEach, beforeAll, afterAll } from '@jest/globals' -import { - createLibp2pAddress, - torBinForPlatform, - torDirForPlatform, - createTmpDir, - tmpQuietDirPath, -} from '../common/utils' +import { torBinForPlatform, torDirForPlatform, createTmpDir, tmpQuietDirPath } from '../common/utils' import { type CreateListenerOptions } from '@libp2p/interface-transport' import { createServer } from 'it-ws/server' import { createCertificatesTestHelper } from '../common/client-server' @@ -22,6 +16,7 @@ import { Tor } from '../tor/tor.service' import crypto from 'crypto' import { TorControl } from '../tor/tor-control.service' import { TorControlAuthType } from '../tor/tor.types' +import { createLibp2pAddress } from '@quiet/common' jest.setTimeout(120000) describe('websocketOverTor', () => { diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 914f45c769..67ce8a7b5b 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -7,3 +7,4 @@ export * from './sortPeers' export * from './channelAddress' export * from './naming' export * from './fileData' +export * from './libp2p' diff --git a/packages/common/src/invitationCode.test.ts b/packages/common/src/invitationCode.test.ts index 1f49410df5..6059b9c6be 100644 --- a/packages/common/src/invitationCode.test.ts +++ b/packages/common/src/invitationCode.test.ts @@ -1,4 +1,4 @@ -import { argvInvitationCode, invitationDeepUrl, invitationShareUrl } from './invitationCode' +import { argvInvitationCode, invitationDeepUrl, invitationShareUrl, pairsToInvitationShareUrl } from './invitationCode' import { Site } from './static' describe('Invitation code helper', () => { @@ -27,6 +27,15 @@ describe('Invitation code helper', () => { ).toEqual('quiet://?peerID1=address1&peerID2=address2') }) + it('creates invitation share url based on invitation pairs', () => { + const pairs = [ + { peerId: 'peerID1', address: 'address1' }, + { peerId: 'peerID2', address: 'address2' }, + ] + const expected = `https://${Site.DOMAIN}/${Site.JOIN_PAGE}#peerID1=address1&peerID2=address2` + expect(pairsToInvitationShareUrl(pairs)).toEqual(expected) + }) + // it('builds proper invitation share url', () => { // expect(invitationShareUrl('validCode')).toEqual(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#validCode`) // }) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index 8ed1a54b2a..389e511558 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -1,6 +1,7 @@ import { InvitationPair } from '@quiet/types' import { InvitationParams, Site } from './static' import { multiaddr } from 'multiaddr' +import { createLibp2pAddress } from './libp2p' // export const retrieveInvitationCode = (url: string): string => { // /** @@ -52,7 +53,11 @@ export const retrieveInvitationCode = (url: string): InvitationPair[] => { } export const invitationShareUrl = (peers: string[] = []): string => { - // Valid format: https://tryquiet.org/join/#=&= + /** + * @arg {string[]} peers - List of peer's p2p addresses + * @returns {string} - Complete shareable invitation link, e.g. https://tryquiet.org/join/#=&= + */ + // Valid format: const pairs = [] for (const peerAddress of peers) { let addr @@ -78,6 +83,22 @@ export const invitationShareUrl = (peers: string[] = []): string => { return url.href } +export const pairsToP2pAddresses = (pairs: InvitationPair[]): string[] => { + const addresses: string[] = [] + for (const pair of pairs) { + addresses.push(createLibp2pAddress(pair.address, pair.peerId)) + } + return addresses +} + +export const pairsToInvitationShareUrl = (pairs: InvitationPair[]) => { + const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}`) + for (const pair of pairs) { + url.searchParams.append(pair.peerId, pair.address) + } + return url.href.replace('?', '#') +} + export const invitationDeepUrl = (pairs: InvitationPair[] = []): string => { const url = new URL('quiet://') for (const pair of pairs) { diff --git a/packages/common/src/libp2p.ts b/packages/common/src/libp2p.ts new file mode 100644 index 0000000000..f4b84d6f8c --- /dev/null +++ b/packages/common/src/libp2p.ts @@ -0,0 +1,8 @@ +export const createLibp2pAddress = (address: string, peerId: string) => { + if (!address.endsWith('.onion')) address += '.onion' + return `/dns4/${address}/tcp/80/ws/p2p/${peerId}` +} + +export const createLibp2pListenAddress = (address: string) => { + return `/dns4/${address}/tcp/80/ws` +} diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx index 9ed4991099..edafa145ce 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx @@ -15,7 +15,7 @@ const JoinCommunity = () => { const currentCommunity = useSelector(communities.selectors.currentCommunity) const currentIdentity = useSelector(identity.selectors.currentIdentity) - const invitationCode = useSelector(communities.selectors.invitationCode) + const invitationCode = useSelector(communities.selectors.invitationCodes) const joinCommunityModal = useModal(ModalName.joinCommunityModal) const createCommunityModal = useModal(ModalName.createCommunityModal) @@ -46,6 +46,7 @@ const JoinCommunity = () => { ownership: CommunityOwnership.User, peers: address, } + console.log('handleCommunityAction createNetwork') dispatch(communities.actions.createNetwork(payload)) } diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx index 1b7f20dc23..fb279728dc 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx @@ -12,7 +12,7 @@ import { LoadingButton } from '../ui/LoadingButton/LoadingButton' import { CreateCommunityDictionary, JoinCommunityDictionary } from '../CreateJoinCommunity/community.dictionary' -import { CommunityOwnership } from '@quiet/types' +import { CommunityOwnership, InvitationPair } from '@quiet/types' import { Controller, useForm } from 'react-hook-form' import { TextInput } from '../../forms/components/textInput' @@ -20,7 +20,7 @@ import { InviteLinkErrors } from '../../forms/fieldsErrors' import { IconButton, InputAdornment } from '@mui/material' import VisibilityOff from '@mui/icons-material/VisibilityOff' import Visibility from '@mui/icons-material/Visibility' -import { ONION_ADDRESS_REGEX, parseName } from '@quiet/common' +import { ONION_ADDRESS_REGEX, pairsToInvitationShareUrl, parseName } from '@quiet/common' import { getInvitationCodes } from '@quiet/state-manager' const PREFIX = 'PerformCommunityActionComponent' @@ -137,7 +137,7 @@ export interface PerformCommunityActionProps { hasReceivedResponse: boolean revealInputValue?: boolean handleClickInputReveal?: () => void - invitationCode?: string + invitationCode?: InvitationPair[] } export const PerformCommunityActionComponent: React.FC = ({ @@ -192,6 +192,7 @@ export const PerformCommunityActionComponent: React.FC { - if (communityOwnership === CommunityOwnership.User && invitationCode) { + if (communityOwnership === CommunityOwnership.User && invitationCode?.length) { setFormSent(true) - setValue('name', invitationCode) + setValue('name', pairsToInvitationShareUrl(invitationCode)) } }, [communityOwnership, invitationCode]) diff --git a/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.tsx b/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.tsx index c6b439bc05..79c59de8be 100644 --- a/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.tsx +++ b/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.tsx @@ -18,10 +18,12 @@ const CreateUsername = () => { const error = useSelector(errors.selectors.registrarErrors) useEffect(() => { - if (currentCommunity && !currentIdentity?.userCertificate && !createUsernameModal.open) { + if (currentCommunity && !currentIdentity?.userCsr && !createUsernameModal.open) { + console.log('createUsernameModal.handleOpen()') createUsernameModal.handleOpen() } - if (currentIdentity?.userCertificate && createUsernameModal.open) { + if (currentIdentity?.userCsr && createUsernameModal.open) { + console.log('createUsernameModal.handleClose()') createUsernameModal.handleClose() } }, [currentIdentity, currentCommunity]) diff --git a/packages/desktop/src/renderer/components/LoadingPanel/LoadingPanel.tsx b/packages/desktop/src/renderer/components/LoadingPanel/LoadingPanel.tsx index 566eebd229..77e1c6b270 100644 --- a/packages/desktop/src/renderer/components/LoadingPanel/LoadingPanel.tsx +++ b/packages/desktop/src/renderer/components/LoadingPanel/LoadingPanel.tsx @@ -24,7 +24,7 @@ const LoadingPanel = () => { const community = useSelector(communities.selectors.currentCommunity) const owner = Boolean(community?.CA) - const currentIdentity = useSelector(identity.selectors.currentIdentity) + // const currentIdentity = useSelector(identity.selectors.currentIdentity) const usersData = Object.keys(useSelector(users.selectors.certificates)) const isOnlyOneUser = usersData.length === 1 diff --git a/packages/desktop/src/renderer/forms/fields/communityFields.ts b/packages/desktop/src/renderer/forms/fields/communityFields.ts index bda6aa21a4..9a1f8e31fb 100644 --- a/packages/desktop/src/renderer/forms/fields/communityFields.ts +++ b/packages/desktop/src/renderer/forms/fields/communityFields.ts @@ -36,10 +36,10 @@ export const inviteLinkField = (name = 'name'): FieldData => { }, validation: { required: FieldErrors.Required, - pattern: { - value: /^[a-z0-9:/.#?= ]+$/g, - message: InviteLinkErrors.InvalidCode, - }, + // pattern: { + // // value: /^[a-z0-9:/.#?= ]+$/g, + // message: InviteLinkErrors.InvalidCode, + // }, }, } } diff --git a/packages/desktop/src/renderer/index.tsx b/packages/desktop/src/renderer/index.tsx index 02942c0c46..ef2e8f1e08 100644 --- a/packages/desktop/src/renderer/index.tsx +++ b/packages/desktop/src/renderer/index.tsx @@ -25,11 +25,6 @@ ipcRenderer.on('invitation', (_event, invitation) => { store.dispatch(communities.actions.handleInvitationCodes(invitation.codes)) }) -// ipcRenderer.on('invitationMA', (_event, invitation) => { -// console.log('invitation', invitation, 'dispatching action') -// store.dispatch(communities.actions.handleInvitationCodes(invitation.codes)) -// }) - const container = document.getElementById('root') if (!container) throw new Error('No root html element!') let root = createRoot(container) diff --git a/packages/desktop/src/renderer/sagas/index.saga.ts b/packages/desktop/src/renderer/sagas/index.saga.ts index 35d0dbc985..e41f8b6faa 100644 --- a/packages/desktop/src/renderer/sagas/index.saga.ts +++ b/packages/desktop/src/renderer/sagas/index.saga.ts @@ -7,7 +7,7 @@ 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.handleInvitationCode.type, handleInvitationCodeSaga), + takeEvery(communities.actions.handleInvitationCodes.type, handleInvitationCodeSaga), startConnectionSaga( socketActions.startConnection({ dataPort: parseInt(dataPort), diff --git a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts index d2bd74f864..2f542068a2 100644 --- a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts +++ b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts @@ -39,11 +39,11 @@ export function* handleInvitationCodeSaga( peers: action.payload, } yield* put(communities.actions.createNetwork(payload)) - return + // return // } // TODO: handle invalid code - // yield* put(communities.actions.clearInvitationCode()) + // yield* put(communities.actions.clearInvitationCodes()) // yield* put( // modalsActions.openModal({ diff --git a/packages/desktop/src/rtl-tests/customProtocol.test.tsx b/packages/desktop/src/rtl-tests/customProtocol.test.tsx index 7e85eef1f7..2837451ef5 100644 --- a/packages/desktop/src/rtl-tests/customProtocol.test.tsx +++ b/packages/desktop/src/rtl-tests/customProtocol.test.tsx @@ -10,6 +10,7 @@ import { modalsActions } from '../renderer/sagas/modals/modals.slice' import { ModalName } from '../renderer/sagas/modals/modals.types' import JoinCommunity from '../renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity' import CreateUsername from '../renderer/components/CreateUsername/CreateUsername' +import { InvitationPair } from '@quiet/types' jest.setTimeout(20_000) @@ -64,9 +65,11 @@ describe('Opening app through custom protocol', () => { socket // Fork state manager's sagas ) - const invitationCode = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' + const invitationCodes: InvitationPair[] = [ + { peerId: 'abcdef', address: 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' }, + ] - store.dispatch(communities.actions.handleInvitationCode(invitationCode)) + store.dispatch(communities.actions.handleInvitationCodes(invitationCodes)) store.dispatch(modalsActions.openModal({ name: ModalName.joinCommunityModal })) diff --git a/packages/state-manager/src/sagas/appConnection/connection.slice.ts b/packages/state-manager/src/sagas/appConnection/connection.slice.ts index 8b5cc4e190..df6306b025 100644 --- a/packages/state-manager/src/sagas/appConnection/connection.slice.ts +++ b/packages/state-manager/src/sagas/appConnection/connection.slice.ts @@ -53,6 +53,7 @@ export const connectionSlice = createSlice({ }, setTorConnectionProcess: (state, action: PayloadAction) => { const info = action.payload + console.log('----> setTorConnectionProcess', info) switch (info) { case ConnectionProcessInfo.CONNECTING_TO_COMMUNITY: state.torConnectionProcess = { number: 20, text: info } diff --git a/packages/state-manager/src/sagas/communities/communities.master.saga.ts b/packages/state-manager/src/sagas/communities/communities.master.saga.ts index d0b855879f..ff986aed1d 100644 --- a/packages/state-manager/src/sagas/communities/communities.master.saga.ts +++ b/packages/state-manager/src/sagas/communities/communities.master.saga.ts @@ -15,6 +15,6 @@ export function* communitiesMasterSaga(socket: Socket): Generator { takeEvery(communitiesActions.updateCommunity.type, updateCommunitySaga), takeEvery(connectionActions.torBootstrapped.type, initCommunities), takeEvery(communitiesActions.launchCommunity.type, launchCommunitySaga, socket), - takeEvery(communitiesActions.launchRegistrar.type, launchRegistrarSaga, socket), + // takeEvery(communitiesActions.launchRegistrar.type, launchRegistrarSaga, socket), ]) } diff --git a/packages/state-manager/src/sagas/communities/communities.selectors.ts b/packages/state-manager/src/sagas/communities/communities.selectors.ts index f8651b258c..9857c2ce09 100644 --- a/packages/state-manager/src/sagas/communities/communities.selectors.ts +++ b/packages/state-manager/src/sagas/communities/communities.selectors.ts @@ -57,6 +57,10 @@ export const invitationCode = createSelector(communitiesSlice, reducerState => { return reducerState.invitationCode }) +export const invitationCodes = createSelector(communitiesSlice, reducerState => { + return reducerState.invitationCodes +}) + export const invitationUrl = createSelector(currentCommunity, community => { const peerList = community?.peerList if (!peerList || peerList?.length === 0) return '' @@ -114,6 +118,7 @@ export const communitiesSelectors = { currentCommunityId, registrarUrl, registrationAttempts, + invitationCodes, invitationCode, invitationUrl, ownerNickname, diff --git a/packages/state-manager/src/sagas/communities/communities.slice.ts b/packages/state-manager/src/sagas/communities/communities.slice.ts index af67c8b8ab..4d976e9e23 100644 --- a/packages/state-manager/src/sagas/communities/communities.slice.ts +++ b/packages/state-manager/src/sagas/communities/communities.slice.ts @@ -91,15 +91,18 @@ export const communitiesSlice = createSlice({ }, }) }, - handleInvitationCode: (state, action: PayloadAction) => { - state.invitationCode = action.payload - }, - clearInvitationCode: state => { - state.invitationCode = '' - }, + // handleInvitationCode: (state, action: PayloadAction) => { + // state.invitationCode = action.payload + // }, + // clearInvitationCode: state => { + // state.invitationCode = '' + // }, handleInvitationCodes: (state, action: PayloadAction) => { state.invitationCodes = action.payload }, + setInvitationCodes: (state, action: PayloadAction) => { + state.invitationCodes = action.payload + }, clearInvitationCodes: state => { state.invitationCodes = [] }, diff --git a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts index 1fa5b13771..66ca0dc57d 100644 --- a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts +++ b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts @@ -1,10 +1,12 @@ import { PayloadAction } from '@reduxjs/toolkit' -import { call, put } from 'typed-redux-saga' +import { call, put, select } from 'typed-redux-saga' import { Time } from 'pkijs' import { generateId } from '../../../utils/cryptography/cryptography' import { communitiesActions } from '../communities.slice' import { createRootCA } from '@quiet/identity' import { type Community, CommunityOwnership } from '@quiet/types' +import { communitiesSelectors } from '../communities.selectors' +import { connectionSelectors } from '../../appConnection/connection.selectors' export function* createNetworkSaga( action: PayloadAction['payload']> @@ -39,7 +41,11 @@ export function* createNetworkSaga( rootCa: CA?.rootCertString, } - yield* put(communitiesActions.clearInvitationCode()) + const invitationPeers = action.payload.peers + if (invitationPeers) { + yield* put(communitiesActions.setInvitationCodes(invitationPeers)) + } + yield* put(communitiesActions.addNewCommunity(payload)) yield* put(communitiesActions.setCurrentCommunity(id)) } diff --git a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts index 4640049c20..3de4f5d09d 100644 --- a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts @@ -8,6 +8,7 @@ import { connectionActions } from '../../appConnection/connection.slice' import { getCurrentTime } from '../../messages/utils/message.utils' import { connectionSelectors } from '../../appConnection/connection.selectors' import { networkSelectors } from '../../network/network.selectors' +import { pairsToP2pAddresses } from '@quiet/common' import { type InitCommunityPayload, SocketActionTypes } from '@quiet/types' export function* initCommunities(): Generator { @@ -36,22 +37,29 @@ export function* launchCommunitySaga( const community = yield* select(communitiesSelectors.selectById(communityId)) const identity = yield* select(identitySelectors.selectById(communityId)) - if (!identity?.userCertificate || !identity.userCsr?.userKey || !community?.rootCa) { + if (!identity?.userCsr?.userKey) { console.error('Could not launch community, Community or Identity is lacking data') return } - const peerList = yield* select(connectionSelectors.peerList) + const invitationCodes = yield* select(communitiesSelectors.invitationCodes) + let peerList: string[] = [] + if (invitationCodes) { + peerList = pairsToP2pAddresses(invitationCodes) + } else { + peerList = yield* select(connectionSelectors.peerList) + } + console.log('LAUNCH community peers', peerList) const payload: InitCommunityPayload = { id: identity.id, peerId: identity.peerId, hiddenService: identity.hiddenService, - certs: { - certificate: identity.userCertificate, - key: identity.userCsr.userKey, - CA: [community.rootCa], - }, + // certs: { + // certificate: identity.userCertificate, + // key: identity.userCsr.userKey, + // CA: [community.rootCa], + // }, peers: peerList, } diff --git a/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts b/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts index 31f71fa16e..3b068ad007 100644 --- a/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts +++ b/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts @@ -61,7 +61,7 @@ describe('responseCreateNetwork', () => { .withState(store.getState()) .provide([[call.fn(generateDmKeyPair), dmKeys]]) .call(generateDmKeyPair) - .put(communitiesActions.clearInvitationCode()) + .put(communitiesActions.clearInvitationCodes()) .put(communitiesActions.updateCommunityData(community)) .put(identityActions.addNewIdentity(identity)) .run() diff --git a/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.ts b/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.ts index 224e210418..4cefc0e43a 100644 --- a/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.ts +++ b/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.ts @@ -22,7 +22,6 @@ export function* responseCreateNetworkSaga(action: PayloadAction | ReturnType | ReturnType + | ReturnType >(emit => { // UPDATE FOR APP socket.on(SocketActionTypes.TOR_BOOTSTRAP_PROCESS, (payload: string) => { @@ -168,6 +169,7 @@ export function subscribe(socket: Socket) { emit(publicChannelsActions.createGeneralChannel()) }) socket.on(SocketActionTypes.REGISTRAR, (payload: ResponseRegistrarPayload) => { + console.log('SocketActionTypes.REGISTRAR') log(SocketActionTypes.REGISTRAR, payload) emit(communitiesActions.responseRegistrar(payload)) emit(networkActions.addInitializedRegistrar(payload.id)) @@ -180,9 +182,10 @@ export function subscribe(socket: Socket) { emit(communitiesActions.responseCreateNetwork(payload)) }) socket.on(SocketActionTypes.COMMUNITY, (payload: ResponseLaunchCommunityPayload) => { - emit(communitiesActions.launchRegistrar(payload.id)) + // emit(communitiesActions.launchRegistrar(payload.id)) emit(filesActions.checkForMissingFiles(payload.id)) emit(networkActions.addInitializedCommunity(payload.id)) + emit(communitiesActions.clearInvitationCodes()) }) // Errors socket.on(SocketActionTypes.ERROR, (payload: ErrorPayload) => { @@ -201,14 +204,14 @@ export function subscribe(socket: Socket) { }) socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => { - console.log('user cert with owner cert', payload) + console.log('Received SEND_USER_CERTIFICATE', payload.communityId) - emit( - communitiesActions.addOwnerCertificate({ - communityId: payload.communityId, - ownerCertificate: payload.payload.ownerCert, - }) - ) + // emit( + // communitiesActions.addOwnerCertificate({ + // communityId: payload.communityId, + // ownerCertificate: payload.payload.ownerCert, // is it needed? Owner is just an admin now + // }) + // ) emit( communitiesActions.storePeerList({ @@ -216,21 +219,22 @@ export function subscribe(socket: Socket) { peerList: payload.payload.peers, }) ) - emit( - identityActions.storeUserCertificate({ - userCertificate: payload.payload.certificate, - communityId: payload.communityId, - }) - ) - emit( - communitiesActions.updateCommunity({ - id: payload.communityId, - rootCa: payload.payload.rootCa, - }) - ) + // emit( + // identityActions.storeUserCertificate({ + // userCertificate: payload.payload.certificate, // is it needed? + // communityId: payload.communityId, + // }) + // ) + // emit( + // communitiesActions.updateCommunity({ + // id: payload.communityId, + // rootCa: payload.payload.rootCa, // is it needed? + // }) + // ) emit(communitiesActions.launchCommunity(payload.communityId)) }) socket.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, (payload: SavedOwnerCertificatePayload) => { + console.log('Received SAVED_OWNER_CERTIFICATE', payload.communityId) emit( communitiesActions.addOwnerCertificate({ communityId: payload.communityId, diff --git a/packages/types/src/community.ts b/packages/types/src/community.ts index 0f2077e5c5..cb4170169c 100644 --- a/packages/types/src/community.ts +++ b/packages/types/src/community.ts @@ -53,7 +53,7 @@ export interface InitCommunityPayload { id: string peerId: PeerId hiddenService: HiddenService - certs: Certificates + certs?: Certificates peers?: string[] } From 28ba290a7a868d6ee130e563b095801a1087a0cb Mon Sep 17 00:00:00 2001 From: Emi Date: Wed, 23 Aug 2023 19:12:32 +0200 Subject: [PATCH 05/28] Add eventlog DB for CSRs; Create invitation link basing on user's data from csrs --- .../connections-manager.service.ts | 67 ++++----- .../backend/src/nest/libp2p/libp2p.service.ts | 3 +- .../backend/src/nest/socket/socket.service.ts | 16 ++- .../src/nest/storage/storage.service.spec.ts | 32 ++++- .../src/nest/storage/storage.service.ts | 136 ++++++++++++++++-- packages/identity/src/index.ts | 10 +- .../sagas/appConnection/connection.slice.ts | 6 +- .../launchCommunity/launchCommunity.saga.ts | 1 + .../sagas/identity/identity.master.saga.ts | 2 + .../src/sagas/identity/identity.slice.ts | 2 + .../registerCertificate.saga.ts | 31 ++-- .../identity/saveUserCsr/saveUserCsr.saga.ts | 19 +++ .../messages/sendMessage/sendMessage.saga.ts | 5 +- .../startConnection/startConnection.saga.ts | 64 +++++---- .../src/sagas/users/users.slice.ts | 1 + packages/state-manager/src/types.ts | 2 + packages/types/src/connection.ts | 1 + packages/types/src/identity.ts | 5 + packages/types/src/socket.ts | 2 + 19 files changed, 304 insertions(+), 101 deletions(-) create mode 100644 packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index f7b280470b..6c5e297807 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -42,6 +42,7 @@ import { StorePeerListPayload, UploadFilePayload, PeerId as PeerIdType, + SaveCSRPayload, } from '@quiet/types' import { CONFIG_OPTIONS, QUIET_DIR, SERVER_IO_PROVIDER, SOCKS_PROXY_AGENT } from '../const' import { ConfigOptions, GetPorts, ServerIoProviderTypes } from '../types' @@ -166,7 +167,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.communityState)) return this.communityState = ServiceState.LAUNCHING } - const registrarData: LaunchRegistrarPayload = await this.localDbService.get(LocalDBKeys.REGISTRAR) + const registrarData: LaunchRegistrarPayload = await this.localDbService.get(LocalDBKeys.REGISTRAR) // TODO: remove if (registrarData) { if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.registrarState)) return this.registrarState = ServiceState.LAUNCHING @@ -271,7 +272,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI community: { ...community, privateKey: network2.hiddenService.privateKey, - registrarUrl: community.registrarUrl || network2.hiddenService.onionAddress.split('.')[0], + registrarUrl: community.registrarUrl || network2.hiddenService.onionAddress.split('.')[0], // TODO: remove }, network, } @@ -469,37 +470,37 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI } await this.storageService?.saveCertificate(saveCertificatePayload) }) - this.socketService.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (args: RegisterUserCertificatePayload) => { - console.log('!!!! REGISTER_USER_CERTIFICATE') - // if (!this.socksProxyAgent) { - // this.createAgent() - // } - - // await this.registrationService.sendCertificateRegistrationRequest( - // args.serviceAddress, - // args.userCsr, - // args.communityId, - // 120_000, - // this.socksProxyAgent - // ) - // const response = await this.registrationService.registerUser(args.userCsr) - this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CONNECTING_TO_COMMUNITY) - console.log('emitting SocketActionTypes.SEND_USER_CERTIFICATE') - this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, { - // TEMPORARY - communityId: args.communityId, - payload: { - peers: [], - }, - }) - // this.emit(SocketActionTypes.SEND_USER_CERTIFICATE, { - // // TEMPORARY - // communityId: args.communityId, - // payload: { - // peers: [], - // }, - // }) - }) + this.socketService.on(SocketActionTypes.SAVE_USER_CSR, async (payload: SaveCSRPayload) => { + console.log('SAVE_USER_CSR backend', payload) + await this.storageService?.saveCSR(payload) + this.serverIoProvider.io.emit(SocketActionTypes.SAVED_USER_CSR, payload) + }) + // this.socketService.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (args: RegisterUserCertificatePayload) => { + // // Change to REGISTER_USER_CSR + // console.log('!!!! REGISTER_USER_CERTIFICATE', args.userCsr) + // // await this.storageService?.saveCSR({ csr: args.userCsr }) + // // if (!this.socksProxyAgent) { + // // this.createAgent() + // // } + + // // await this.registrationService.sendCertificateRegistrationRequest( + // // args.serviceAddress, + // // args.userCsr, + // // args.communityId, + // // 120_000, + // // this.socksProxyAgent + // // ) + // // const response = await this.registrationService.registerUser(args.userCsr) + // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CONNECTING_TO_COMMUNITY) + // console.log('emitting SocketActionTypes.SEND_USER_CERTIFICATE') + // this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, { + // // TEMPORARY + // communityId: args.communityId, + // payload: { + // peers: [], + // }, + // }) + // }) this.socketService.on( SocketActionTypes.REGISTER_OWNER_CERTIFICATE, async (args: RegisterOwnerCertificatePayload) => { diff --git a/packages/backend/src/nest/libp2p/libp2p.service.ts b/packages/backend/src/nest/libp2p/libp2p.service.ts index 643ec011d5..a9e8619110 100644 --- a/packages/backend/src/nest/libp2p/libp2p.service.ts +++ b/packages/backend/src/nest/libp2p/libp2p.service.ts @@ -44,7 +44,7 @@ export class Libp2pService extends EventEmitter { return createLibp2pListenAddress(address) } - public async createInstance(params: Libp2pNodeParams): Promise { + public async createInstance(params: Libp2pNodeParams): Promise { console.log('Libp2p.createInstance::: peers:::', params.peers) if (this.libp2pInstance) { return this.libp2pInstance @@ -113,6 +113,7 @@ export class Libp2pService extends EventEmitter { this.libp2pInstance.addEventListener('peer:connect', async peer => { const remotePeerId = peer.detail.remotePeer.toString() + console.log('ADDRESS', peer.detail.remoteAddr) this.logger(`${peerId.toString()} connected to ${remotePeerId}`) // Stop dialing as soon as we connect to a peer diff --git a/packages/backend/src/nest/socket/socket.service.ts b/packages/backend/src/nest/socket/socket.service.ts index 202a118817..697972af89 100644 --- a/packages/backend/src/nest/socket/socket.service.ts +++ b/packages/backend/src/nest/socket/socket.service.ts @@ -15,6 +15,7 @@ import { LaunchRegistrarPayload, Community, DeleteFilesFromChannelSocketPayload, + SaveCSRPayload, } from '@quiet/types' import cors, { CorsOptions } from 'cors' import EventEmitter from 'events' @@ -100,12 +101,19 @@ export class SocketService extends EventEmitter implements OnModuleInit { this.emit(SocketActionTypes.ASK_FOR_MESSAGES, payload) }) - socket.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (payload: RegisterUserCertificatePayload) => { - this.logger(`Registering user CSR (${payload.communityId}) on ${payload.serviceAddress}`) - this.emit(SocketActionTypes.REGISTER_USER_CERTIFICATE, payload) + socket.on(SocketActionTypes.SAVE_USER_CSR, async (payload: SaveCSRPayload) => { + this.logger(`SAVING user CSR ${payload.csr}`) + this.emit(SocketActionTypes.SAVE_USER_CSR, payload) await new Promise(resolve => setTimeout(() => resolve(), 2000)) - this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE) + this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.SAVING_USER_CSR) }) + + // socket.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (payload: RegisterUserCertificatePayload) => { + // this.logger(`Registering user CSR (${payload.communityId}) on ${payload.serviceAddress}`) + // this.emit(SocketActionTypes.REGISTER_USER_CERTIFICATE, payload) + // await new Promise(resolve => setTimeout(() => resolve(), 2000)) + // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE) + // }) socket.on(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, async (payload: RegisterOwnerCertificatePayload) => { this.logger(`Registering owner certificate (${payload.communityId})`) this.emit(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, payload) diff --git a/packages/backend/src/nest/storage/storage.service.spec.ts b/packages/backend/src/nest/storage/storage.service.spec.ts index 8e95303aad..ee19696c65 100644 --- a/packages/backend/src/nest/storage/storage.service.spec.ts +++ b/packages/backend/src/nest/storage/storage.service.spec.ts @@ -540,7 +540,7 @@ describe('StorageService', () => { }) describe('Users', () => { - it('gets all users from db', async () => { + it('gets all registered users from db', async () => { await storageService.init(peerId) const mockGetCertificates = jest.fn() // @ts-ignore - Property 'getAllEventLogEntries' is protected @@ -549,7 +549,7 @@ describe('StorageService', () => { 'MIICWzCCAgGgAwIBAgIGAYKIVrmoMAoGCCqGSM49BAMCMA8xDTALBgNVBAMTBG1haW4wHhcNMjIwODEwMTUxOTIxWhcNMzAwMTMxMjMwMDAwWjBJMUcwRQYDVQQDEz5wM29xZHI1M2RrZ2czbjVudWV6bHp5YXdoeHZpdDVlZnh6bHVudnpwN243bG12YTZmajNpNDNhZC5vbmlvbjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCAjxbiV781WC8O5emEdavPaQfR0FD8CaqC+P3R3uRdL9xuzGeUu8f5NIplSJ6abBMnanGgcMs34u82buiFROHqjggENMIIBCTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIAgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwLwYJKoZIhvcNAQkMBCIEICSr5xj+pjBSb+YOZ7TMPQJHYs4KASfnc9TugSpKJUG/MBUGCisGAQQBg4wbAgEEBxMFZGV2dnYwPQYJKwYBAgEPAwEBBDATLlFtVlRrVWFkMkdxM01rQ2E4Z2YxMlIxZ3NXRGZrMnlpVEVxYjZZR1hERzJpUTMwSQYDVR0RBEIwQII+cDNvcWRyNTNka2dnM241bnVlemx6eWF3aHh2aXQ1ZWZ4emx1bnZ6cDduN2xtdmE2ZmozaTQzYWQub25pb24wCgYIKoZIzj0EAwIDSAAwRQIhAIXhkkgs3H6GcZ1GYrSL2qJYDRQcpZlmcbq7YjpJHaORAiBMfkwP75v08R/ud6BPWvdS36corT+596+HzpqFt6bffw==', 'MIICYTCCAgegAwIBAgIGAYKIYnYuMAoGCCqGSM49BAMCMA8xDTALBgNVBAMTBG1haW4wHhcNMjIwODEwMTUzMjEwWhcNMzAwMTMxMjMwMDAwWjBJMUcwRQYDVQQDEz52bnl3dWl5bDdwN2lnMm11cmNzY2R5emtza281M2U0azNkcGRtMnlvb3B2dnUyNXA2d3dqcWJhZC5vbmlvbjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABM0cOt7jMJ6YhRvL9nhbDCh42QJPKDet/Zc2PJ9rm6CzYz1IXc5uRUCUNZSnNykVMZknogAavp0FjV+cFXzV8gGjggETMIIBDzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIAgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwLwYJKoZIhvcNAQkMBCIEIIsBwPwIhLSltj9dnkgkMq3sOe3RVha9Mhukop6XOoISMBsGCisGAQQBg4wbAgEEDRMLZHNrZmpia3NmaWcwPQYJKwYBAgEPAwEBBDATLlFtZDJVbjlBeW5va1pyY1pHc011YXFndXBUdGlkSEdRblVrTlZmRkZBZWY5N0MwSQYDVR0RBEIwQII+dm55d3VpeWw3cDdpZzJtdXJjc2NkeXprc2tvNTNlNGszZHBkbTJ5b29wdnZ1MjVwNnd3anFiYWQub25pb24wCgYIKoZIzj0EAwIDSAAwRQIgAiCmGfUuSG010CxLEzu9mAQOgDq//SHI9LkXbmCxaAUCIQC9xzmkRBxq5HmNomYJ9ZAJXaY3J6+VqBYthaVnv0bhMw==', ]) - const allUsers = storageService.getAllUsers() + const allUsers = storageService.getAllRegisteredUsers() expect(allUsers).toStrictEqual([ { onionAddress: 'p3oqdr53dkgg3n5nuezlzyawhxvit5efxzlunvzp7n7lmva6fj3i43ad.onion', @@ -565,6 +565,34 @@ describe('StorageService', () => { }, ]) }) + it('gets all users from db', async () => { + await storageService.init(peerId) + const mockGetCsrs = jest.fn() + // @ts-ignore - Property 'getAllEventLogEntries' is protected + storageService.getAllEventLogEntries = mockGetCsrs + mockGetCsrs.mockReturnValue([ + 'MIIDHjCCAsMCAQAwSTFHMEUGA1UEAxM+NnZ1MmJ4a2k3NzdpdDNjcGF5djZmcTZ2cGw0a2Uza3pqN2d4aWNmeWdtNTVkaGh0cGh5ZmR2eWQub25pb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATMpfp2hSfWFL26OZlZKZEWG9fyAM1ndlEzO0kLxT0pA/7/fs+a5X/s4TkzqCVVQSzhas/84q0WE99ScAcM1LQJoIICFjAuBgkqhkiG9w0BCQ4xITAfMB0GA1UdDgQWBBR6VRzktP1pzZxsGUaJivNUrtgSrzCCAUcGCSqGSIb3DQEJDDGCATgEggE0KZq9s6HEViRfplVgYkulg6XV411ZRe4U1UjfXTf1pRaygfcenGbT6RRagPtZzjuq5hHdYhqDjRzZhnbn8ZASYTgBM7qcseUq5UpS1pE08DI2jePKqatp3Pzm6a/MGSziESnREx784JlKfwKMjJl33UA8lQm9nhSeAIHyBx3c4Lf8IXdW2n3rnhbVfjpBMAxwh6lt+e5agtGXy+q/xAESUeLPfUgRYWctlLgt8Op+WTpLyBkZsVFoBvJrMt2XdM0RI32YzTRr56GXFa4VyQmY5xXwlQSPgidAP7jPkVygNcoeXvAz2ZCk3IR1Cn3mX8nMko53MlDNaMYldUQA0ug28/S7BlSlaq2CDD4Ol3swTq7C4KGTxKrI36ruYUZx7NEaQDF5V7VvqPCZ0fZoTIJuSYTQ67gwEQYKKwYBBAGDjBsCATEDEwFvMD0GCSsGAQIBDwMBATEwEy5RbVhSWTRyaEF4OE11cThkTUdrcjlxa25KZEU2VUhaRGRHYURSVFFFYndGTjViMEcGA1UdETFAEz42dnUyYnhraTc3N2l0M2NwYXl2NmZxNnZwbDRrZTNremo3Z3hpY2Z5Z201NWRoaHRwaHlmZHZ5ZC5vbmlvbjAKBggqhkjOPQQDAgNJADBGAiEAt+f1u/bchg5AZHv6NTGNoXeejTRWUhX3ioGwW6TGg84CIQCHqKNzDh2JjS/hUHx5PApAmfNnQTSf19X6LnNHQweU1g==', + 'MIIDHTCCAsMCAQAwSTFHMEUGA1UEAxM+eTd5Y3ptdWdsMnRla2FtaTdzYmR6NXBmYWVtdng3YmFod3RocmR2Y2J6dzV2ZXgyY3JzcjI2cWQub25pb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATMq0l4bCmjdb0grtzpwtDVLM9E1IQpL9vrB4+lD9OBZzlrx2365jV7shVu9utas8w8fxtKoBZSnT5+32ZMFTB4oIICFjAuBgkqhkiG9w0BCQ4xITAfMB0GA1UdDgQWBBSoDQpTZdEvi1/Rr/muVXT1clyKRDCCAUcGCSqGSIb3DQEJDDGCATgEggE0BQvyvkiiXEf/PLKnsR1Ba9AhYsVO8o56bnftUnoVzBlRZgUzLJvOSroPk/EmbVz+okhMrcYNgCWHvxrAqHVVq0JRP6bi98BtCUotx6OPFHp5K5QCL60hod1uAnhKocyJG9tsoM9aS+krn/k+g4RCBjiPZ25cC7QG/UNr6wyIQ8elBho4MKm8iOp7EShSsZOV1f6xrnXYCC/zyUc85GEuycLzVImgAQvPATbdMzY4zSGnNLHxkvSUNxaR9LnEWf+i1jeqcOiXOvmdyU5Be3ZqhGKvvBg/5vyLQiCIfeapjZemnLqFHQBitglDm2xnKL6HzMyfZoAHPV7YcWYR4spU9Ju8Q8aqSeAryx7sx55eSR4GO5UQTo5DrQn6xtkwOZ/ytsOknFthF8jcA9uTAMDKA2TylCUwEQYKKwYBBAGDjBsCATEDEwFvMD0GCSsGAQIBDwMBATEwEy5RbVQxOFV2blVCa3NlTWMzU3FuZlB4cEh3TjhuekxySmVOU0xadGM4ckFGWGh6MEcGA1UdETFAEz55N3ljem11Z2wydGVrYW1pN3NiZHo1cGZhZW12eDdiYWh3dGhyZHZjYnp3NXZleDJjcnNyMjZxZC5vbmlvbjAKBggqhkjOPQQDAgNIADBFAiEAoFrAglxmk7ciD6AHQOB1qEoLu0NARcxgwmIry8oeTHwCICyXp5NJQ9Z8vReIAQNng2H2+/XjHifZEWzhoN0VkcBx', + ]) + const allUsers = storageService.getAllUsers() + + expect(allUsers).toStrictEqual([ + { + onionAddress: '6vu2bxki777it3cpayv6fq6vpl4ke3kzj7gxicfygm55dhhtphyfdvyd.onion', + peerId: 'QmXRY4rhAx8Muq8dMGkr9qknJdE6UHZDdGaDRTQEbwFN5b', + dmPublicKey: + '299abdb3a1c456245fa65560624ba583a5d5e35d5945ee14d548df5d37f5a516b281f71e9c66d3e9145a80fb59ce3baae611dd621a838d1cd98676e7f1901261380133ba9cb1e52ae54a52d69134f032368de3caa9ab69dcfce6e9afcc192ce21129d1131efce0994a7f028c8c9977dd403c9509bd9e149e0081f2071ddce0b7fc217756da7deb9e16d57e3a41300c7087a96df9ee5a82d197cbeabfc4011251e2cf7d481161672d94b82df0ea7e593a4bc81919b1516806f26b32dd9774cd11237d98cd346be7a19715ae15c90998e715f095048f8227403fb8cf915ca035ca1e5ef033d990a4dc84750a7de65fc9cc928e773250cd68c625754400d2e836f3f4bb0654a56aad820c3e0e977b304eaec2e0a193c4aac8dfaaee614671ecd11a40317957b56fa8f099d1f6684c826e4984d0ebb8', + username: 'o', + }, + { + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd.onion', + peerId: 'QmT18UvnUBkseMc3SqnfPxpHwN8nzLrJeNSLZtc8rAFXhz', + dmPublicKey: + '050bf2be48a25c47ff3cb2a7b11d416bd02162c54ef28e7a6e77ed527a15cc19516605332c9bce4aba0f93f1266d5cfea2484cadc60d802587bf1ac0a87555ab42513fa6e2f7c06d094a2dc7a38f147a792b94022fad21a1dd6e02784aa1cc891bdb6ca0cf5a4be92b9ff93e83844206388f676e5c0bb406fd436beb0c8843c7a5061a3830a9bc88ea7b112852b19395d5feb1ae75d8082ff3c9473ce4612ec9c2f35489a0010bcf0136dd333638cd21a734b1f192f494371691f4b9c459ffa2d637aa70e8973af99dc94e417b766a8462afbc183fe6fc8b4220887de6a98d97a69cba851d0062b609439b6c6728be87cccc9f6680073d5ed8716611e2ca54f49bbc43c6aa49e02bcb1eecc79e5e491e063b95104e8e43ad09fac6d930399ff2b6c3a49c5b6117c8dc03db9300c0ca0364f29425', + username: 'o', + }, + ]) + }) }) describe('Files deletion', () => { diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index 7eb3aa5582..7d341ce943 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -7,6 +7,8 @@ import { parseCertificate, verifySignature, verifyUserCert, + parseCertificationRequest, + getReqFieldValue, } from '@quiet/identity' import type { IPFS } from 'ipfs-core' import OrbitDB from 'orbit-db' @@ -27,6 +29,7 @@ import { NoCryptoEngineError, PublicChannel, PushNotificationPayload, + SaveCSRPayload, SaveCertificatePayload, SocketActionTypes, User, @@ -43,7 +46,7 @@ import AccessControllers from 'orbit-db-access-controllers' import { MessagesAccessController } from './MessagesAccessController' import { createChannelAccessController } from './ChannelsAccessController' import Logger from '../common/logger' -import { DirectMessagesRepo, IMessageThread, PublicChannelsRepo } from '../common/types' +import { DirectMessagesRepo, PublicChannelsRepo } from '../common/types' import { removeFiles, removeDirs, createPaths, getUsersAddresses } from '../common/utils' import { StorageEvents } from './storage.types' @@ -55,6 +58,7 @@ interface DBOptions { export class StorageService extends EventEmitter { public channels: KeyValueStore private certificates: EventStore + private certificatesRequests: EventStore public publicChannelsRepos: Map = new Map() public directMessagesRepos: Map = new Map() private publicKeysMap: Map = new Map() @@ -150,6 +154,9 @@ export class StorageService extends EventEmitter { if (this.certificates?.address) { dbs.push(this.certificates.address) } + if (this.certificatesRequests?.address) { + dbs.push(this.certificatesRequests.address) + } const channels = this.publicChannelsRepos.values() @@ -203,13 +210,15 @@ export class StorageService extends EventEmitter { } public async initDatabases() { - this.logger('1/4') + this.logger('1/5') await this.createDbForChannels() - this.logger('2/4') + this.logger('2/5') await this.createDbForCertificates() - this.logger('3/4') + this.logger('3/5') + await this.createDbForCertificatesRequests() + this.logger('4/5') await this.initAllChannels() - this.logger('4/4') + this.logger('5/5') this.logger('Initialized DBs') this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.INITIALIZED_DBS) } @@ -245,27 +254,34 @@ export class StorageService extends EventEmitter { public async stopOrbitDb() { try { - if (this.channels) { - await this.channels.close() - } + await this.channels?.close() } catch (e) { - this.logger.error('channels', e) + this.logger.error('Error closing channels db', e) } try { - if (this.certificates) { - await this.certificates.close() - } + await this.certificates?.close() + } catch (e) { + this.logger.error('Error closing certificates db', e) + } + try { + await this.certificatesRequests?.close() } catch (e) { - this.logger.error('certificates', e) + this.logger.error('Error closing certificates db', e) } await this.__stopOrbitDb() await this.__stopIPFS() } public async updatePeersList() { + console.log('updatePeersList') const allUsers = this.getAllUsers() - const peers = await getUsersAddresses(allUsers) + console.log('updatePeersList allUsers', allUsers) + const registeredUsers = this.getAllRegisteredUsers() + console.log('updatePeersList registeredUsers', registeredUsers) + const peers = [...new Set(await getUsersAddresses(allUsers.concat(registeredUsers)))] + // const peers = [...new Set(await getUsersAddresses(registeredUsers))] + console.log('updatePeersList peers', peers) const community = await this.localDbService.get(LocalDBKeys.COMMUNITY) this.emit(StorageEvents.UPDATE_PEERS_LIST, { communityId: community.id, peerList: peers }) } @@ -332,6 +348,61 @@ export class StorageService extends EventEmitter { this.logger('STORAGE: Finished createDbForCertificates') } + public async createDbForCertificatesRequests() { + this.logger('certificatesRequests db init') + this.certificatesRequests = await this.orbitDb.log('csrs', { + replicate: false, + accessController: { + write: ['*'], + }, + }) + // this.certificates.events.on('replicate.progress', async (_address, _hash, entry, _progress, _total) => { + // const certificate = entry.payload.value + + // const parsedCertificate = parseCertificate(certificate) + // const key = keyFromCertificate(parsedCertificate) + + // const username = getCertFieldValue(parsedCertificate, CertFieldsTypes.nickName) + // if (!username) { + // this.logger.error( + // `Certificates replicate.progress: could not parse certificate for field type ${CertFieldsTypes.nickName}` + // ) + // return + // } + + // this.userNamesMap.set(key, username) + // }) + this.certificatesRequests.events.on('replicated', async () => { + this.logger('REPLICATED: CSRs') + // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CSRS_REPLICATED) + // this.emit(StorageEvents.LOAD_CERTIFICATES, { + // certificates: this.getAllEventLogEntries(this.certificatesRequests), + // }) + await this.updatePeersList() + }) + this.certificatesRequests.events.on('write', async (_address, entry) => { + this.logger('Saved CSR locally') + this.logger(entry.payload.value) + // this.emit(StorageEvents.LOAD_CERTIFICATES, { + // certificates: this.getAllEventLogEntries(this.certificates), + // }) + await this.updatePeersList() + }) + // this.certificates.events.on('ready', () => { + // this.logger('Loaded certificates to memory') + // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.LOADED_CERTIFICATES) + // this.emit(StorageEvents.LOAD_CERTIFICATES, { + // certificates: this.getAllEventLogEntries(this.certificates), + // }) + // }) + + // @ts-expect-error - OrbitDB's type declaration of `load` lacks 'options' + await this.certificates.load({ fetchEntryTimeout: 15000 }) + const allcsrs = this.getAllEventLogEntries(this.certificatesRequests) + this.logger('ALL Certificates COUNT:', allcsrs.length) + this.logger('STORAGE: Finished creating certificatesRequests db') + } + public async loadAllChannels() { this.logger('Getting all channels') // @ts-expect-error - OrbitDB's type declaration of `load` lacks 'options' @@ -755,7 +826,25 @@ export class StorageService extends EventEmitter { return true } - public getAllUsers(): User[] { + public async saveCSR(payload: SaveCSRPayload): Promise { + this.logger('About to save csr...') + if (!payload.csr) { + this.logger('CSR is either null or undefined, not saving to db') + return false + } + // TODO: Verify CSR? + // const verification = await verifyUserCert(payload.rootPermsData.certificate, payload.certificate) + // if (verification.resultCode !== 0) { + // this.logger.error('Certificate is not valid') + // this.logger.error(verification.resultMessage) + // return false + // } + this.logger('Saving csr...') + await this.certificatesRequests.add(payload.csr) + return true + } + + public getAllRegisteredUsers(): User[] { const certs = this.getAllEventLogEntries(this.certificates) const allUsers: User[] = [] for (const cert of certs) { @@ -770,6 +859,23 @@ export class StorageService extends EventEmitter { return allUsers } + public getAllUsers(): User[] { + const csrs = this.getAllEventLogEntries(this.certificatesRequests) + console.log('csrs', csrs.length) + const allUsers: User[] = [] + for (const csr of csrs) { + const parsedCert = parseCertificationRequest(csr) + const onionAddress = getReqFieldValue(parsedCert, CertFieldsTypes.commonName) + const peerId = getReqFieldValue(parsedCert, CertFieldsTypes.peerId) + const username = getReqFieldValue(parsedCert, CertFieldsTypes.nickName) + const dmPublicKey = getReqFieldValue(parsedCert, CertFieldsTypes.dmPublicKey) + console.log('DATA', onionAddress, peerId, username) + if (!onionAddress || !peerId || !username || !dmPublicKey) continue + allUsers.push({ onionAddress, peerId, username, dmPublicKey }) + } + return allUsers + } + public usernameCert(username: string): string | null { /** * Check if given username is already in use diff --git a/packages/identity/src/index.ts b/packages/identity/src/index.ts index 0e2139b2fb..e319ce40fd 100644 --- a/packages/identity/src/index.ts +++ b/packages/identity/src/index.ts @@ -2,6 +2,7 @@ import { createRootCA, type RootCA } from './generateRootCA' import { extractPubKey, parseCertificate, + parseCertificationRequest, keyFromCertificate, keyObjectFromString, extractPubKeyString, @@ -36,7 +37,14 @@ import { export { createRootCA } export type { RootCA } -export { extractPubKey, parseCertificate, keyFromCertificate, keyObjectFromString, extractPubKeyString } +export { + extractPubKey, + parseCertificate, + keyFromCertificate, + keyObjectFromString, + extractPubKeyString, + parseCertificationRequest, +} export { verifyUserCert } export { verifySignature } export { sign } diff --git a/packages/state-manager/src/sagas/appConnection/connection.slice.ts b/packages/state-manager/src/sagas/appConnection/connection.slice.ts index df6306b025..ecc2cfa53f 100644 --- a/packages/state-manager/src/sagas/appConnection/connection.slice.ts +++ b/packages/state-manager/src/sagas/appConnection/connection.slice.ts @@ -58,9 +58,6 @@ export const connectionSlice = createSlice({ case ConnectionProcessInfo.CONNECTING_TO_COMMUNITY: state.torConnectionProcess = { number: 20, text: info } break - case ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE: - state.torConnectionProcess = { number: 20, text: info } - break case ConnectionProcessInfo.REGISTERING_OWNER_CERTIFICATE: state.torConnectionProcess = { number: 20, text: info } break @@ -88,6 +85,9 @@ export const connectionSlice = createSlice({ case ConnectionProcessInfo.LAUNCHED_COMMUNITY: state.torConnectionProcess = { number: 85, text: info } break + case ConnectionProcessInfo.SAVING_USER_CSR: + state.torConnectionProcess = { number: 85, text: info } + break case ConnectionProcessInfo.CHANNELS_REPLICATED: state.torConnectionProcess = { number: 90, text: info } break diff --git a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts index 3de4f5d09d..12e1070bb8 100644 --- a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts @@ -29,6 +29,7 @@ export function* launchCommunitySaga( socket: Socket, action: PayloadAction['payload'] | undefined> ): Generator { + console.log('LAUNCH COMMUNITY SAGA') let communityId: string | undefined = action.payload if (!communityId) { diff --git a/packages/state-manager/src/sagas/identity/identity.master.saga.ts b/packages/state-manager/src/sagas/identity/identity.master.saga.ts index 3546f4b03e..88338dba0e 100644 --- a/packages/state-manager/src/sagas/identity/identity.master.saga.ts +++ b/packages/state-manager/src/sagas/identity/identity.master.saga.ts @@ -6,6 +6,7 @@ import { saveOwnerCertToDbSaga } from './saveOwnerCertToDb/saveOwnerCertToDb.sag import { registerUsernameSaga } from './registerUsername/registerUsername.saga' import { savedOwnerCertificateSaga } from './savedOwnerCertificate/savedOwnerCertificate.saga' import { verifyJoinTimestampSaga } from './verifyJoinTimestamp/verifyJoinTimestamp.saga' +import { saveUserCsrSaga } from './saveUserCsr/saveUserCsr.saga' export function* identityMasterSaga(socket: Socket): Generator { yield all([ @@ -14,5 +15,6 @@ export function* identityMasterSaga(socket: Socket): Generator { takeEvery(identityActions.saveOwnerCertToDb.type, saveOwnerCertToDbSaga, socket), takeEvery(identityActions.savedOwnerCertificate.type, savedOwnerCertificateSaga, socket), takeEvery(identityActions.verifyJoinTimestamp.type, verifyJoinTimestampSaga), + takeEvery(identityActions.saveCsr.type, saveUserCsrSaga, socket), ]) } diff --git a/packages/state-manager/src/sagas/identity/identity.slice.ts b/packages/state-manager/src/sagas/identity/identity.slice.ts index 6911d6c04c..ce92acab00 100644 --- a/packages/state-manager/src/sagas/identity/identity.slice.ts +++ b/packages/state-manager/src/sagas/identity/identity.slice.ts @@ -8,6 +8,7 @@ import { type Identity, type RegisterCertificatePayload, type StoreUserCertificatePayload, + SaveCSRPayload, } from '@quiet/types' export class IdentityState { public identities: EntityState = identityAdapter.getInitialState() @@ -42,6 +43,7 @@ export const identitySlice = createSlice({ }, }) }, + saveCsr: state => state, verifyJoinTimestamp: state => state, updateJoinTimestamp: (state, action: PayloadAction) => { identityAdapter.updateOne(state.identities, { diff --git a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts index 362af87d95..e98a7bf428 100644 --- a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts +++ b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts @@ -1,6 +1,6 @@ import { applyEmitParams, type Socket } from '../../../types' import { type PayloadAction } from '@reduxjs/toolkit' -import { apply, select } from 'typed-redux-saga' +import { apply, select, put } from 'typed-redux-saga' import { communitiesSelectors } from '../../communities/communities.selectors' import { type identityActions } from '../identity.slice' import { @@ -8,6 +8,7 @@ import { type RegisterUserCertificatePayload, SocketActionTypes, } from '@quiet/types' +import { communitiesActions } from '../../communities/communities.slice' export function* registerCertificateSaga( socket: Socket, @@ -30,17 +31,21 @@ export function* registerCertificateSaga( } yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, payload)) - } else { - if (!currentCommunity.registrarUrl) { - console.error('Could not register certificate, no registrar url') - return - } - const payload: RegisterUserCertificatePayload = { - communityId: action.payload.communityId, - userCsr: action.payload.userCsr.userCsr, - serviceAddress: currentCommunity.registrarUrl, - } - - yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.REGISTER_USER_CERTIFICATE, payload)) } + + yield* put(communitiesActions.launchCommunity(action.payload.communityId)) + + // else { + // if (!currentCommunity.registrarUrl) { + // console.error('Could not register certificate, no registrar url') + // return + // } + // const payload: RegisterUserCertificatePayload = { + // communityId: action.payload.communityId, + // userCsr: action.payload.userCsr.userCsr, + // serviceAddress: currentCommunity.registrarUrl, + // } + + // yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.REGISTER_USER_CERTIFICATE, payload)) + // } } diff --git a/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts b/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts new file mode 100644 index 0000000000..c01ada798d --- /dev/null +++ b/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts @@ -0,0 +1,19 @@ +import { SaveCSRPayload, SocketActionTypes } from '@quiet/types' +import { applyEmitParams, type Socket } from '../../../types' +import { PayloadAction } from '@reduxjs/toolkit' +import { apply, select } from 'typed-redux-saga' +import { identitySelectors } from '../identity.selectors' + +export function* saveUserCsrSaga(socket: Socket): Generator { + console.log('SAVE USER CSR SAGA') + const identity = yield* select(identitySelectors.currentIdentity) + if (!identity?.userCsr) { + console.error('saveUserCsrSaga NO IDENTITY') + return + } + const payload: SaveCSRPayload = { + csr: identity.userCsr?.userCsr, + } + console.log('SENDING SAVE_USER_CSR') + yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.SAVE_USER_CSR, payload)) +} diff --git a/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts b/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts index e1c3c0e1d1..32b0c020c5 100644 --- a/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts +++ b/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts @@ -15,7 +15,10 @@ export function* sendMessageSaga( action: PayloadAction['payload']> ): Generator { const identity = yield* select(identitySelectors.currentIdentity) - if (!identity?.userCsr || !identity.userCertificate) return + if (!identity?.userCsr || !identity.userCertificate) { + console.info('No user CSR or user certificate') + return + } const certificate = identity.userCertificate diff --git a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts index 853848d67d..439f0875d7 100644 --- a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts +++ b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts @@ -42,6 +42,7 @@ import { type SavedOwnerCertificatePayload, SendUserCertificatePayload, type SendOwnerCertificatePayload, + SaveCSRPayload, } from '@quiet/types' const log = logger('socket') @@ -88,6 +89,7 @@ export function subscribe(socket: Socket) { | ReturnType | ReturnType | ReturnType + | ReturnType >(emit => { // UPDATE FOR APP socket.on(SocketActionTypes.TOR_BOOTSTRAP_PROCESS, (payload: string) => { @@ -182,7 +184,9 @@ export function subscribe(socket: Socket) { emit(communitiesActions.responseCreateNetwork(payload)) }) socket.on(SocketActionTypes.COMMUNITY, (payload: ResponseLaunchCommunityPayload) => { + console.log('on SocketActionTypes.COMMUNITY') // emit(communitiesActions.launchRegistrar(payload.id)) + emit(identityActions.saveCsr()) emit(filesActions.checkForMissingFiles(payload.id)) emit(networkActions.addInitializedCommunity(payload.id)) emit(communitiesActions.clearInvitationCodes()) @@ -202,37 +206,41 @@ export function subscribe(socket: Socket) { ) emit(usersActions.responseSendCertificates(payload)) }) + socket.on(SocketActionTypes.SAVED_USER_CSR, (payload: SaveCSRPayload) => { + console.log('SAVEDD USER CSR') - socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => { - console.log('Received SEND_USER_CERTIFICATE', payload.communityId) + // emit(communitiesActions.launchCommunity(payload.communityId)) + }) + // socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => { + // console.log('Received SEND_USER_CERTIFICATE', payload.communityId) - // emit( - // communitiesActions.addOwnerCertificate({ - // communityId: payload.communityId, - // ownerCertificate: payload.payload.ownerCert, // is it needed? Owner is just an admin now - // }) - // ) + // // emit( + // // communitiesActions.addOwnerCertificate({ + // // communityId: payload.communityId, + // // ownerCertificate: payload.payload.ownerCert, // is it needed? Owner is just an admin now + // // }) + // // ) - emit( - communitiesActions.storePeerList({ - communityId: payload.communityId, - peerList: payload.payload.peers, - }) - ) - // emit( - // identityActions.storeUserCertificate({ - // userCertificate: payload.payload.certificate, // is it needed? - // communityId: payload.communityId, - // }) - // ) - // emit( - // communitiesActions.updateCommunity({ - // id: payload.communityId, - // rootCa: payload.payload.rootCa, // is it needed? - // }) - // ) - emit(communitiesActions.launchCommunity(payload.communityId)) - }) + // emit( + // communitiesActions.storePeerList({ + // communityId: payload.communityId, + // peerList: payload.payload.peers, + // }) + // ) + // // emit( + // // identityActions.storeUserCertificate({ + // // userCertificate: payload.payload.certificate, // is it needed? + // // communityId: payload.communityId, + // // }) + // // ) + // // emit( + // // communitiesActions.updateCommunity({ + // // id: payload.communityId, + // // rootCa: payload.payload.rootCa, // is it needed? + // // }) + // // ) + // emit(communitiesActions.launchCommunity(payload.communityId)) + // }) socket.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, (payload: SavedOwnerCertificatePayload) => { console.log('Received SAVED_OWNER_CERTIFICATE', payload.communityId) emit( diff --git a/packages/state-manager/src/sagas/users/users.slice.ts b/packages/state-manager/src/sagas/users/users.slice.ts index c5d1e9b8bf..d70706e37c 100644 --- a/packages/state-manager/src/sagas/users/users.slice.ts +++ b/packages/state-manager/src/sagas/users/users.slice.ts @@ -6,6 +6,7 @@ import { type SendCertificatesResponse } from '@quiet/types' export class UsersState { public certificates: EntityState = certificatesAdapter.getInitialState() + public csrs: EntityState = certificatesAdapter.getInitialState() } export const usersSlice = createSlice({ diff --git a/packages/state-manager/src/types.ts b/packages/state-manager/src/types.ts index abd95a819b..2a71e13bc4 100644 --- a/packages/state-manager/src/types.ts +++ b/packages/state-manager/src/types.ts @@ -3,6 +3,7 @@ import { type DefaultEventsMap } from 'socket.io-client/build/typed-events' import { type messagesActions } from './sagas/messages/messages.slice' import { type publicChannelsActions } from './sagas/publicChannels/publicChannels.slice' import { + SaveCSRPayload, type CancelDownloadPayload, type Community, type DeleteFilesFromChannelSocketPayload, @@ -37,6 +38,7 @@ export interface EmitEvents { [SocketActionTypes.CLOSE]: () => void [SocketActionTypes.LEAVE_COMMUNITY]: () => void [SocketActionTypes.CREATE_NETWORK]: EmitEvent + [SocketActionTypes.SAVE_USER_CSR]: EmitEvent } export type Socket = IOSocket diff --git a/packages/types/src/connection.ts b/packages/types/src/connection.ts index 11085d1088..e342c2e2b4 100644 --- a/packages/types/src/connection.ts +++ b/packages/types/src/connection.ts @@ -18,6 +18,7 @@ export interface NetworkStats { export enum ConnectionProcessInfo { CONNECTING_TO_COMMUNITY = 'Connecting to community owner via Tor', REGISTERING_USER_CERTIFICATE = 'Registering user certificate', + SAVING_USER_CSR = 'Saving user csr', REGISTERING_OWNER_CERTIFICATE = 'Registering owner certificate', LAUNCHING_COMMUNITY = 'Launching community', SPAWNING_HIDDEN_SERVICE = 'Spawning hidden service for community', diff --git a/packages/types/src/identity.ts b/packages/types/src/identity.ts index 175e8d7c56..2185f379ab 100644 --- a/packages/types/src/identity.ts +++ b/packages/types/src/identity.ts @@ -79,6 +79,11 @@ export interface SaveCertificatePayload { rootPermsData: PermsData } +export interface SaveCSRPayload { + // communityId: string + csr: string +} + export interface SaveOwnerCertificatePayload { id: string peerId: string diff --git a/packages/types/src/socket.ts b/packages/types/src/socket.ts index 133e10bc0f..5b31423294 100644 --- a/packages/types/src/socket.ts +++ b/packages/types/src/socket.ts @@ -54,6 +54,8 @@ export enum SocketActionTypes { // S SAVE_OWNER_CERTIFICATE = 'saveOwnerCertificate', SAVED_OWNER_CERTIFICATE = 'savedOwnerCertificate', + SAVE_USER_CSR = 'saveUserCsr', + SAVED_USER_CSR = 'savedUserCsr', SEND_DIRECT_MESSAGE = 'sendDirectMessage', SEND_MESSAGE = 'sendMessage', SEND_MESSAGES_IDS = 'sendIds', From 2e2d3b520c417505b36a4d29cab8725f9a45ac58 Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 24 Aug 2023 10:43:18 +0200 Subject: [PATCH 06/28] Remove tmp fix for sendCommand --- packages/backend/src/nest/tor/tor-control.service.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/backend/src/nest/tor/tor-control.service.ts b/packages/backend/src/nest/tor/tor-control.service.ts index 2f7087f7dc..d5692474bb 100644 --- a/packages/backend/src/nest/tor/tor-control.service.ts +++ b/packages/backend/src/nest/tor/tor-control.service.ts @@ -63,13 +63,7 @@ export class TorControl implements OnModuleInit { // eslint-disable-next-line @typescript-eslint/ban-types private async _sendCommand(command: string, resolve: Function, reject: Function) { - try { - await this.connect() - } catch (e) { - console.error(`ERROR for ${command}`, e) - this.disconnect() - await this.connect() - } + await this.connect() const connectionTimeout = setTimeout(() => { reject('TOR: Send command timeout') From bb30494731d3c82ea3458a2ba58b560afa934ead Mon Sep 17 00:00:00 2001 From: Vin Kabuki Date: Fri, 25 Aug 2023 12:58:42 +0200 Subject: [PATCH 07/28] Fix community double launch --- .../sagas/identity/identity.master.saga.ts | 2 -- .../savedOwnerCertificate.saga.ts | 35 ------------------- .../startConnection/startConnection.saga.ts | 1 - 3 files changed, 38 deletions(-) delete mode 100644 packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts diff --git a/packages/state-manager/src/sagas/identity/identity.master.saga.ts b/packages/state-manager/src/sagas/identity/identity.master.saga.ts index 88338dba0e..5c4dc8166f 100644 --- a/packages/state-manager/src/sagas/identity/identity.master.saga.ts +++ b/packages/state-manager/src/sagas/identity/identity.master.saga.ts @@ -4,7 +4,6 @@ import { identityActions } from './identity.slice' import { registerCertificateSaga } from './registerCertificate/registerCertificate.saga' import { saveOwnerCertToDbSaga } from './saveOwnerCertToDb/saveOwnerCertToDb.saga' import { registerUsernameSaga } from './registerUsername/registerUsername.saga' -import { savedOwnerCertificateSaga } from './savedOwnerCertificate/savedOwnerCertificate.saga' import { verifyJoinTimestampSaga } from './verifyJoinTimestamp/verifyJoinTimestamp.saga' import { saveUserCsrSaga } from './saveUserCsr/saveUserCsr.saga' @@ -13,7 +12,6 @@ export function* identityMasterSaga(socket: Socket): Generator { takeEvery(identityActions.registerUsername.type, registerUsernameSaga, socket), takeEvery(identityActions.registerCertificate.type, registerCertificateSaga, socket), takeEvery(identityActions.saveOwnerCertToDb.type, saveOwnerCertToDbSaga, socket), - takeEvery(identityActions.savedOwnerCertificate.type, savedOwnerCertificateSaga, socket), takeEvery(identityActions.verifyJoinTimestamp.type, verifyJoinTimestampSaga), takeEvery(identityActions.saveCsr.type, saveUserCsrSaga, socket), ]) diff --git a/packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts b/packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts deleted file mode 100644 index 5631401ee2..0000000000 --- a/packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { type Socket, applyEmitParams } from '../../../types' -import { select, apply } from 'typed-redux-saga' -import { type PayloadAction } from '@reduxjs/toolkit' -import { type identityActions } from '../identity.slice' -import { communitiesSelectors } from '../../communities/communities.selectors' -import { identitySelectors } from '../identity.selectors' -import { type InitCommunityPayload, SocketActionTypes } from '@quiet/types' - -export function* savedOwnerCertificateSaga( - socket: Socket, - action: PayloadAction['payload']> -): Generator { - let communityId: string = action.payload - - if (!communityId) { - communityId = yield* select(communitiesSelectors.currentCommunityId) - } - - const community = yield* select(communitiesSelectors.selectById(communityId)) - const identity = yield* select(identitySelectors.selectById(communityId)) - if (!identity?.userCertificate || !identity?.userCsr || !community?.rootCa) return - - const payload: InitCommunityPayload = { - id: communityId, - peerId: identity.peerId, - hiddenService: identity.hiddenService, - certs: { - certificate: identity.userCertificate, - key: identity.userCsr.userKey, - CA: [community.rootCa], - }, - } - - yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.CREATE_COMMUNITY, payload)) -} diff --git a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts index bc482dc3ad..fefa4cec2a 100644 --- a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts +++ b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts @@ -259,7 +259,6 @@ export function subscribe(socket: Socket) { communityId: payload.communityId, }) ) - emit(identityActions.savedOwnerCertificate(payload.communityId)) }) return () => undefined }) From f2972df64a18db679cc5ab98b836df608885beb0 Mon Sep 17 00:00:00 2001 From: Emi Date: Sun, 27 Aug 2023 14:01:33 +0200 Subject: [PATCH 08/28] Simulate registrar by creating certificate on csr replication --- .../connections-manager.service.ts | 66 +++++++------------ .../registration/registration.functions.ts | 1 + .../nest/registration/registration.service.ts | 17 +++++ .../backend/src/nest/socket/socket.service.ts | 8 +-- .../src/nest/storage/storage.service.ts | 33 +++++----- .../communities/communities.master.saga.ts | 2 +- .../launchRegistrar/launchRegistrar.saga.ts | 4 ++ .../sagas/identity/identity.master.saga.ts | 4 +- .../src/sagas/identity/identity.slice.ts | 2 +- .../registerCertificate.saga.ts | 4 +- .../savedOwnerCertificate.saga.ts | 35 ++++++++++ .../startConnection/startConnection.saga.ts | 64 +++++++++--------- packages/types/src/identity.ts | 2 +- 13 files changed, 144 insertions(+), 98 deletions(-) create mode 100644 packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index 7480694c6f..8908cadf98 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -43,6 +43,7 @@ import { UploadFilePayload, PeerId as PeerIdType, SaveCSRPayload, + SendUserCertificatePayload, } from '@quiet/types' import { CONFIG_OPTIONS, QUIET_DIR, SERVER_IO_PROVIDER, SOCKS_PROXY_AGENT } from '../const' import { ConfigOptions, GetPorts, ServerIoProviderTypes } from '../types' @@ -328,7 +329,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI const { Libp2pModule } = await import('../libp2p/libp2p.module') const moduleRef = await this.lazyModuleLoader.load(() => Libp2pModule) - this.logger('launchCommunityFromStorage') const { Libp2pService } = await import('../libp2p/libp2p.service') const lazyService = moduleRef.get(Libp2pService) this.libp2pService = lazyService @@ -398,13 +398,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI console.log('SAVED_OWNER_CERTIFICATE', payload) this.serverIoProvider.io.emit(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload) }) - // this.registrationService.on(RegistrationEvents.SPAWN_HS_FOR_REGISTRAR, async payload => { - // await this.tor.spawnHiddenService({ - // targetPort: payload.port, - // privKey: payload.privateKey, - // virtPort: payload.targetPort, - // }) - // }) this.registrationService.on(RegistrationEvents.ERROR, payload => { emitError(this.serverIoProvider.io, payload) }) @@ -412,10 +405,10 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI // console.log('SEND_USER_CERTIFICATE', payload) // this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, payload) // }) - // this.registrationService.on(RegistrationEvents.NEW_USER, async payload => { - // console.log('NEW_USER', payload) - // await this.storageService?.saveCertificate(payload) - // }) + this.registrationService.on(RegistrationEvents.NEW_USER, async payload => { + console.log('NEW_USER', payload) + await this.storageService?.saveCertificate(payload) + }) } private attachsocketServiceListeners() { // Community @@ -450,19 +443,14 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI this.communityState = ServiceState.LAUNCHING await this.launchCommunity(args) }) - // Registration - // this.socketService.on(SocketActionTypes.LAUNCH_REGISTRAR, async (args: LaunchRegistrarPayload) => { - // this.logger(`socketService - ${SocketActionTypes.LAUNCH_REGISTRAR}`) - - // const communityData = await this.localDbService.get(LocalDBKeys.REGISTRAR) - // if (!communityData) { - // await this.localDbService.put(LocalDBKeys.REGISTRAR, args) - // } - // console.log('this.registrarState', this.registrarState) - // if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.registrarState)) return - // this.registrarState = ServiceState.LAUNCHING - // await this.registrationService.launchRegistrar(args) - // }) + this.socketService.on(SocketActionTypes.LAUNCH_REGISTRAR, async (args: LaunchRegistrarPayload) => { + // Event left for setting permsData purposes + this.logger(`socketService - ${SocketActionTypes.LAUNCH_REGISTRAR}`) + this.registrationService.permsData = { + certificate: args.rootCertString, + privKey: args.rootKeyString, + } + }) this.socketService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, async (args: SaveOwnerCertificatePayload) => { console.log('SAVED_OWNER_CERTIFICATE') const saveCertificatePayload: SaveCertificatePayload = { @@ -479,28 +467,18 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI // this.socketService.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (args: RegisterUserCertificatePayload) => { // // Change to REGISTER_USER_CSR // console.log('!!!! REGISTER_USER_CERTIFICATE', args.userCsr) - // // await this.storageService?.saveCSR({ csr: args.userCsr }) - // // if (!this.socksProxyAgent) { - // // this.createAgent() - // // } - - // // await this.registrationService.sendCertificateRegistrationRequest( - // // args.serviceAddress, - // // args.userCsr, - // // args.communityId, - // // 120_000, - // // this.socksProxyAgent - // // ) - // // const response = await this.registrationService.registerUser(args.userCsr) - // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CONNECTING_TO_COMMUNITY) + + // const registerResponse = await this.registrationService.registerUser(args.userCsr) // console.log('emitting SocketActionTypes.SEND_USER_CERTIFICATE') - // this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, { - // // TEMPORARY + // const payload: SendUserCertificatePayload = { // communityId: args.communityId, // payload: { + // certificate: registerResponse.body.certificate, // peers: [], + // rootCa: registerResponse.body.certificate, // }, - // }) + // } + // this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, payload) // }) this.socketService.on( SocketActionTypes.REGISTER_OWNER_CERTIFICATE, @@ -615,5 +593,9 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI console.log('emitting deleted channel event back to state manager') this.serverIoProvider.io.emit(SocketActionTypes.CHANNEL_DELETION_RESPONSE, payload) }) + this.storageService.on('REPLICATED_CSR', async (payload: { csr: string }) => { + console.log('ON REPLICATED_CSR') + this.registrationService.emit('REGISTER_USER_CERTIFICATE', payload.csr) + }) } } diff --git a/packages/backend/src/nest/registration/registration.functions.ts b/packages/backend/src/nest/registration/registration.functions.ts index 178682dd23..8438a9de28 100644 --- a/packages/backend/src/nest/registration/registration.functions.ts +++ b/packages/backend/src/nest/registration/registration.functions.ts @@ -205,6 +205,7 @@ export const registerUser = async ( let cert: string const userData = new UserCsrData() userData.csr = csr + console.log('USER DATA', userData) const validationErrors = await validate(userData) if (validationErrors.length > 0) { logger.error(`Received data is not valid: ${validationErrors.toString()}`) diff --git a/packages/backend/src/nest/registration/registration.service.ts b/packages/backend/src/nest/registration/registration.service.ts index 4b294c2ae5..c11d62feed 100644 --- a/packages/backend/src/nest/registration/registration.service.ts +++ b/packages/backend/src/nest/registration/registration.service.ts @@ -43,6 +43,15 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { console.log('SET CERTIFICATES', certs) this.setCertificates(certs) }) + this.on('REGISTER_USER_CERTIFICATE', async (csr: string) => { + if (!this._permsData) { + console.log('NO PERMS DATA') + return + } + console.log('CSR in registration service', csr) + const response = await this.registerUser(csr) + // this.emit('REGISTER_USER_CERTIFICATE_RESPONSE', response) + }) this.setRouting() } @@ -85,6 +94,14 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { }) } + public set permsData(perms: PermsData) { + console.log('Setting owner perms data') + this._permsData = { + certificate: perms.certificate, + privKey: perms.privKey, + } + } + public async registerOwnerCertificate(payload: RegisterOwnerCertificatePayload): Promise { let cert: string try { diff --git a/packages/backend/src/nest/socket/socket.service.ts b/packages/backend/src/nest/socket/socket.service.ts index 697972af89..56971a931e 100644 --- a/packages/backend/src/nest/socket/socket.service.ts +++ b/packages/backend/src/nest/socket/socket.service.ts @@ -132,10 +132,10 @@ export class SocketService extends EventEmitter implements OnModuleInit { this.emit(SocketActionTypes.LAUNCH_COMMUNITY, payload) this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.LAUNCHING_COMMUNITY) }) - // socket.on(SocketActionTypes.LAUNCH_REGISTRAR, async (payload: LaunchRegistrarPayload) => { - // this.logger(`Launching registrar for community ${payload.id}, user ${payload.peerId}`) - // this.emit(SocketActionTypes.LAUNCH_REGISTRAR, payload) - // }) + socket.on(SocketActionTypes.LAUNCH_REGISTRAR, async (payload: LaunchRegistrarPayload) => { + this.logger(`Launching registrar for community ${payload.id}, user ${payload.peerId}`) + this.emit(SocketActionTypes.LAUNCH_REGISTRAR, payload) + }) socket.on(SocketActionTypes.CREATE_NETWORK, async (community: Community) => { this.logger(`Creating network for community ${community.id}`) this.emit(SocketActionTypes.CREATE_NETWORK, community) diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index 7d341ce943..f29e01fd9c 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -356,22 +356,25 @@ export class StorageService extends EventEmitter { write: ['*'], }, }) - // this.certificates.events.on('replicate.progress', async (_address, _hash, entry, _progress, _total) => { - // const certificate = entry.payload.value - - // const parsedCertificate = parseCertificate(certificate) - // const key = keyFromCertificate(parsedCertificate) - - // const username = getCertFieldValue(parsedCertificate, CertFieldsTypes.nickName) - // if (!username) { - // this.logger.error( - // `Certificates replicate.progress: could not parse certificate for field type ${CertFieldsTypes.nickName}` - // ) - // return - // } + this.certificatesRequests.events.on('replicate.progress', async (_address, _hash, entry, _progress, _total) => { + const csr = entry.payload.value - // this.userNamesMap.set(key, username) - // }) + // const parsedCertificate = parseCertificationRequest(csr) + console.log('REPLICATED CSR', csr) + this.emit('REPLICATED_CSR', { csr: csr }) + + // const key = keyFromCertificate(parsedCertificate) + + // const username = getCertFieldValue(parsedCertificate, CertFieldsTypes.nickName) + // if (!username) { + // this.logger.error( + // `Certificates replicate.progress: could not parse certificate for field type ${CertFieldsTypes.nickName}` + // ) + // return + // } + + // this.userNamesMap.set(key, username) + }) this.certificatesRequests.events.on('replicated', async () => { this.logger('REPLICATED: CSRs') // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CSRS_REPLICATED) diff --git a/packages/state-manager/src/sagas/communities/communities.master.saga.ts b/packages/state-manager/src/sagas/communities/communities.master.saga.ts index ff986aed1d..d0b855879f 100644 --- a/packages/state-manager/src/sagas/communities/communities.master.saga.ts +++ b/packages/state-manager/src/sagas/communities/communities.master.saga.ts @@ -15,6 +15,6 @@ export function* communitiesMasterSaga(socket: Socket): Generator { takeEvery(communitiesActions.updateCommunity.type, updateCommunitySaga), takeEvery(connectionActions.torBootstrapped.type, initCommunities), takeEvery(communitiesActions.launchCommunity.type, launchCommunitySaga, socket), - // takeEvery(communitiesActions.launchRegistrar.type, launchRegistrarSaga, socket), + takeEvery(communitiesActions.launchRegistrar.type, launchRegistrarSaga, socket), ]) } diff --git a/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts b/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts index 32a91de270..9cc3b43e7e 100644 --- a/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts @@ -11,6 +11,7 @@ export function* launchRegistrarSaga( socket: Socket, action: PayloadAction['payload'] | undefined> ): Generator { + console.log('launchRegistrarSaga') let communityId: string | undefined = action.payload if (!communityId) { @@ -18,10 +19,12 @@ export function* launchRegistrarSaga( } const community = yield* select(communitiesSelectors.selectById(communityId)) + console.log('launchRegistrarSaga 1') if (!community?.privateKey) { console.error('Could not launch registrar, Community is lacking privateKey') return } + console.log('launchRegistrarSaga 2') if (community.CA?.rootCertString) { const identity = yield* select(identitySelectors.selectById(communityId)) if (!identity) { @@ -35,6 +38,7 @@ export function* launchRegistrarSaga( rootKeyString: community.CA.rootKeyString, privateKey: community.privateKey, } + console.log('Sending LAUNCH_REGISTRAR') yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.LAUNCH_REGISTRAR, payload)) } } diff --git a/packages/state-manager/src/sagas/identity/identity.master.saga.ts b/packages/state-manager/src/sagas/identity/identity.master.saga.ts index 5c4dc8166f..eae6529385 100644 --- a/packages/state-manager/src/sagas/identity/identity.master.saga.ts +++ b/packages/state-manager/src/sagas/identity/identity.master.saga.ts @@ -6,13 +6,15 @@ import { saveOwnerCertToDbSaga } from './saveOwnerCertToDb/saveOwnerCertToDb.sag import { registerUsernameSaga } from './registerUsername/registerUsername.saga' import { verifyJoinTimestampSaga } from './verifyJoinTimestamp/verifyJoinTimestamp.saga' import { saveUserCsrSaga } from './saveUserCsr/saveUserCsr.saga' +import { savedOwnerCertificateSaga } from './savedOwnerCertificate/savedOwnerCertificate.saga' export function* identityMasterSaga(socket: Socket): Generator { yield all([ takeEvery(identityActions.registerUsername.type, registerUsernameSaga, socket), takeEvery(identityActions.registerCertificate.type, registerCertificateSaga, socket), takeEvery(identityActions.saveOwnerCertToDb.type, saveOwnerCertToDbSaga, socket), + takeEvery(identityActions.savedOwnerCertificate.type, savedOwnerCertificateSaga, socket), takeEvery(identityActions.verifyJoinTimestamp.type, verifyJoinTimestampSaga), - takeEvery(identityActions.saveCsr.type, saveUserCsrSaga, socket), + takeEvery(identityActions.saveUserCsr.type, saveUserCsrSaga, socket), ]) } diff --git a/packages/state-manager/src/sagas/identity/identity.slice.ts b/packages/state-manager/src/sagas/identity/identity.slice.ts index ce92acab00..abecaa5f1b 100644 --- a/packages/state-manager/src/sagas/identity/identity.slice.ts +++ b/packages/state-manager/src/sagas/identity/identity.slice.ts @@ -43,7 +43,7 @@ export const identitySlice = createSlice({ }, }) }, - saveCsr: state => state, + saveUserCsr: state => state, verifyJoinTimestamp: state => state, updateJoinTimestamp: (state, action: PayloadAction) => { identityAdapter.updateOne(state.identities, { diff --git a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts index e98a7bf428..b80c60d9ed 100644 --- a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts +++ b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts @@ -31,10 +31,10 @@ export function* registerCertificateSaga( } yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, payload)) + } else { + yield* put(communitiesActions.launchCommunity(action.payload.communityId)) } - yield* put(communitiesActions.launchCommunity(action.payload.communityId)) - // else { // if (!currentCommunity.registrarUrl) { // console.error('Could not register certificate, no registrar url') diff --git a/packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts b/packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts new file mode 100644 index 0000000000..5631401ee2 --- /dev/null +++ b/packages/state-manager/src/sagas/identity/savedOwnerCertificate/savedOwnerCertificate.saga.ts @@ -0,0 +1,35 @@ +import { type Socket, applyEmitParams } from '../../../types' +import { select, apply } from 'typed-redux-saga' +import { type PayloadAction } from '@reduxjs/toolkit' +import { type identityActions } from '../identity.slice' +import { communitiesSelectors } from '../../communities/communities.selectors' +import { identitySelectors } from '../identity.selectors' +import { type InitCommunityPayload, SocketActionTypes } from '@quiet/types' + +export function* savedOwnerCertificateSaga( + socket: Socket, + action: PayloadAction['payload']> +): Generator { + let communityId: string = action.payload + + if (!communityId) { + communityId = yield* select(communitiesSelectors.currentCommunityId) + } + + const community = yield* select(communitiesSelectors.selectById(communityId)) + const identity = yield* select(identitySelectors.selectById(communityId)) + if (!identity?.userCertificate || !identity?.userCsr || !community?.rootCa) return + + const payload: InitCommunityPayload = { + id: communityId, + peerId: identity.peerId, + hiddenService: identity.hiddenService, + certs: { + certificate: identity.userCertificate, + key: identity.userCsr.userKey, + CA: [community.rootCa], + }, + } + + yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.CREATE_COMMUNITY, payload)) +} diff --git a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts index fefa4cec2a..864b531a93 100644 --- a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts +++ b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts @@ -89,7 +89,7 @@ export function subscribe(socket: Socket) { | ReturnType | ReturnType | ReturnType - | ReturnType + | ReturnType | ReturnType >(emit => { // UPDATE FOR APP @@ -165,6 +165,7 @@ export function subscribe(socket: Socket) { // Community socket.on(SocketActionTypes.NEW_COMMUNITY, (_payload: ResponseCreateCommunityPayload) => { + console.log('on SocketActionTypes.NEW_COMMUNITY') emit(identityActions.saveOwnerCertToDb()) emit(publicChannelsActions.createGeneralChannel()) }) @@ -183,8 +184,8 @@ export function subscribe(socket: Socket) { }) socket.on(SocketActionTypes.COMMUNITY, (payload: ResponseLaunchCommunityPayload) => { console.log('on SocketActionTypes.COMMUNITY') - // emit(communitiesActions.launchRegistrar(payload.id)) - emit(identityActions.saveCsr()) + emit(communitiesActions.launchRegistrar(payload.id)) + emit(identityActions.saveUserCsr()) emit(filesActions.checkForMissingFiles(payload.id)) emit(networkActions.addInitializedCommunity(payload.id)) emit(communitiesActions.clearInvitationCodes()) @@ -209,36 +210,36 @@ export function subscribe(socket: Socket) { // emit(communitiesActions.launchCommunity(payload.communityId)) }) - // socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => { - // console.log('Received SEND_USER_CERTIFICATE', payload.communityId) + socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => { + console.log('Received SEND_USER_CERTIFICATE', payload.communityId) - // // emit( - // // communitiesActions.addOwnerCertificate({ - // // communityId: payload.communityId, - // // ownerCertificate: payload.payload.ownerCert, // is it needed? Owner is just an admin now - // // }) - // // ) + emit( + communitiesActions.addOwnerCertificate({ + communityId: payload.communityId, + ownerCertificate: payload.payload.ownerCert, + }) + ) - // emit( - // communitiesActions.storePeerList({ - // communityId: payload.communityId, - // peerList: payload.payload.peers, - // }) - // ) - // // emit( - // // identityActions.storeUserCertificate({ - // // userCertificate: payload.payload.certificate, // is it needed? - // // communityId: payload.communityId, - // // }) - // // ) - // // emit( - // // communitiesActions.updateCommunity({ - // // id: payload.communityId, - // // rootCa: payload.payload.rootCa, // is it needed? - // // }) - // // ) - // emit(communitiesActions.launchCommunity(payload.communityId)) - // }) + emit( + communitiesActions.storePeerList({ + communityId: payload.communityId, + peerList: payload.payload.peers, + }) + ) + emit( + identityActions.storeUserCertificate({ + userCertificate: payload.payload.certificate, // is it needed? + communityId: payload.communityId, + }) + ) + emit( + communitiesActions.updateCommunity({ + id: payload.communityId, + rootCa: payload.payload.rootCa, // is it needed? + }) + ) + emit(communitiesActions.launchCommunity(payload.communityId)) + }) socket.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, (payload: SavedOwnerCertificatePayload) => { console.log('Received SAVED_OWNER_CERTIFICATE', payload.communityId) emit( @@ -259,6 +260,7 @@ export function subscribe(socket: Socket) { communityId: payload.communityId, }) ) + emit(identityActions.savedOwnerCertificate(payload.communityId)) }) return () => undefined }) diff --git a/packages/types/src/identity.ts b/packages/types/src/identity.ts index 2185f379ab..6c92c7bf4b 100644 --- a/packages/types/src/identity.ts +++ b/packages/types/src/identity.ts @@ -60,7 +60,7 @@ export interface RegisterCertificatePayload { export interface RegisterUserCertificatePayload { communityId: string userCsr: string - serviceAddress: string + // serviceAddress?: string } export interface PermsData { From ee55f9235295209cea861c5dc7a66a5cf5a186ae Mon Sep 17 00:00:00 2001 From: Vin Kabuki Date: Tue, 29 Aug 2023 10:23:36 +0200 Subject: [PATCH 09/28] Update own certificate on replication --- .../sagas/identity/identity.master.saga.ts | 3 ++ .../src/sagas/identity/identity.selectors.ts | 5 +++ .../updateCertificate.saga.ts | 36 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts diff --git a/packages/state-manager/src/sagas/identity/identity.master.saga.ts b/packages/state-manager/src/sagas/identity/identity.master.saga.ts index eae6529385..777b7161db 100644 --- a/packages/state-manager/src/sagas/identity/identity.master.saga.ts +++ b/packages/state-manager/src/sagas/identity/identity.master.saga.ts @@ -7,6 +7,8 @@ import { registerUsernameSaga } from './registerUsername/registerUsername.saga' import { verifyJoinTimestampSaga } from './verifyJoinTimestamp/verifyJoinTimestamp.saga' import { saveUserCsrSaga } from './saveUserCsr/saveUserCsr.saga' import { savedOwnerCertificateSaga } from './savedOwnerCertificate/savedOwnerCertificate.saga' +import { usersActions } from '../users/users.slice' +import { updateCertificateSaga } from './updateCertificate/updateCertificate.saga' export function* identityMasterSaga(socket: Socket): Generator { yield all([ @@ -16,5 +18,6 @@ export function* identityMasterSaga(socket: Socket): Generator { takeEvery(identityActions.savedOwnerCertificate.type, savedOwnerCertificateSaga, socket), takeEvery(identityActions.verifyJoinTimestamp.type, verifyJoinTimestampSaga), takeEvery(identityActions.saveUserCsr.type, saveUserCsrSaga, socket), + takeEvery(usersActions.responseSendCertificates.type, updateCertificateSaga), ]) } diff --git a/packages/state-manager/src/sagas/identity/identity.selectors.ts b/packages/state-manager/src/sagas/identity/identity.selectors.ts index 1891d9c54d..42e154d575 100644 --- a/packages/state-manager/src/sagas/identity/identity.selectors.ts +++ b/packages/state-manager/src/sagas/identity/identity.selectors.ts @@ -33,6 +33,10 @@ export const joinedCommunities = createSelector(selectCommunities, selectEntitie export const joinTimestamp = createSelector(currentIdentity, identity => identity?.joinTimestamp) +export const csr = createSelector(communitiesSelectors.currentCommunityId, selectEntities, (id, identities) => { + return identities[id]?.userCsr +}) + export const identitySelectors = { selectById, selectEntities, @@ -40,4 +44,5 @@ export const identitySelectors = { communityMembership, joinedCommunities, joinTimestamp, + csr, } diff --git a/packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts b/packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts new file mode 100644 index 0000000000..7cb46c1705 --- /dev/null +++ b/packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts @@ -0,0 +1,36 @@ +import { SendCertificatesResponse } from '@quiet/types' +import { PayloadAction } from '@reduxjs/toolkit' +import { select, call, put } from 'typed-redux-saga' +import { identitySelectors } from '../identity.selectors' +import { CertFieldsTypes, getCertFieldValue, getReqFieldValue, loadCSR, parseCertificate } from '@quiet/identity' +import { identityActions } from '../identity.slice' +import { communitiesSelectors } from '../../communities/communities.selectors' + +export function* updateCertificateSaga(action: PayloadAction): Generator { + const certificate = yield* select(identitySelectors.communityMembership) + const communityId = yield* select(communitiesSelectors.currentCommunityId) + + if (certificate) return + + const csr = yield* select(identitySelectors.csr) + + if (!csr?.userCsr) return + + const parsedCsr = yield* call(loadCSR, csr?.userCsr) + const username = getReqFieldValue(parsedCsr, CertFieldsTypes.nickName) + + const cert = action.payload.certificates.find(cert => { + const parsedCert = parseCertificate(cert) + const certUsername = getCertFieldValue(parsedCert, CertFieldsTypes.nickName) + if (certUsername === username) return cert + }) + + if (cert) { + yield* put( + identityActions.storeUserCertificate({ + userCertificate: cert, + communityId, + }) + ) + } +} From 51cbda4e89485b023fcd1e87cfe652f0fa13bbdf Mon Sep 17 00:00:00 2001 From: Emi Date: Mon, 4 Sep 2023 15:02:19 +0200 Subject: [PATCH 10/28] Cleanup --- .../connections-manager.service.ts | 36 ++-------- .../nest/registration/registration.service.ts | 2 +- .../nest/registration/registration.types.ts | 1 + .../src/nest/storage/storage.service.ts | 67 +++++++------------ .../backend/src/nest/storage/storage.types.ts | 1 + .../identity/saveUserCsr/saveUserCsr.saga.ts | 6 +- 6 files changed, 36 insertions(+), 77 deletions(-) diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index 49d1d9a377..0f62531eb0 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -336,7 +336,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI const _peerId = await peerIdFromKeys(restoredRsa.marshalPubKey(), restoredRsa.marshalPrivKey()) let peers = payload.peers - console.log('LAUNCH COMMUNITY PAYLOAD PEERS', peers) + console.log(`Launching community ${payload.id}, payload peers: ${peers}`) if (!peers || peers.length === 0) { peers = [this.libp2pService.createLibp2pAddress(onionAddress, _peerId.toString())] } @@ -385,7 +385,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI }) this.registrationService.on(SocketActionTypes.CONNECTION_PROCESS_INFO, data => { - console.log('CONNECTION_PROCESS_INFO', data) this.serverIoProvider.io.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, data) }) } @@ -394,18 +393,12 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI this.registrarState = payload }) this.registrationService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload => { - console.log('SAVED_OWNER_CERTIFICATE', payload) this.serverIoProvider.io.emit(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload) }) this.registrationService.on(RegistrationEvents.ERROR, payload => { emitError(this.serverIoProvider.io, payload) }) - // this.registrationService.on(SocketActionTypes.SEND_USER_CERTIFICATE, payload => { - // console.log('SEND_USER_CERTIFICATE', payload) - // this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, payload) - // }) this.registrationService.on(RegistrationEvents.NEW_USER, async payload => { - console.log('NEW_USER', payload) await this.storageService?.saveCertificate(payload) }) } @@ -430,11 +423,9 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI } }) this.socketService.on(SocketActionTypes.CREATE_NETWORK, async (args: Community) => { - console.log('SocketActionTypes.CREATE_NETWORK') await this.createNetwork(args) }) this.socketService.on(SocketActionTypes.CREATE_COMMUNITY, async (args: InitCommunityPayload) => { - console.log('SocketActionTypes.CREATE_COMMUNITY') await this.createCommunity(args) }) this.socketService.on(SocketActionTypes.LAUNCH_COMMUNITY, async (args: InitCommunityPayload) => { @@ -452,7 +443,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI } }) this.socketService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, async (args: SaveOwnerCertificatePayload) => { - console.log('SAVED_OWNER_CERTIFICATE') const saveCertificatePayload: SaveCertificatePayload = { certificate: args.certificate, rootPermsData: args.permsData, @@ -460,26 +450,10 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI await this.storageService?.saveCertificate(saveCertificatePayload) }) this.socketService.on(SocketActionTypes.SAVE_USER_CSR, async (payload: SaveCSRPayload) => { - console.log('SAVE_USER_CSR backend', payload) + console.log(`On ${SocketActionTypes.SAVE_USER_CSR}: ${payload.csr}`) await this.storageService?.saveCSR(payload) this.serverIoProvider.io.emit(SocketActionTypes.SAVED_USER_CSR, payload) }) - // this.socketService.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (args: RegisterUserCertificatePayload) => { - // // Change to REGISTER_USER_CSR - // console.log('!!!! REGISTER_USER_CERTIFICATE', args.userCsr) - - // const registerResponse = await this.registrationService.registerUser(args.userCsr) - // console.log('emitting SocketActionTypes.SEND_USER_CERTIFICATE') - // const payload: SendUserCertificatePayload = { - // communityId: args.communityId, - // payload: { - // certificate: registerResponse.body.certificate, - // peers: [], - // rootCa: registerResponse.body.certificate, - // }, - // } - // this.serverIoProvider.io.emit(SocketActionTypes.SEND_USER_CERTIFICATE, payload) - // }) this.socketService.on( SocketActionTypes.REGISTER_OWNER_CERTIFICATE, async (args: RegisterOwnerCertificatePayload) => { @@ -593,9 +567,9 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI console.log('emitting deleted channel event back to state manager') this.serverIoProvider.io.emit(SocketActionTypes.CHANNEL_DELETION_RESPONSE, payload) }) - this.storageService.on('REPLICATED_CSR', async (payload: { csr: string }) => { - console.log('ON REPLICATED_CSR') - this.registrationService.emit('REGISTER_USER_CERTIFICATE', payload.csr) + this.storageService.on(StorageEvents.REPLICATED_CSR, async (payload: { csr: string }) => { + console.log(`On ${StorageEvents.REPLICATED_CSR}`) + this.registrationService.emit(RegistrationEvents.REGISTER_USER_CERTIFICATE, payload.csr) }) } } diff --git a/packages/backend/src/nest/registration/registration.service.ts b/packages/backend/src/nest/registration/registration.service.ts index c11d62feed..93254a1a1c 100644 --- a/packages/backend/src/nest/registration/registration.service.ts +++ b/packages/backend/src/nest/registration/registration.service.ts @@ -43,7 +43,7 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { console.log('SET CERTIFICATES', certs) this.setCertificates(certs) }) - this.on('REGISTER_USER_CERTIFICATE', async (csr: string) => { + this.on(RegistrationEvents.REGISTER_USER_CERTIFICATE, async (csr: string) => { if (!this._permsData) { console.log('NO PERMS DATA') return diff --git a/packages/backend/src/nest/registration/registration.types.ts b/packages/backend/src/nest/registration/registration.types.ts index 62e81b59c1..dcffe9d7f9 100644 --- a/packages/backend/src/nest/registration/registration.types.ts +++ b/packages/backend/src/nest/registration/registration.types.ts @@ -4,4 +4,5 @@ export enum RegistrationEvents { NEW_USER = 'newUser', SET_CERTIFICATES = 'setCertificates', REGISTRAR_STATE = 'registrarState', + REGISTER_USER_CERTIFICATE = 'registerUserCertificate', } diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index f29e01fd9c..716790d3c7 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -17,7 +17,7 @@ import KeyValueStore from 'orbit-db-kvstore' import path from 'path' import { EventEmitter } from 'events' import PeerId from 'peer-id' -import { getCrypto } from 'pkijs' +import { CertificationRequest, getCrypto } from 'pkijs' import { stringToArrayBuffer } from 'pvutils' import validate from '../validation/validators' import { CID } from 'multiformats/cid' @@ -274,14 +274,10 @@ export class StorageService extends EventEmitter { } public async updatePeersList() { - console.log('updatePeersList') const allUsers = this.getAllUsers() - console.log('updatePeersList allUsers', allUsers) const registeredUsers = this.getAllRegisteredUsers() - console.log('updatePeersList registeredUsers', registeredUsers) const peers = [...new Set(await getUsersAddresses(allUsers.concat(registeredUsers)))] - // const peers = [...new Set(await getUsersAddresses(registeredUsers))] - console.log('updatePeersList peers', peers) + console.log('updatePeersList, peers count:', peers.length) const community = await this.localDbService.get(LocalDBKeys.COMMUNITY) this.emit(StorageEvents.UPDATE_PEERS_LIST, { communityId: community.id, peerList: peers }) } @@ -358,46 +354,34 @@ export class StorageService extends EventEmitter { }) this.certificatesRequests.events.on('replicate.progress', async (_address, _hash, entry, _progress, _total) => { const csr = entry.payload.value + this.logger('REPLICATED CSR', csr) + let parsedCSR: CertificationRequest + try { + parsedCSR = parseCertificationRequest(csr) + } catch (e) { + this.logger.error(`csrs replicate.progress: could not parse certificate request`) + return + } - // const parsedCertificate = parseCertificationRequest(csr) - console.log('REPLICATED CSR', csr) - this.emit('REPLICATED_CSR', { csr: csr }) - - // const key = keyFromCertificate(parsedCertificate) - - // const username = getCertFieldValue(parsedCertificate, CertFieldsTypes.nickName) - // if (!username) { - // this.logger.error( - // `Certificates replicate.progress: could not parse certificate for field type ${CertFieldsTypes.nickName}` - // ) - // return - // } + const username = getReqFieldValue(parsedCSR, CertFieldsTypes.nickName) + if (!username) { + this.logger.error( + `csrs replicate.progress: could not parse certificate request for field type ${CertFieldsTypes.nickName}` + ) + return + } - // this.userNamesMap.set(key, username) + this.emit(StorageEvents.REPLICATED_CSR, { csr: csr }) }) this.certificatesRequests.events.on('replicated', async () => { this.logger('REPLICATED: CSRs') - // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CSRS_REPLICATED) - // this.emit(StorageEvents.LOAD_CERTIFICATES, { - // certificates: this.getAllEventLogEntries(this.certificatesRequests), - // }) await this.updatePeersList() }) this.certificatesRequests.events.on('write', async (_address, entry) => { this.logger('Saved CSR locally') this.logger(entry.payload.value) - // this.emit(StorageEvents.LOAD_CERTIFICATES, { - // certificates: this.getAllEventLogEntries(this.certificates), - // }) await this.updatePeersList() }) - // this.certificates.events.on('ready', () => { - // this.logger('Loaded certificates to memory') - // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.LOADED_CERTIFICATES) - // this.emit(StorageEvents.LOAD_CERTIFICATES, { - // certificates: this.getAllEventLogEntries(this.certificates), - // }) - // }) // @ts-expect-error - OrbitDB's type declaration of `load` lacks 'options' await this.certificates.load({ fetchEntryTimeout: 15000 }) @@ -835,13 +819,14 @@ export class StorageService extends EventEmitter { this.logger('CSR is either null or undefined, not saving to db') return false } - // TODO: Verify CSR? - // const verification = await verifyUserCert(payload.rootPermsData.certificate, payload.certificate) - // if (verification.resultCode !== 0) { - // this.logger.error('Certificate is not valid') - // this.logger.error(verification.resultMessage) - // return false - // } + // TODO: Verify CSR + try { + parseCertificationRequest(payload.csr) + } catch (e) { + this.logger.error(`Cannot save csr ${payload.csr}. Reason: ${e.message}`) + return false + } + this.logger('Saving csr...') await this.certificatesRequests.add(payload.csr) return true diff --git a/packages/backend/src/nest/storage/storage.types.ts b/packages/backend/src/nest/storage/storage.types.ts index 617b944333..9941dddc1a 100644 --- a/packages/backend/src/nest/storage/storage.types.ts +++ b/packages/backend/src/nest/storage/storage.types.ts @@ -4,6 +4,7 @@ export enum StorageEvents { // Peers UPDATE_PEERS_LIST = 'updatePeersList', LOAD_CERTIFICATES = 'loadCertificates', + REPLICATED_CSR = 'replicatedCsr', // Public Channels LOAD_PUBLIC_CHANNELS = 'loadPublicChannels', LOAD_ALL_PRIVATE_CONVERSATIONS = 'loadAllPrivateConversations', diff --git a/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts b/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts index c01ada798d..df82b47dea 100644 --- a/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts +++ b/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts @@ -1,19 +1,17 @@ import { SaveCSRPayload, SocketActionTypes } from '@quiet/types' import { applyEmitParams, type Socket } from '../../../types' -import { PayloadAction } from '@reduxjs/toolkit' import { apply, select } from 'typed-redux-saga' import { identitySelectors } from '../identity.selectors' export function* saveUserCsrSaga(socket: Socket): Generator { - console.log('SAVE USER CSR SAGA') const identity = yield* select(identitySelectors.currentIdentity) if (!identity?.userCsr) { - console.error('saveUserCsrSaga NO IDENTITY') + console.error('Cannot save user csr, no identity') return } const payload: SaveCSRPayload = { csr: identity.userCsr?.userCsr, } - console.log('SENDING SAVE_USER_CSR') + console.log(`Send ${SocketActionTypes.SAVE_USER_CSR}`) yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.SAVE_USER_CSR, payload)) } From 61b78d832cb8be9d82462e249ce51a973cf4a804 Mon Sep 17 00:00:00 2001 From: Emi Date: Tue, 5 Sep 2023 00:42:53 +0200 Subject: [PATCH 11/28] Check if peerid and onion address are valid in deep link --- packages/common/package.json | 3 +- packages/common/src/invitationCode.test.ts | 40 ++++++++++--- packages/common/src/invitationCode.ts | 67 +++++----------------- 3 files changed, 48 insertions(+), 62 deletions(-) diff --git a/packages/common/package.json b/packages/common/package.json index f04ab5b2bb..6d211b4e02 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -28,7 +28,8 @@ "@quiet/types": "^2.0.0-alpha.0", "multiaddr": "^10.0.1", "cross-env": "^5.2.0", - "debug": "^4.3.1" + "debug": "^4.3.1", + "peer-id": "^0.16.0" }, "jest": { "transform": { diff --git a/packages/common/src/invitationCode.test.ts b/packages/common/src/invitationCode.test.ts index 6059b9c6be..e64d7cb474 100644 --- a/packages/common/src/invitationCode.test.ts +++ b/packages/common/src/invitationCode.test.ts @@ -1,11 +1,22 @@ -import { argvInvitationCode, invitationDeepUrl, invitationShareUrl, pairsToInvitationShareUrl } from './invitationCode' +import { + argvInvitationCode, + invitationDeepUrl, + invitationShareUrl, + pairsToInvitationShareUrl, + retrieveInvitationCode, +} from './invitationCode' import { Site } from './static' describe('Invitation code helper', () => { + const peerId1 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA' + const address1 = 'gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad' + const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE' + const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' + it('retrieves invitation code from argv', () => { const expectedCodes = [ - { peerId: 'peerID1', address: 'address1' }, - { peerId: 'peerID2', address: 'address2' }, + { peerId: peerId1, address: address1 }, + { peerId: peerId2, address: address2 }, ] const result = argvInvitationCode([ 'something', @@ -15,7 +26,7 @@ describe('Invitation code helper', () => { 'quiet://?param=invalid', invitationDeepUrl(expectedCodes), ]) - expect(result).toBe(expectedCodes) + expect(result).toEqual(expectedCodes) }) it('builds proper invitation deep url', () => { @@ -36,10 +47,6 @@ describe('Invitation code helper', () => { expect(pairsToInvitationShareUrl(pairs)).toEqual(expected) }) - // it('builds proper invitation share url', () => { - // expect(invitationShareUrl('validCode')).toEqual(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#validCode`) - // }) - it('builds proper invitation share url', () => { const peerList = [ '/dns4/gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad.onion/tcp/443/wss/p2p/QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', @@ -50,4 +57,21 @@ describe('Invitation code helper', () => { `https://${Site.DOMAIN}/${Site.JOIN_PAGE}#QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad&QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA=somethingElse` ) }) + + it('retrieves invitation codes from deep url', () => { + const codes = retrieveInvitationCode(`quiet://?${peerId1}=${address1}&${peerId2}=${address2}`) + expect(codes).toEqual([ + { peerId: peerId1, address: address1 }, + { peerId: peerId2, address: address2 }, + ]) + }) + + it('retrieves invitation codes from deep url with partly invalid codes', () => { + const peerId1 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA' + const address1 = 'gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad' + const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLs' + const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' + const codes = retrieveInvitationCode(`quiet://?${peerId1}=${address1}&${peerId2}=${address2}}`) + expect(codes).toEqual([{ peerId: peerId1, address: address1 }]) + }) }) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index 389e511558..650ecc9667 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -1,27 +1,8 @@ import { InvitationPair } from '@quiet/types' -import { InvitationParams, Site } from './static' +import { ONION_ADDRESS_REGEX, Site } from './static' import { multiaddr } from 'multiaddr' import { createLibp2pAddress } from './libp2p' - -// export const retrieveInvitationCode = (url: string): string => { -// /** -// * Extract invitation code from deep url. -// * Valid format: quiet://?code= -// */ -// let data: URL -// try { -// data = new URL(url) -// } catch (e) { -// return '' -// } -// if (!data || data.protocol !== 'quiet:') return '' -// const code = data.searchParams.get(InvitationParams.CODE) -// if (code) { -// console.log('Retrieved code:', code) -// return code -// } -// return '' -// } +import PeerId from 'peer-id' export const retrieveInvitationCode = (url: string): InvitationPair[] => { /** @@ -38,9 +19,14 @@ export const retrieveInvitationCode = (url: string): InvitationPair[] => { const params = data.searchParams const codes: InvitationPair[] = [] for (const [peerId, address] of params.entries()) { - // TODO: basic check if peerid and address have proper format? - if (peerId.length !== 46 || address.length !== 56) { - console.log(`peerId '${peerId}' or address ${address} is not valid`) + try { + PeerId.createFromB58String(peerId.trim()) + } catch (e) { + console.log(`PeerId ${peerId} is not valid. ${e.message}`) + continue + } + if (!address.trim().match(ONION_ADDRESS_REGEX)) { + console.log(`Onion address ${address} is not valid`) continue } codes.push({ @@ -71,15 +57,15 @@ export const invitationShareUrl = (peers: string[] = []): string => { const peerId = addr.getPeerId() const address: string = addr.nodeAddress().address if (!peerId || !address) { - console.error('NO PEER ID OR ADDRESS IN', peerAddress) + console.error(`No peerId or address in ${peerAddress}`) continue } const rawAddress = address.endsWith('.onion') ? address.split('.')[0] : address pairs.push(`${peerId}=${rawAddress}`) } - console.log('CODE', pairs.join('&')) - const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${pairs.join('&')}`) + console.log('invitationShareUrl', pairs.join('&')) + const url = new URL(`${Site.MAIN_PAGE}${Site.JOIN_PAGE}#${pairs.join('&')}`) return url.href } @@ -92,7 +78,7 @@ export const pairsToP2pAddresses = (pairs: InvitationPair[]): string[] => { } export const pairsToInvitationShareUrl = (pairs: InvitationPair[]) => { - const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}`) + const url = new URL(`${Site.MAIN_PAGE}${Site.JOIN_PAGE}`) for (const pair of pairs) { url.searchParams.append(pair.peerId, pair.address) } @@ -120,28 +106,3 @@ export const argvInvitationCode = (argv: string[]): InvitationPair[] => { } return invitationCodes } - -// export const argvInvitationCode = (argv: string[]): string => { -// /** -// * Extract invitation code from deep url if url is present in argv -// */ -// let invitationCode = '' -// for (const arg of argv) { -// invitationCode = retrieveInvitationCode(arg) -// if (invitationCode) { -// break -// } -// } -// return invitationCode -// } - -// export const invitationDeepUrl = (code = ''): string => { -// const url = new URL('quiet://') -// url.searchParams.append(InvitationParams.CODE, code) -// return url.href -// } - -// export const invitationShareUrl = (code = ''): string => { -// const url = new URL(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${code}`) -// return url.href -// } From fe1eac5e0451ee38d05295ab35b4e45f5b3fad29 Mon Sep 17 00:00:00 2001 From: Emi Date: Tue, 5 Sep 2023 01:44:26 +0200 Subject: [PATCH 12/28] Validate invitation codes format in url pasted in join screen; cleanup, fix part of the tests --- packages/common/package-lock.json | 448 +++++++++++++++++- packages/common/src/invitationCode.test.ts | 8 +- packages/common/src/invitationCode.ts | 25 +- packages/common/src/static.ts | 2 + .../JoinCommunity/JoinCommunity.test.tsx | 28 +- .../JoinCommunity/JoinCommunity.tsx | 1 - .../PerformCommunityActionComponent.tsx | 5 - .../invitationCode/invitationCode.test.ts | 19 +- .../invitationCode/invitationCode.ts | 24 +- 9 files changed, 489 insertions(+), 71 deletions(-) diff --git a/packages/common/package-lock.json b/packages/common/package-lock.json index 4f968b3904..14c4441e15 100644 --- a/packages/common/package-lock.json +++ b/packages/common/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "cross-env": "^5.2.0", "debug": "^4.3.1", - "multiaddr": "^10.0.1" + "multiaddr": "^10.0.1", + "peer-id": "^0.16.0" }, "devDependencies": { "@types/jest": "^26.0.23", @@ -1096,8 +1097,7 @@ "node_modules/@types/node": { "version": "17.0.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", - "dev": true + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -2900,8 +2900,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/is-accessor-descriptor": { "version": "1.0.0", @@ -4613,6 +4612,246 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/peer-id": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.16.0.tgz", + "integrity": "sha512-EmL7FurFUduU9m1PS9cfJ5TAuCvxKQ7DKpfx3Yj6IKWyBRtosriFuOag/l3ni/dtPgPLwiA4R9IvpL7hsDLJuQ==", + "dependencies": { + "class-is": "^1.1.0", + "libp2p-crypto": "^0.21.0", + "multiformats": "^9.4.5", + "protobufjs": "^6.10.2", + "uint8arrays": "^3.0.0" + }, + "engines": { + "node": ">=15.0.0" + } + }, + "node_modules/peer-id/node_modules/@noble/ed25519": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", + "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/peer-id/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/peer-id/node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/peer-id/node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/peer-id/node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/peer-id/node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/peer-id/node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/peer-id/node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/peer-id/node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/peer-id/node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/peer-id/node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/peer-id/node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/peer-id/node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "node_modules/peer-id/node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" + }, + "node_modules/peer-id/node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "node_modules/peer-id/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/peer-id/node_modules/iso-random-stream": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/iso-random-stream/-/iso-random-stream-2.0.2.tgz", + "integrity": "sha512-yJvs+Nnelic1L2vH2JzWvvPQFA4r7kSTnpST/+LkAQjSz0hos2oqLD+qIVi9Qk38Hoe7mNDt3j0S27R58MVjLQ==", + "dependencies": { + "events": "^3.3.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/peer-id/node_modules/libp2p-crypto": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.21.2.tgz", + "integrity": "sha512-EXFrhSpiHtJ+/L8xXDvQNK5VjUMG51u878jzZcaT5XhuN/zFg6PWJFnl/qB2Y2j7eMWnvCRP7Kp+ua2H36cG4g==", + "dependencies": { + "@noble/ed25519": "^1.5.1", + "@noble/secp256k1": "^1.3.0", + "err-code": "^3.0.1", + "iso-random-stream": "^2.0.0", + "multiformats": "^9.4.5", + "node-forge": "^1.2.1", + "protobufjs": "^6.11.2", + "uint8arrays": "^3.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/peer-id/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/peer-id/node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "node_modules/peer-id/node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/peer-id/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/peer-id/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/peer-id/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/peer-id/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/peer-id/node_modules/uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "dependencies": { + "multiformats": "^9.4.2" + } + }, + "node_modules/peer-id/node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -7250,8 +7489,7 @@ "@types/node": { "version": "17.0.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", - "dev": true + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -8635,8 +8873,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "is-accessor-descriptor": { "version": "1.0.0", @@ -9952,6 +10189,199 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "peer-id": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.16.0.tgz", + "integrity": "sha512-EmL7FurFUduU9m1PS9cfJ5TAuCvxKQ7DKpfx3Yj6IKWyBRtosriFuOag/l3ni/dtPgPLwiA4R9IvpL7hsDLJuQ==", + "requires": { + "class-is": "^1.1.0", + "libp2p-crypto": "^0.21.0", + "multiformats": "^9.4.5", + "protobufjs": "^6.10.2", + "uint8arrays": "^3.0.0" + }, + "dependencies": { + "@noble/ed25519": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", + "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==" + }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" + }, + "err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "iso-random-stream": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/iso-random-stream/-/iso-random-stream-2.0.2.tgz", + "integrity": "sha512-yJvs+Nnelic1L2vH2JzWvvPQFA4r7kSTnpST/+LkAQjSz0hos2oqLD+qIVi9Qk38Hoe7mNDt3j0S27R58MVjLQ==", + "requires": { + "events": "^3.3.0", + "readable-stream": "^3.4.0" + } + }, + "libp2p-crypto": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.21.2.tgz", + "integrity": "sha512-EXFrhSpiHtJ+/L8xXDvQNK5VjUMG51u878jzZcaT5XhuN/zFg6PWJFnl/qB2Y2j7eMWnvCRP7Kp+ua2H36cG4g==", + "requires": { + "@noble/ed25519": "^1.5.1", + "@noble/secp256k1": "^1.3.0", + "err-code": "^3.0.1", + "iso-random-stream": "^2.0.0", + "multiformats": "^9.4.5", + "node-forge": "^1.2.1", + "protobufjs": "^6.11.2", + "uint8arrays": "^3.0.0" + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "requires": { + "multiformats": "^9.4.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + } + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/packages/common/src/invitationCode.test.ts b/packages/common/src/invitationCode.test.ts index e64d7cb474..028c07d512 100644 --- a/packages/common/src/invitationCode.test.ts +++ b/packages/common/src/invitationCode.test.ts @@ -5,7 +5,7 @@ import { pairsToInvitationShareUrl, retrieveInvitationCode, } from './invitationCode' -import { Site } from './static' +import { QUIET_JOIN_PAGE } from './static' describe('Invitation code helper', () => { const peerId1 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA' @@ -43,7 +43,7 @@ describe('Invitation code helper', () => { { peerId: 'peerID1', address: 'address1' }, { peerId: 'peerID2', address: 'address2' }, ] - const expected = `https://${Site.DOMAIN}/${Site.JOIN_PAGE}#peerID1=address1&peerID2=address2` + const expected = `${QUIET_JOIN_PAGE}#peerID1=address1&peerID2=address2` expect(pairsToInvitationShareUrl(pairs)).toEqual(expected) }) @@ -54,7 +54,7 @@ describe('Invitation code helper', () => { '/dns4/somethingElse.onion/tcp/443/wss/p2p/QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA', ] expect(invitationShareUrl(peerList)).toEqual( - `https://${Site.DOMAIN}/${Site.JOIN_PAGE}#QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad&QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA=somethingElse` + `${QUIET_JOIN_PAGE}#QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad&QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA=somethingElse` ) }) @@ -67,8 +67,6 @@ describe('Invitation code helper', () => { }) it('retrieves invitation codes from deep url with partly invalid codes', () => { - const peerId1 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA' - const address1 = 'gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad' const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLs' const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' const codes = retrieveInvitationCode(`quiet://?${peerId1}=${address1}&${peerId2}=${address2}}`) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index 650ecc9667..0baee840b9 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -19,16 +19,7 @@ export const retrieveInvitationCode = (url: string): InvitationPair[] => { const params = data.searchParams const codes: InvitationPair[] = [] for (const [peerId, address] of params.entries()) { - try { - PeerId.createFromB58String(peerId.trim()) - } catch (e) { - console.log(`PeerId ${peerId} is not valid. ${e.message}`) - continue - } - if (!address.trim().match(ONION_ADDRESS_REGEX)) { - console.log(`Onion address ${address} is not valid`) - continue - } + if (!invitationCodeValid(peerId, address)) continue codes.push({ peerId, address, @@ -106,3 +97,17 @@ export const argvInvitationCode = (argv: string[]): InvitationPair[] => { } return invitationCodes } + +export const invitationCodeValid = (peerId: string, onionAddress: string): boolean => { + try { + PeerId.createFromB58String(peerId.trim()) + } catch (e) { + console.log(`PeerId ${peerId} is not valid. ${e.message}`) + return false + } + if (!onionAddress.trim().match(ONION_ADDRESS_REGEX)) { + console.log(`Onion address ${onionAddress} is not valid`) + return false + } + return true +} diff --git a/packages/common/src/static.ts b/packages/common/src/static.ts index 057018d0a7..9f7249fd22 100644 --- a/packages/common/src/static.ts +++ b/packages/common/src/static.ts @@ -9,3 +9,5 @@ export enum Site { MAIN_PAGE = 'https://tryquiet.org/', JOIN_PAGE = 'join', } + +export const QUIET_JOIN_PAGE = `${Site.MAIN_PAGE}${Site.JOIN_PAGE}` diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx index 3985a2845f..26770777a3 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx @@ -17,10 +17,11 @@ import PerformCommunityActionComponent from '../PerformCommunityActionComponent' import { inviteLinkField } from '../../../forms/fields/communityFields' import { InviteLinkErrors } from '../../../forms/fieldsErrors' import { CommunityOwnership } from '@quiet/types' -import { Site, InvitationParams } from '@quiet/common' +import { Site, InvitationParams, QUIET_JOIN_PAGE } from '@quiet/common' describe('join community', () => { - const validCode = 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad' + const validCode = + 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' it('users switches from join to create', async () => { const { store } = await prepareStore({ @@ -131,9 +132,9 @@ describe('join community', () => { }) it.each([ - [`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#${validCode}`], - [`https://${Site.DOMAIN}/${Site.JOIN_PAGE}/#${validCode}`], - [`https://${Site.DOMAIN}/${Site.JOIN_PAGE}?code=${validCode}`], // Old link format + [`${QUIET_JOIN_PAGE}#${validCode}`], + [`${QUIET_JOIN_PAGE}/#${validCode}`], + // [`${QUIET_JOIN_PAGE}?code=${validCode}`], // Old link format ])( 'joins community on submit if connection is ready and invitation code is a correct invitation url (%s)', async (invitationLink: string) => { @@ -202,20 +203,17 @@ describe('join community', () => { }) it.each([ - ['http://nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', InviteLinkErrors.InvalidCode], - ['nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2ola09bp2', InviteLinkErrors.InvalidCode], - ['nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2ola!', InviteLinkErrors.InvalidCode], - ['nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2ola ', InviteLinkErrors.InvalidCode], - ['nqnw4kc4c77fb47lk52m5l57h4tc', InviteLinkErrors.InvalidCode], - [`https://${Site.DOMAIN}/${Site.JOIN_PAGE}?${InvitationParams.CODE}=invalidcode`, InviteLinkErrors.InvalidCode], + // ['http://nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', InviteLinkErrors.InvalidCode], + // ['aaa=bbb', InviteLinkErrors.InvalidCode], + // ['nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2ola!', InviteLinkErrors.InvalidCode], + // ['nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2ola ', InviteLinkErrors.InvalidCode], + // ['nqnw4kc4c77fb47lk52m5l57h4tc', InviteLinkErrors.InvalidCode], + // [`${QUIET_JOIN_PAGE}?${InvitationParams.CODE}=invalidcode`, InviteLinkErrors.InvalidCode], [ `https://otherwebsite.com/${Site.JOIN_PAGE}?${InvitationParams.CODE}=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, InviteLinkErrors.InvalidCode, ], - [ - `https://${Site.DOMAIN}/${Site.JOIN_PAGE}?param=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, - InviteLinkErrors.InvalidCode, - ], + [`${QUIET_JOIN_PAGE}?param=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, InviteLinkErrors.InvalidCode], [ `https://${Site.DOMAIN}/share?${InvitationParams.CODE}=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, InviteLinkErrors.InvalidCode, diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx index 5abf50b036..57d97998b3 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx @@ -41,7 +41,6 @@ const JoinCommunity = () => { ownership: CommunityOwnership.User, peers: address, } - console.log('handleCommunityAction createNetwork') dispatch(communities.actions.createNetwork(payload)) } diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx index fb279728dc..b4d4ce8e72 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx @@ -188,16 +188,11 @@ export const PerformCommunityActionComponent: React.FC { + const peerId1 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA' + const address1 = 'gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad' + const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE' + const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' + it('retrieves invitation code if url is a proper share url', () => { - const result = getInvitationCodes(`https://${Site.DOMAIN}/${Site.JOIN_PAGE}#peerId1=address1&peerId2=address2`) + const result = getInvitationCodes(`${QUIET_JOIN_PAGE}#${peerId1}=${address1}&${peerId2}=${address2}`) expect(result).toEqual([ - { peerId: 'peerId1', address: 'address1' }, - { peerId: 'peerId2', address: 'address2' }, + { peerId: peerId1, address: address1 }, + { peerId: peerId2, address: address2 }, ]) }) @@ -16,10 +21,10 @@ describe('Invitation code helper', () => { }) it('retrieves invitation code if url is a proper code', () => { - const result = getInvitationCodes(`peerId1=address1&peerId2=address2`) + const result = getInvitationCodes(`${peerId1}=${address1}&${peerId2}=${address2}`) expect(result).toEqual([ - { peerId: 'peerId1', address: 'address1' }, - { peerId: 'peerId2', address: 'address2' }, + { peerId: peerId1, address: address1 }, + { peerId: peerId2, address: address2 }, ]) }) }) diff --git a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts index cd85cedd48..1706e589c6 100644 --- a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts +++ b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts @@ -1,12 +1,16 @@ -import { Site } from '@quiet/common' +import { Site, invitationCodeValid } from '@quiet/common' import { InvitationPair } from '@quiet/types' const getInvitationPairs = (code: string) => { + /** + * @param code =&= + */ const pairs = code.split('&') const codes: InvitationPair[] = [] for (const pair of pairs) { const [peerId, address] = pair.split('=') if (!peerId || !address) continue + if (!invitationCodeValid(peerId, address)) continue codes.push({ peerId: peerId, address: address, @@ -32,24 +36,6 @@ export const getInvitationCodes = (codeOrUrl: string): InvitationPair[] => { if (validUrl && validUrl.host === Site.DOMAIN && validUrl.pathname.includes(Site.JOIN_PAGE)) { const hash = validUrl.hash - // const params = validUrl.searchParams - // TODO: I don't think handling params is needed here as we only accept url with '#' and code without url - - // if (params) { - // // Type 'URLSearchParams' must have a '[Symbol.iterator]()' method that returns an iterator - // for (const [peerId, address] of params) { - // // TODO: basic check if peerid and address have proper format? - // if (peerId.length !== 46 || address.length !== 56) { - // console.log(`peerId '${peerId}' or address ${address} is not valid`) - // continue - // } - // codes.push({ - // peerId, - // address, - // }) - // } - // } - if (hash) { // Parse hash const pairs = hash.substring(1) From 56e4faf4124d522def12dbb2955ac6935274490d Mon Sep 17 00:00:00 2001 From: Emi Date: Wed, 6 Sep 2023 13:37:37 +0200 Subject: [PATCH 13/28] Cleanup --- packages/backend/src/nest/common/utils.ts | 3 +- .../connections-manager.service.ts | 5 - .../backend/src/nest/socket/socket.service.ts | 7 - packages/common/package-lock.json | 512 ++++++++---------- packages/common/package.json | 2 +- packages/common/src/invitationCode.ts | 6 +- packages/common/src/static.ts | 4 - .../JoinCommunity/JoinCommunity.test.tsx | 23 +- .../JoinCommunity/JoinCommunity.tsx | 2 +- .../PerformCommunityActionComponent.tsx | 2 + .../sagas/appConnection/connection.slice.ts | 3 +- 11 files changed, 234 insertions(+), 335 deletions(-) diff --git a/packages/backend/src/nest/common/utils.ts b/packages/backend/src/nest/common/utils.ts index f6e2901627..55e139d7ec 100644 --- a/packages/backend/src/nest/common/utils.ts +++ b/packages/backend/src/nest/common/utils.ts @@ -12,7 +12,8 @@ import { TestConfig } from '../const' import logger from './logger' import { createCertificatesTestHelper } from './client-server' import { Libp2pNodeParams } from '../libp2p/libp2p.types' -import { createLibp2pAddress, createLibp2pListenAddress } from '@quiet/common' +import { ONION_ADDRESS_REGEX, Site, createLibp2pAddress, createLibp2pListenAddress } from '@quiet/common' +import { multiaddr } from '@multiformats/multiaddr' const log = logger('test') export interface Ports { diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index 0f62531eb0..7c963e641f 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -167,11 +167,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.communityState)) return this.communityState = ServiceState.LAUNCHING } - const registrarData: LaunchRegistrarPayload = await this.localDbService.get(LocalDBKeys.REGISTRAR) // TODO: remove - if (registrarData) { - if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.registrarState)) return - this.registrarState = ServiceState.LAUNCHING - } if (community) { await this.launchCommunity(community) } diff --git a/packages/backend/src/nest/socket/socket.service.ts b/packages/backend/src/nest/socket/socket.service.ts index 56971a931e..8faecd7bc0 100644 --- a/packages/backend/src/nest/socket/socket.service.ts +++ b/packages/backend/src/nest/socket/socket.service.ts @@ -107,13 +107,6 @@ export class SocketService extends EventEmitter implements OnModuleInit { await new Promise(resolve => setTimeout(() => resolve(), 2000)) this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.SAVING_USER_CSR) }) - - // socket.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (payload: RegisterUserCertificatePayload) => { - // this.logger(`Registering user CSR (${payload.communityId}) on ${payload.serviceAddress}`) - // this.emit(SocketActionTypes.REGISTER_USER_CERTIFICATE, payload) - // await new Promise(resolve => setTimeout(() => resolve(), 2000)) - // this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE) - // }) socket.on(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, async (payload: RegisterOwnerCertificatePayload) => { this.logger(`Registering owner certificate (${payload.communityId})`) this.emit(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, payload) diff --git a/packages/common/package-lock.json b/packages/common/package-lock.json index 14c4441e15..89dd1a2d08 100644 --- a/packages/common/package-lock.json +++ b/packages/common/package-lock.json @@ -9,9 +9,9 @@ "version": "2.0.0-alpha.0", "license": "ISC", "dependencies": { + "@multiformats/multiaddr": "11.4.0", "cross-env": "^5.2.0", "debug": "^4.3.1", - "multiaddr": "^10.0.1", "peer-id": "^0.16.0" }, "devDependencies": { @@ -983,6 +983,125 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@multiformats/multiaddr": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-11.4.0.tgz", + "integrity": "sha512-rLIhSOCKQhm/fCjg+5tVM9xrtjbZjZKJg6bb65YbFsNoPSYhweEohXO8Pkg2xbRy3NqVEVkS+8DB/+VhNvjd5Q==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "dns-over-http-resolver": "^2.1.0", + "err-code": "^3.0.1", + "multiformats": "^11.0.0", + "uint8arrays": "^4.0.2", + "varint": "^6.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/@chainsafe/is-ip": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.0.2.tgz", + "integrity": "sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA==" + }, + "node_modules/@multiformats/multiaddr/node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/dns-over-http-resolver": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-2.1.2.tgz", + "integrity": "sha512-Bjbf6aZjr3HMnwGslZnoW3MJVqgbTsh39EZWpikx2yLl9xEjw4eZhlOHCFhkOu89zoWaS4rqe2Go53TXW4Byiw==", + "dependencies": { + "debug": "^4.3.1", + "native-fetch": "^4.0.2", + "receptacle": "^1.3.2", + "undici": "^5.12.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "node_modules/@multiformats/multiaddr/node_modules/multiformats": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", + "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/native-fetch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-4.0.2.tgz", + "integrity": "sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg==", + "peerDependencies": { + "undici": "*" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/receptacle": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", + "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/uint8arrays": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-4.0.6.tgz", + "integrity": "sha512-4ZesjQhqOU2Ip6GPReIwN60wRxIupavL8T0Iy36BBHr2qyMrNxsPJvr7vpS4eFt8F8kSguWUPad6ZM9izs/vyw==", + "dependencies": { + "multiformats": "^12.0.1" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/uint8arrays/node_modules/multiformats": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.1.tgz", + "integrity": "sha512-GBSToTmri2vJYs8wqcZQ8kB21dCaeTOzHTIAlr8J06C1eL6UbzqURXFZ5Fl0EYm9GAFz1IlYY8SxGOs9G9NJRg==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/undici": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz", + "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" + }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -4052,178 +4171,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/multiaddr": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.1.tgz", - "integrity": "sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg==", - "deprecated": "This module is deprecated, please upgrade to @multiformats/multiaddr", - "dependencies": { - "dns-over-http-resolver": "^1.2.3", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.4.5", - "uint8arrays": "^3.0.0", - "varint": "^6.0.0" - } - }, - "node_modules/multiaddr/node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/multiaddr/node_modules/dns-over-http-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz", - "integrity": "sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==", - "dependencies": { - "debug": "^4.3.1", - "native-fetch": "^3.0.0", - "receptacle": "^1.3.2" - } - }, - "node_modules/multiaddr/node_modules/err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, - "node_modules/multiaddr/node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "peer": true, - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/multiaddr/node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "peer": true, - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/multiaddr/node_modules/ip-regex": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/multiaddr/node_modules/is-ip": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", - "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", - "dependencies": { - "ip-regex": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/multiaddr/node_modules/multiformats": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" - }, - "node_modules/multiaddr/node_modules/native-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-3.0.0.tgz", - "integrity": "sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==", - "peerDependencies": { - "node-fetch": "*" - } - }, - "node_modules/multiaddr/node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "peer": true, - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/multiaddr/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "peer": true, - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/multiaddr/node_modules/receptacle": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", - "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/multiaddr/node_modules/uint8arrays": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", - "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", - "dependencies": { - "multiformats": "^9.4.2" - } - }, - "node_modules/multiaddr/node_modules/varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - }, - "node_modules/multiaddr/node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "peer": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -7378,6 +7325,102 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@multiformats/multiaddr": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-11.4.0.tgz", + "integrity": "sha512-rLIhSOCKQhm/fCjg+5tVM9xrtjbZjZKJg6bb65YbFsNoPSYhweEohXO8Pkg2xbRy3NqVEVkS+8DB/+VhNvjd5Q==", + "requires": { + "@chainsafe/is-ip": "^2.0.1", + "dns-over-http-resolver": "^2.1.0", + "err-code": "^3.0.1", + "multiformats": "^11.0.0", + "uint8arrays": "^4.0.2", + "varint": "^6.0.0" + }, + "dependencies": { + "@chainsafe/is-ip": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.0.2.tgz", + "integrity": "sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA==" + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, + "dns-over-http-resolver": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-2.1.2.tgz", + "integrity": "sha512-Bjbf6aZjr3HMnwGslZnoW3MJVqgbTsh39EZWpikx2yLl9xEjw4eZhlOHCFhkOu89zoWaS4rqe2Go53TXW4Byiw==", + "requires": { + "debug": "^4.3.1", + "native-fetch": "^4.0.2", + "receptacle": "^1.3.2", + "undici": "^5.12.0" + } + }, + "err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "multiformats": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", + "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==" + }, + "native-fetch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-4.0.2.tgz", + "integrity": "sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg==", + "requires": {} + }, + "receptacle": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", + "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", + "requires": { + "ms": "^2.1.1" + } + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, + "uint8arrays": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-4.0.6.tgz", + "integrity": "sha512-4ZesjQhqOU2Ip6GPReIwN60wRxIupavL8T0Iy36BBHr2qyMrNxsPJvr7vpS4eFt8F8kSguWUPad6ZM9izs/vyw==", + "requires": { + "multiformats": "^12.0.1" + }, + "dependencies": { + "multiformats": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.1.tgz", + "integrity": "sha512-GBSToTmri2vJYs8wqcZQ8kB21dCaeTOzHTIAlr8J06C1eL6UbzqURXFZ5Fl0EYm9GAFz1IlYY8SxGOs9G9NJRg==" + } + } + }, + "undici": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz", + "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==", + "requires": { + "busboy": "^1.6.0" + } + }, + "varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" + } + } + }, "@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -9761,129 +9804,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "multiaddr": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-10.0.1.tgz", - "integrity": "sha512-G5upNcGzEGuTHkzxezPrrD6CaIHR9uo+7MwqhNVcXTs33IInon4y7nMiGxl2CY5hG7chvYQUQhz5V52/Qe3cbg==", - "requires": { - "dns-over-http-resolver": "^1.2.3", - "err-code": "^3.0.1", - "is-ip": "^3.1.0", - "multiformats": "^9.4.5", - "uint8arrays": "^3.0.0", - "varint": "^6.0.0" - }, - "dependencies": { - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "peer": true - }, - "dns-over-http-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-1.2.3.tgz", - "integrity": "sha512-miDiVSI6KSNbi4SVifzO/reD8rMnxgrlnkrlkugOLQpWQTe2qMdHsZp5DmfKjxNE+/T3VAAYLQUZMv9SMr6+AA==", - "requires": { - "debug": "^4.3.1", - "native-fetch": "^3.0.0", - "receptacle": "^1.3.2" - } - }, - "err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "peer": true, - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "peer": true, - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "ip-regex": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==" - }, - "is-ip": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", - "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", - "requires": { - "ip-regex": "^4.0.0" - } - }, - "multiformats": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" - }, - "native-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-3.0.0.tgz", - "integrity": "sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw==", - "requires": {} - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "peer": true - }, - "node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "peer": true, - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, - "receptacle": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", - "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", - "requires": { - "ms": "^2.1.1" - } - }, - "uint8arrays": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", - "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", - "requires": { - "multiformats": "^9.4.2" - } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "peer": true - } - } - }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", diff --git a/packages/common/package.json b/packages/common/package.json index 6d211b4e02..367d341dda 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "@quiet/types": "^2.0.0-alpha.0", - "multiaddr": "^10.0.1", + "@multiformats/multiaddr": "11.4.0", "cross-env": "^5.2.0", "debug": "^4.3.1", "peer-id": "^0.16.0" diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index 0baee840b9..a1bb7a59cb 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -1,9 +1,8 @@ import { InvitationPair } from '@quiet/types' import { ONION_ADDRESS_REGEX, Site } from './static' -import { multiaddr } from 'multiaddr' import { createLibp2pAddress } from './libp2p' import PeerId from 'peer-id' - +// import { multiaddr } from export const retrieveInvitationCode = (url: string): InvitationPair[] => { /** * Extract invitation codes from deep url. @@ -35,11 +34,12 @@ export const invitationShareUrl = (peers: string[] = []): string => { * @returns {string} - Complete shareable invitation link, e.g. https://tryquiet.org/join/#=&= */ // Valid format: + // const mulriaddr = (await import('@multiformats/multiaddr')).default const pairs = [] for (const peerAddress of peers) { let addr try { - addr = multiaddr(peerAddress) + // addr = mulriaddr.multiaddr(peerAddress) } catch (e) { console.error(`Could not add peer address '${peerAddress}' to invitation url. Reason: ${e.message}`) continue diff --git a/packages/common/src/static.ts b/packages/common/src/static.ts index 9f7249fd22..05b1f35f0a 100644 --- a/packages/common/src/static.ts +++ b/packages/common/src/static.ts @@ -1,9 +1,5 @@ export const ONION_ADDRESS_REGEX = /^[a-z0-9]{56}$/g -export enum InvitationParams { - CODE = 'code', -} - export enum Site { DOMAIN = 'tryquiet.org', MAIN_PAGE = 'https://tryquiet.org/', diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx index 26770777a3..bfae571455 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx @@ -17,7 +17,7 @@ import PerformCommunityActionComponent from '../PerformCommunityActionComponent' import { inviteLinkField } from '../../../forms/fields/communityFields' import { InviteLinkErrors } from '../../../forms/fieldsErrors' import { CommunityOwnership } from '@quiet/types' -import { Site, InvitationParams, QUIET_JOIN_PAGE } from '@quiet/common' +import { Site, QUIET_JOIN_PAGE } from '@quiet/common' describe('join community', () => { const validCode = @@ -203,21 +203,14 @@ describe('join community', () => { }) it.each([ - // ['http://nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', InviteLinkErrors.InvalidCode], - // ['aaa=bbb', InviteLinkErrors.InvalidCode], - // ['nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2ola!', InviteLinkErrors.InvalidCode], - // ['nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2ola ', InviteLinkErrors.InvalidCode], + [`http://${validCode}`, InviteLinkErrors.InvalidCode], + // ['QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=bbb', InviteLinkErrors.InvalidCode], + // ['bbb=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', InviteLinkErrors.InvalidCode], + // ['QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE= ', InviteLinkErrors.InvalidCode], // ['nqnw4kc4c77fb47lk52m5l57h4tc', InviteLinkErrors.InvalidCode], - // [`${QUIET_JOIN_PAGE}?${InvitationParams.CODE}=invalidcode`, InviteLinkErrors.InvalidCode], - [ - `https://otherwebsite.com/${Site.JOIN_PAGE}?${InvitationParams.CODE}=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, - InviteLinkErrors.InvalidCode, - ], - [`${QUIET_JOIN_PAGE}?param=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, InviteLinkErrors.InvalidCode], - [ - `https://${Site.DOMAIN}/share?${InvitationParams.CODE}=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, - InviteLinkErrors.InvalidCode, - ], + // [`https://otherwebsite.com/${Site.JOIN_PAGE}#${validCode}`, InviteLinkErrors.InvalidCode], + // [`${QUIET_JOIN_PAGE}?param=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, InviteLinkErrors.InvalidCode], + // [`${Site.MAIN_PAGE}/share?${validCode}`, InviteLinkErrors.InvalidCode], ])('user inserting invalid url %s should see "%s" error', async (url: string, error: string) => { const handleCommunityAction = jest.fn() diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx index 57d97998b3..590c156805 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { socketSelectors } from '../../../sagas/socket/socket.selectors' -import { CommunityOwnership, CreateNetworkPayload, InvitationPair, TOR_BOOTSTRAP_COMPLETE } from '@quiet/types' +import { CommunityOwnership, CreateNetworkPayload, InvitationPair } from '@quiet/types' import { communities, identity, connection } from '@quiet/state-manager' import PerformCommunityActionComponent from '../../../components/CreateJoinCommunity/PerformCommunityActionComponent' import { ModalName } from '../../../sagas/modals/modals.types' diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx index b4d4ce8e72..9073a6484d 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx @@ -182,6 +182,7 @@ export const PerformCommunityActionComponent: React.FC void ) => { + console.log('SUBMIT FORM', communityOwnership, values.name) if (communityOwnership === CommunityOwnership.Owner) { setFormSent(true) handleSubmit(parseName(values.name)) @@ -190,6 +191,7 @@ export const PerformCommunityActionComponent: React.FC) => { const info = action.payload - console.log('----> setTorConnectionProcess', info) switch (info) { case ConnectionProcessInfo.CONNECTING_TO_COMMUNITY: state.torConnectionProcess = { number: 20, text: info } @@ -86,7 +85,7 @@ export const connectionSlice = createSlice({ state.torConnectionProcess = { number: 85, text: info } break case ConnectionProcessInfo.SAVING_USER_CSR: - state.torConnectionProcess = { number: 85, text: info } + state.torConnectionProcess = { number: 87, text: info } break case ConnectionProcessInfo.CHANNELS_REPLICATED: state.torConnectionProcess = { number: 90, text: info } From 6bb6f49a0c63af0b4e326ce04091828695592aeb Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 03:05:20 +0200 Subject: [PATCH 14/28] Add community metadata to database --- .../connections-manager.service.ts | 13 +++++ .../nest/registration/registration.service.ts | 1 - .../backend/src/nest/socket/socket.service.ts | 8 ++++ .../src/nest/storage/storage.service.ts | 47 ++++++++++++++++++- .../backend/src/nest/storage/storage.types.ts | 2 + packages/common/package.json | 1 - packages/common/src/invitationCode.ts | 22 +++++---- .../communities/communities.master.saga.ts | 2 + .../sagas/communities/communities.slice.ts | 8 +--- .../launchCommunity/launchCommunity.saga.ts | 8 ---- .../launchRegistrar/launchRegistrar.saga.ts | 3 -- .../launchCommunity.saga.ts | 25 ++++++++++ .../updateCommunity/updateCommunity.saga.ts | 2 + .../startConnection/startConnection.saga.ts | 23 ++++++--- packages/types/src/community.ts | 11 +++++ packages/types/src/socket.ts | 2 + 16 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 packages/state-manager/src/sagas/communities/saveCommunityMetadata/launchCommunity.saga.ts diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index 7c963e641f..4baec55254 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -44,6 +44,8 @@ import { PeerId as PeerIdType, SaveCSRPayload, SendUserCertificatePayload, + CommunityMetadata, + CommunityMetadataPayload, } from '@quiet/types' import { CONFIG_OPTIONS, QUIET_DIR, SERVER_IO_PROVIDER, SOCKS_PROXY_AGENT } from '../const' import { ConfigOptions, GetPorts, ServerIoProviderTypes } from '../types' @@ -437,6 +439,9 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI privKey: args.rootKeyString, } }) + this.socketService.on(SocketActionTypes.SEND_COMMUNITY_METADATA, async (payload: CommunityMetadata) => { + await this.storageService?.updateCommunityMetadata(payload) + }) this.socketService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, async (args: SaveOwnerCertificatePayload) => { const saveCertificatePayload: SaveCertificatePayload = { certificate: args.certificate, @@ -566,5 +571,13 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI console.log(`On ${StorageEvents.REPLICATED_CSR}`) this.registrationService.emit(RegistrationEvents.REGISTER_USER_CERTIFICATE, payload.csr) }) + this.storageService.on(StorageEvents.REPLICATED_COMMUNITY_METADATA, (payload: CommunityMetadata) => { + console.log(`On ${StorageEvents.REPLICATED_COMMUNITY_METADATA}: ${payload}`) + const communityMetadataPayload: CommunityMetadataPayload = { + rootCa: payload.rootCa, + ownerCertificate: payload.ownerCertificate, + } + this.serverIoProvider.io.emit(SocketActionTypes.SAVE_COMMUNITY_METADATA, communityMetadataPayload) + }) } } diff --git a/packages/backend/src/nest/registration/registration.service.ts b/packages/backend/src/nest/registration/registration.service.ts index 93254a1a1c..f3bb56d8e4 100644 --- a/packages/backend/src/nest/registration/registration.service.ts +++ b/packages/backend/src/nest/registration/registration.service.ts @@ -50,7 +50,6 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { } console.log('CSR in registration service', csr) const response = await this.registerUser(csr) - // this.emit('REGISTER_USER_CERTIFICATE_RESPONSE', response) }) this.setRouting() } diff --git a/packages/backend/src/nest/socket/socket.service.ts b/packages/backend/src/nest/socket/socket.service.ts index 8faecd7bc0..bb554a0916 100644 --- a/packages/backend/src/nest/socket/socket.service.ts +++ b/packages/backend/src/nest/socket/socket.service.ts @@ -16,6 +16,7 @@ import { Community, DeleteFilesFromChannelSocketPayload, SaveCSRPayload, + CommunityMetadata, } from '@quiet/types' import cors, { CorsOptions } from 'cors' import EventEmitter from 'events' @@ -115,6 +116,13 @@ export class SocketService extends EventEmitter implements OnModuleInit { socket.on(SocketActionTypes.SAVE_OWNER_CERTIFICATE, async (payload: SaveOwnerCertificatePayload) => { this.logger(`Saving owner certificate (${payload.peerId}), community: ${payload.id}`) this.emit(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload) + const communityMetadataPayload: CommunityMetadata = { + id: payload.id, + ownerCertificate: payload.certificate, + rootCa: payload.permsData.certificate, + } + console.log('meta from state-manager', communityMetadataPayload) + this.emit(SocketActionTypes.SEND_COMMUNITY_METADATA, communityMetadataPayload) }) socket.on(SocketActionTypes.CREATE_COMMUNITY, async (payload: InitCommunityPayload) => { this.logger(`Creating community ${payload.id}`) diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index 716790d3c7..cf46e28a82 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -23,6 +23,7 @@ import validate from '../validation/validators' import { CID } from 'multiformats/cid' import { ChannelMessage, + CommunityMetadata, ConnectionProcessInfo, DeleteFilesFromChannelSocketPayload, FileMetadata, @@ -63,6 +64,7 @@ export class StorageService extends EventEmitter { public directMessagesRepos: Map = new Map() private publicKeysMap: Map = new Map() private userNamesMap: Map = new Map() + private communityMetadata: KeyValueStore private ipfs: IPFS private orbitDb: OrbitDB private filesManager: IpfsFileManagerService @@ -157,6 +159,9 @@ export class StorageService extends EventEmitter { if (this.certificatesRequests?.address) { dbs.push(this.certificatesRequests.address) } + if (this.communityMetadata?.address) { + dbs.push(this.communityMetadata.address) + } const channels = this.publicChannelsRepos.values() @@ -217,11 +222,46 @@ export class StorageService extends EventEmitter { this.logger('3/5') await this.createDbForCertificatesRequests() this.logger('4/5') - await this.initAllChannels() + await this.createDbForCommunityMetadata() this.logger('5/5') + await this.initAllChannels() this.logger('Initialized DBs') this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.INITIALIZED_DBS) } + private async createDbForCommunityMetadata() { + this.logger('createDbForCommunityMetadata init') + this.communityMetadata = await this.orbitDb.keyvalue('community-metadata', { + replicate: false, + accessController: { + write: ['*'], + }, + }) + + this.communityMetadata.events.on('write', async (_address, _entry) => { + this.logger('WRITE: communityMetadata') + }) + + this.communityMetadata.events.on('replicated', async () => { + this.logger('Replicated community metadata') + // @ts-expect-error - OrbitDB's type declaration of `load` lacks 'options' + await this.communityMetadata.load({ fetchEntryTimeout: 15000 }) + this.emit(StorageEvents.REPLICATED_COMMUNITY_METADATA, Object.values(this.communityMetadata.all)[0]) + }) + // @ts-expect-error - OrbitDB's type declaration of `load` lacks 'options' + await this.communityMetadata.load({ fetchEntryTimeout: 15000 }) + } + + public async updateCommunityMetadata(communityMetadata: CommunityMetadata) { + this.logger(`Updating community metadata`) + if (!communityMetadata.id) return + const meta = this.communityMetadata.get(communityMetadata.id) + console.log('meta from db', meta) + if (meta?.ownerCertificate && meta?.rootCa) return + await this.communityMetadata.put(communityMetadata.id, { + ...meta, + ...communityMetadata, + }) + } private async __stopOrbitDb() { if (this.orbitDb) { @@ -269,6 +309,11 @@ export class StorageService extends EventEmitter { } catch (e) { this.logger.error('Error closing certificates db', e) } + try { + await this.communityMetadata?.close() + } catch (e) { + this.logger.error('Error closing community metadata db', e) + } await this.__stopOrbitDb() await this.__stopIPFS() } diff --git a/packages/backend/src/nest/storage/storage.types.ts b/packages/backend/src/nest/storage/storage.types.ts index 9941dddc1a..84b3286b5d 100644 --- a/packages/backend/src/nest/storage/storage.types.ts +++ b/packages/backend/src/nest/storage/storage.types.ts @@ -23,6 +23,8 @@ export enum StorageEvents { LOAD_ALL_DIRECT_MESSAGES = 'loadAllDirectMessages', // Misc SEND_PUSH_NOTIFICATION = 'sendPushNotification', + // Community + REPLICATED_COMMUNITY_METADATA = 'replicatedCommunityMetadata', } export interface InitStorageParams { communityId: string diff --git a/packages/common/package.json b/packages/common/package.json index 367d341dda..b2b28752b9 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -26,7 +26,6 @@ }, "dependencies": { "@quiet/types": "^2.0.0-alpha.0", - "@multiformats/multiaddr": "11.4.0", "cross-env": "^5.2.0", "debug": "^4.3.1", "peer-id": "^0.16.0" diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index a1bb7a59cb..643cd31d3f 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -2,7 +2,6 @@ import { InvitationPair } from '@quiet/types' import { ONION_ADDRESS_REGEX, Site } from './static' import { createLibp2pAddress } from './libp2p' import PeerId from 'peer-id' -// import { multiaddr } from export const retrieveInvitationCode = (url: string): InvitationPair[] => { /** * Extract invitation codes from deep url. @@ -33,25 +32,28 @@ export const invitationShareUrl = (peers: string[] = []): string => { * @arg {string[]} peers - List of peer's p2p addresses * @returns {string} - Complete shareable invitation link, e.g. https://tryquiet.org/join/#=&= */ - // Valid format: - // const mulriaddr = (await import('@multiformats/multiaddr')).default const pairs = [] for (const peerAddress of peers) { - let addr + let peerId: string + let onionAddress: string try { - // addr = mulriaddr.multiaddr(peerAddress) + peerId = peerAddress.split('/p2p/')[1] } catch (e) { - console.error(`Could not add peer address '${peerAddress}' to invitation url. Reason: ${e.message}`) + console.info(`Could not add peer address '${peerAddress}' to invitation url. Reason: ${e.message}`) + continue + } + try { + onionAddress = peerAddress.split('/tcp/')[0].split('/dns4/')[1] + } catch (e) { + console.info(`Could not add peer address '${peerAddress}' to invitation url. Reason: ${e.message}`) continue } - const peerId = addr.getPeerId() - const address: string = addr.nodeAddress().address - if (!peerId || !address) { + if (!peerId || !onionAddress) { console.error(`No peerId or address in ${peerAddress}`) continue } - const rawAddress = address.endsWith('.onion') ? address.split('.')[0] : address + const rawAddress = onionAddress.endsWith('.onion') ? onionAddress.split('.')[0] : onionAddress pairs.push(`${peerId}=${rawAddress}`) } diff --git a/packages/state-manager/src/sagas/communities/communities.master.saga.ts b/packages/state-manager/src/sagas/communities/communities.master.saga.ts index d0b855879f..45c87313a4 100644 --- a/packages/state-manager/src/sagas/communities/communities.master.saga.ts +++ b/packages/state-manager/src/sagas/communities/communities.master.saga.ts @@ -7,6 +7,7 @@ import { initCommunities, launchCommunitySaga } from './launchCommunity/launchCo import { launchRegistrarSaga } from './launchRegistrar/launchRegistrar.saga' import { createNetworkSaga } from './createNetwork/createNetwork.saga' import { responseCreateNetworkSaga } from './responseCreateNetwork/responseCreateNetwork.saga' +import { saveCommunityMetadataSaga } from './saveCommunityMetadata/launchCommunity.saga' export function* communitiesMasterSaga(socket: Socket): Generator { yield all([ @@ -16,5 +17,6 @@ export function* communitiesMasterSaga(socket: Socket): Generator { takeEvery(connectionActions.torBootstrapped.type, initCommunities), takeEvery(communitiesActions.launchCommunity.type, launchCommunitySaga, socket), takeEvery(communitiesActions.launchRegistrar.type, launchRegistrarSaga, socket), + takeEvery(communitiesActions.saveCommunityMetadata.type, saveCommunityMetadataSaga, socket), ]) } diff --git a/packages/state-manager/src/sagas/communities/communities.slice.ts b/packages/state-manager/src/sagas/communities/communities.slice.ts index 4d976e9e23..da7ed55693 100644 --- a/packages/state-manager/src/sagas/communities/communities.slice.ts +++ b/packages/state-manager/src/sagas/communities/communities.slice.ts @@ -11,6 +11,7 @@ import { type StorePeerListPayload, type UpdateCommunityPayload, type UpdateRegistrationAttemptsPayload, + CommunityMetadataPayload, } from '@quiet/types' export class CommunitiesState { @@ -91,12 +92,6 @@ export const communitiesSlice = createSlice({ }, }) }, - // handleInvitationCode: (state, action: PayloadAction) => { - // state.invitationCode = action.payload - // }, - // clearInvitationCode: state => { - // state.invitationCode = '' - // }, handleInvitationCodes: (state, action: PayloadAction) => { state.invitationCodes = action.payload }, @@ -115,6 +110,7 @@ export const communitiesSlice = createSlice({ }, }) }, + saveCommunityMetadata: (state, _action: PayloadAction) => state, }, }) diff --git a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts index 12e1070bb8..210669538a 100644 --- a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts @@ -29,14 +29,12 @@ export function* launchCommunitySaga( socket: Socket, action: PayloadAction['payload'] | undefined> ): Generator { - console.log('LAUNCH COMMUNITY SAGA') let communityId: string | undefined = action.payload if (!communityId) { communityId = yield* select(communitiesSelectors.currentCommunityId) } - const community = yield* select(communitiesSelectors.selectById(communityId)) const identity = yield* select(identitySelectors.selectById(communityId)) if (!identity?.userCsr?.userKey) { console.error('Could not launch community, Community or Identity is lacking data') @@ -50,17 +48,11 @@ export function* launchCommunitySaga( } else { peerList = yield* select(connectionSelectors.peerList) } - console.log('LAUNCH community peers', peerList) const payload: InitCommunityPayload = { id: identity.id, peerId: identity.peerId, hiddenService: identity.hiddenService, - // certs: { - // certificate: identity.userCertificate, - // key: identity.userCsr.userKey, - // CA: [community.rootCa], - // }, peers: peerList, } diff --git a/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts b/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts index 9cc3b43e7e..f91a9f0395 100644 --- a/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts @@ -11,7 +11,6 @@ export function* launchRegistrarSaga( socket: Socket, action: PayloadAction['payload'] | undefined> ): Generator { - console.log('launchRegistrarSaga') let communityId: string | undefined = action.payload if (!communityId) { @@ -19,12 +18,10 @@ export function* launchRegistrarSaga( } const community = yield* select(communitiesSelectors.selectById(communityId)) - console.log('launchRegistrarSaga 1') if (!community?.privateKey) { console.error('Could not launch registrar, Community is lacking privateKey') return } - console.log('launchRegistrarSaga 2') if (community.CA?.rootCertString) { const identity = yield* select(identitySelectors.selectById(communityId)) if (!identity) { diff --git a/packages/state-manager/src/sagas/communities/saveCommunityMetadata/launchCommunity.saga.ts b/packages/state-manager/src/sagas/communities/saveCommunityMetadata/launchCommunity.saga.ts new file mode 100644 index 0000000000..630b270bc0 --- /dev/null +++ b/packages/state-manager/src/sagas/communities/saveCommunityMetadata/launchCommunity.saga.ts @@ -0,0 +1,25 @@ +import { type PayloadAction } from '@reduxjs/toolkit' +import { put, select } from 'typed-redux-saga' +import { type Socket } from '../../../types' +import { communitiesSelectors } from '../communities.selectors' +import { communitiesActions } from '../communities.slice' + +export function* saveCommunityMetadataSaga( + socket: Socket, + action: PayloadAction['payload']> +): Generator { + const communityId = yield* select(communitiesSelectors.currentCommunityId) + console.log('save community metadata', action.payload) + yield* put( + communitiesActions.updateCommunity({ + id: communityId, + rootCa: action.payload.rootCa, + }) + ) + yield* put( + communitiesActions.addOwnerCertificate({ + communityId: communityId, + ownerCertificate: action.payload.ownerCertificate, + }) + ) +} diff --git a/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts b/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts index 70befbaff2..3dfc6fed9b 100644 --- a/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts +++ b/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts @@ -6,6 +6,7 @@ import { type PayloadAction } from '@reduxjs/toolkit' export function* updateCommunitySaga( action: PayloadAction['payload']> ): Generator { + console.log('updateCommunitySaga', action.payload) const rootCa = loadCertificate(action.payload.rootCa) const communityName = yield* call(getCertFieldValue, rootCa, CertFieldsTypes.commonName) @@ -19,6 +20,7 @@ export function* updateCommunitySaga( rootCa: action.payload.rootCa, name: communityName, } + console.log('updateCommunitySaga::', payload) yield* put(communitiesActions.updateCommunityData(payload)) } diff --git a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts index a645b28a60..d05331b3c8 100644 --- a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts +++ b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts @@ -43,6 +43,7 @@ import { SendUserCertificatePayload, type SendOwnerCertificatePayload, SaveCSRPayload, + CommunityMetadata, } from '@quiet/types' const log = logger('socket') @@ -90,6 +91,7 @@ export function subscribe(socket: Socket) { | ReturnType | ReturnType | ReturnType + | ReturnType >(emit => { // UPDATE FOR APP socket.on(SocketActionTypes.TOR_INITIALIZED, () => { @@ -201,11 +203,9 @@ export function subscribe(socket: Socket) { ) emit(usersActions.responseSendCertificates(payload)) }) - socket.on(SocketActionTypes.SAVED_USER_CSR, (payload: SaveCSRPayload) => { - console.log('SAVEDD USER CSR') - - // emit(communitiesActions.launchCommunity(payload.communityId)) - }) + // socket.on(SocketActionTypes.SAVED_USER_CSR, (payload: SaveCSRPayload) => { + // console.log('SAVEDD USER CSR') + // }) socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => { console.log('Received SEND_USER_CERTIFICATE', payload.communityId) @@ -224,14 +224,14 @@ export function subscribe(socket: Socket) { ) emit( identityActions.storeUserCertificate({ - userCertificate: payload.payload.certificate, // is it needed? + userCertificate: payload.payload.certificate, communityId: payload.communityId, }) ) emit( communitiesActions.updateCommunity({ id: payload.communityId, - rootCa: payload.payload.rootCa, // is it needed? + rootCa: payload.payload.rootCa, }) ) emit(communitiesActions.launchCommunity(payload.communityId)) @@ -258,6 +258,15 @@ export function subscribe(socket: Socket) { ) emit(identityActions.savedOwnerCertificate(payload.communityId)) }) + socket.on(SocketActionTypes.SAVE_COMMUNITY_METADATA, (payload: CommunityMetadata) => { + console.log('SAVE COMMUNITY METADATA', payload) + emit( + communitiesActions.saveCommunityMetadata({ + rootCa: payload.rootCa, + ownerCertificate: payload.ownerCertificate, + }) + ) + }) return () => undefined }) } diff --git a/packages/types/src/community.ts b/packages/types/src/community.ts index cb4170169c..a38096d4fb 100644 --- a/packages/types/src/community.ts +++ b/packages/types/src/community.ts @@ -103,3 +103,14 @@ export interface AddOwnerCertificatePayload { communityId: string ownerCertificate: string } + +export interface CommunityMetadata { + id: string + rootCa: string + ownerCertificate: string +} + +export interface CommunityMetadataPayload { + rootCa: string + ownerCertificate: string +} diff --git a/packages/types/src/socket.ts b/packages/types/src/socket.ts index 83e2122088..548394ede6 100644 --- a/packages/types/src/socket.ts +++ b/packages/types/src/socket.ts @@ -54,12 +54,14 @@ export enum SocketActionTypes { SAVE_OWNER_CERTIFICATE = 'saveOwnerCertificate', SAVED_OWNER_CERTIFICATE = 'savedOwnerCertificate', SAVE_USER_CSR = 'saveUserCsr', + SAVE_COMMUNITY_METADATA = 'saveCommunityMetadata', SAVED_USER_CSR = 'savedUserCsr', SEND_DIRECT_MESSAGE = 'sendDirectMessage', SEND_MESSAGE = 'sendMessage', SEND_MESSAGES_IDS = 'sendIds', SEND_PEER_ID = 'sendPeerId', SEND_USER_CERTIFICATE = 'sendUserCertificate', + SEND_COMMUNITY_METADATA = 'sendCommunityMetadata', SUBSCRIBE_FOR_ALL_CONVERSATIONS = 'subscribeToAllConversations', SUBSCRIBE_FOR_DIRECT_MESSAGE_THREAD = 'subscribeToDirectMessageThread', // T From 0928c026367ee5ee9fc5992a4bc58348ea887713 Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 03:13:49 +0200 Subject: [PATCH 15/28] Do not save same csr twice --- packages/backend/src/nest/storage/storage.service.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index cf46e28a82..2dcf2d63a9 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -872,6 +872,10 @@ export class StorageService extends EventEmitter { return false } + const csrs = this.getAllEventLogEntries(this.certificatesRequests) + + if (csrs.includes(payload.csr)) return false + this.logger('Saving csr...') await this.certificatesRequests.add(payload.csr) return true From dd11cd61b6b45f24542e107bcb601ddd498817a6 Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 13:33:35 +0200 Subject: [PATCH 16/28] Fix handleInvitationCode test; revive warning modal when no code is valid --- .../backend/src/nest/libp2p/libp2p.service.ts | 3 +- .../websocketOverTor.tor.spec.ts | 69 -------- packages/common/src/invitationCode.ts | 8 +- packages/desktop/src/main/invitation.ts | 1 - .../renderer/forms/fields/communityFields.ts | 4 - .../handleInvitationCode.saga.test.ts | 162 +++++++++--------- .../invitation/handleInvitationCode.saga.ts | 39 ++--- .../menus/InvitationContextMenu.container.tsx | 2 - .../startConnection/startConnection.saga.ts | 3 - 9 files changed, 105 insertions(+), 186 deletions(-) diff --git a/packages/backend/src/nest/libp2p/libp2p.service.ts b/packages/backend/src/nest/libp2p/libp2p.service.ts index a9e8619110..82b840ec73 100644 --- a/packages/backend/src/nest/libp2p/libp2p.service.ts +++ b/packages/backend/src/nest/libp2p/libp2p.service.ts @@ -113,13 +113,13 @@ export class Libp2pService extends EventEmitter { this.libp2pInstance.addEventListener('peer:connect', async peer => { const remotePeerId = peer.detail.remotePeer.toString() - console.log('ADDRESS', peer.detail.remoteAddr) this.logger(`${peerId.toString()} connected to ${remotePeerId}`) // Stop dialing as soon as we connect to a peer dialInChunks.stop() this.connectedPeers.set(remotePeerId, DateTime.utc().valueOf()) + this.logger(`${this.connectedPeers.size} connected peers`) this.emit(Libp2pEvents.PEER_CONNECTED, { peers: [remotePeerId], @@ -146,6 +146,7 @@ export class Libp2pService extends EventEmitter { const connectionDuration: number = connectionEndTime - connectionStartTime this.connectedPeers.delete(remotePeerId) + this.logger(`${this.connectedPeers.size} connected peers`) this.emit(Libp2pEvents.PEER_DISCONNECTED, { peer: remotePeerId, diff --git a/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts b/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts index fa18cfb8af..1ffde5daa4 100644 --- a/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts +++ b/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts @@ -278,73 +278,4 @@ describe('websocketOverTor', () => { }) ).rejects.toBeTruthy() }) - - it.skip('rejects connection if server cert is invalid', async () => { - const pems = await createCertificatesTestHelper(`${service1.onionAddress}`, `${service2.onionAddress}`) - const anotherPems = await createCertificatesTestHelper(`${service1.onionAddress}`, `${service2.onionAddress}`) - - const prepareListenerArg: CreateListenerOptions = { - handler: x => x, - upgrader: { - // @ts-expect-error - upgradeOutbound, - // @ts-expect-error - upgradeInbound, - }, - } - - const signal: AbortSignal = { - ...abortSignalOpts, - addEventListener, - removeEventListener, - } - - const peerId1 = 'Qme5NiSQ6V3cc3nyfYVtkkXDPGBSYEVUNCN5sM4DbyYc7s' - const peerId2 = 'QmeCWxba5Yk1ZAKogQJsaHXoAermE7PgFZqpqyKNg65cSN' - - const websocketsOverTorData1 = { - filter: all, - websocket: { - agent, - cert: anotherPems.servCert, - key: anotherPems.servKey, - ca: [pems.ca], - }, - localAddress: createLibp2pAddress(service1.onionAddress, peerId1), - targetPort: port1Target, - createServer, - } - - const websocketsOverTorData2 = { - filter: all, - websocket: { - agent, - cert: pems.servCert, - key: pems.servKey, - ca: [pems.ca], - }, - localAddress: createLibp2pAddress(service2.onionAddress, peerId2), - targetPort: port2Target, - createServer, - } - - const multiAddress = multiaddr(createLibp2pAddress(service1.onionAddress, peerId1)) - - const ws1 = webSockets(websocketsOverTorData1)() - const ws2 = webSockets(websocketsOverTorData2)() - - listener = await ws1.prepareListener(prepareListenerArg) - - await listener.listen(multiAddress) - - const onConnection = jest.fn() - listener.on('connection', onConnection) - - await expect( - ws2.dial(multiAddress, { - signal, - upgrader: prepareListenerArg.upgrader, - }) - ).rejects.toBeTruthy() - }) }) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index 643cd31d3f..a6aa3a9787 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -1,7 +1,6 @@ import { InvitationPair } from '@quiet/types' import { ONION_ADDRESS_REGEX, Site } from './static' import { createLibp2pAddress } from './libp2p' -import PeerId from 'peer-id' export const retrieveInvitationCode = (url: string): InvitationPair[] => { /** * Extract invitation codes from deep url. @@ -101,10 +100,9 @@ export const argvInvitationCode = (argv: string[]): InvitationPair[] => { } export const invitationCodeValid = (peerId: string, onionAddress: string): boolean => { - try { - PeerId.createFromB58String(peerId.trim()) - } catch (e) { - console.log(`PeerId ${peerId} is not valid. ${e.message}`) + if (!peerId.match(/^[a-zA-Z0-9]{46}$/g)) { + // TODO: test it more properly e.g with PeerId.createFromB58String(peerId.trim()) + console.log(`PeerId ${peerId} is not valid`) return false } if (!onionAddress.trim().match(ONION_ADDRESS_REGEX)) { diff --git a/packages/desktop/src/main/invitation.ts b/packages/desktop/src/main/invitation.ts index 59ac09262c..00f5c097bd 100644 --- a/packages/desktop/src/main/invitation.ts +++ b/packages/desktop/src/main/invitation.ts @@ -6,7 +6,6 @@ import { BrowserWindow } from 'electron' import { InvitationPair } from '@quiet/types' export const processInvitationCode = (mainWindow: BrowserWindow, codes: InvitationPair[]) => { - if (codes.length === 0) return mainWindow.webContents.send('invitation', { codes, }) diff --git a/packages/desktop/src/renderer/forms/fields/communityFields.ts b/packages/desktop/src/renderer/forms/fields/communityFields.ts index 9a1f8e31fb..7d048a35ff 100644 --- a/packages/desktop/src/renderer/forms/fields/communityFields.ts +++ b/packages/desktop/src/renderer/forms/fields/communityFields.ts @@ -36,10 +36,6 @@ export const inviteLinkField = (name = 'name'): FieldData => { }, validation: { required: FieldErrors.Required, - // pattern: { - // // value: /^[a-z0-9:/.#?= ]+$/g, - // message: InviteLinkErrors.InvalidCode, - // }, }, } } diff --git a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts index 82cd8afd50..a98bf1d5e1 100644 --- a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts +++ b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts @@ -1,87 +1,91 @@ -// import { communities, getFactory, Store } from '@quiet/state-manager' -// import { Community, CommunityOwnership, CreateNetworkPayload } from '@quiet/types' -// import { FactoryGirl } from 'factory-girl' -// import { expectSaga } from 'redux-saga-test-plan' -// import { handleInvitationCodeSaga } from './handleInvitationCode.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 { communities, getFactory, Store } from '@quiet/state-manager' +import { Community, CommunityOwnership, CreateNetworkPayload, InvitationPair } from '@quiet/types' +import { FactoryGirl } from 'factory-girl' +import { expectSaga } from 'redux-saga-test-plan' +import { handleInvitationCodeSaga } from './handleInvitationCode.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' -// describe('Handle invitation code', () => { -// let store: Store -// let factory: FactoryGirl -// let community: Community -// let validInvitationCode: string +describe('Handle invitation code', () => { + let store: Store + let factory: FactoryGirl + let community: Community + let validInvitationPair: InvitationPair[] -// beforeEach(async () => { -// store = ( -// await prepareStore({ -// [StoreKeys.Socket]: { -// ...new SocketState(), -// isConnected: true, -// }, -// }) -// ).store + beforeEach(async () => { + store = ( + await prepareStore({ + [StoreKeys.Socket]: { + ...new SocketState(), + isConnected: true, + }, + }) + ).store -// factory = await getFactory(store) -// validInvitationCode = 'bb5wacaftixjl3yhq2cp3ls2ife2e5wlwct3hjlb4lyk4iniypmgozyd' -// }) + factory = await getFactory(store) + validInvitationPair = [ + { + address: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + }, + ] + }) -// it('creates network if code is valid', async () => { -// const payload: CreateNetworkPayload = { -// ownership: CommunityOwnership.User, -// registrar: validInvitationCode, -// } -// await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(validInvitationCode)) -// .withState(store.getState()) -// .put(communities.actions.createNetwork(payload)) -// .run() -// }) + it('creates network if code is valid', async () => { + const payload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + peers: validInvitationPair, + } + await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCodes(validInvitationPair)) + .withState(store.getState()) + .put(communities.actions.createNetwork(payload)) + .run() + }) -// it('does not try to create network if user is already in community', async () => { -// community = await factory.create['payload']>('Community') -// const payload: CreateNetworkPayload = { -// ownership: CommunityOwnership.User, -// registrar: validInvitationCode, -// } + it('does not try to create network if user is already in community', async () => { + community = await factory.create['payload']>('Community') + const payload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + peers: validInvitationPair, + } -// await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(validInvitationCode)) -// .withState(store.getState()) -// .put( -// modalsActions.openModal({ -// name: ModalName.warningModal, -// args: { -// title: 'You already belong to a community', -// subtitle: "We're sorry but for now you can only be a member of a single community at a time.", -// }, -// }) -// ) -// .not.put(communities.actions.createNetwork(payload)) -// .run() -// }) + await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCodes(validInvitationPair)) + .withState(store.getState()) + .put( + modalsActions.openModal({ + name: ModalName.warningModal, + args: { + title: 'You already belong to a community', + subtitle: "We're sorry but for now you can only be a member of a single community at a time.", + }, + }) + ) + .not.put(communities.actions.createNetwork(payload)) + .run() + }) -// it('does not try to create network if code is invalid', async () => { -// const code = 'invalid' -// const payload: CreateNetworkPayload = { -// ownership: CommunityOwnership.User, -// peers: code, -// } + it('does not try to create network if code is invalid', async () => { + const payload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + peers: [], + } -// await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCode(code)) -// .withState(store.getState()) -// .put(communities.actions.clearInvitationCode()) -// .put( -// modalsActions.openModal({ -// name: ModalName.warningModal, -// args: { -// title: 'Invalid link', -// subtitle: 'The invite link you received is not valid. Please check it and try again.', -// }, -// }) -// ) -// .not.put(communities.actions.createNetwork(payload)) -// .run() -// }) -// }) + await expectSaga(handleInvitationCodeSaga, communities.actions.handleInvitationCodes([])) + .withState(store.getState()) + .put(communities.actions.clearInvitationCodes()) + .put( + modalsActions.openModal({ + name: ModalName.warningModal, + args: { + title: 'Invalid link', + subtitle: 'The invite link you received is not valid. Please check it and try again.', + }, + }) + ) + .not.put(communities.actions.createNetwork(payload)) + .run() + }) +}) diff --git a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts index 2f542068a2..a43c71a988 100644 --- a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts +++ b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.ts @@ -31,27 +31,22 @@ export function* handleInvitationCodeSaga( return } - // const code = action.payload.trim() - - // if (code.match(ONION_ADDRESS_REGEX)) { - const payload: CreateNetworkPayload = { - ownership: CommunityOwnership.User, - peers: action.payload, + if (action.payload.length > 0) { + const payload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + peers: action.payload, + } + yield* put(communities.actions.createNetwork(payload)) + } else { + yield* put(communities.actions.clearInvitationCodes()) + yield* put( + modalsActions.openModal({ + name: ModalName.warningModal, + args: { + title: 'Invalid link', + subtitle: 'The invite link you received is not valid. Please check it and try again.', + }, + }) + ) } - yield* put(communities.actions.createNetwork(payload)) - // return - // } - - // TODO: handle invalid code - // yield* put(communities.actions.clearInvitationCodes()) - - // yield* put( - // modalsActions.openModal({ - // name: ModalName.warningModal, - // args: { - // title: 'Invalid link', - // subtitle: 'The invite link you received is not valid. Please check it and try again.', - // }, - // }) - // ) } diff --git a/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx b/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx index 19b5398145..c092fbc895 100644 --- a/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx +++ b/packages/mobile/src/components/ContextMenu/menus/InvitationContextMenu.container.tsx @@ -21,8 +21,6 @@ export const InvitationContextMenu: FC = () => { const dispatch = useDispatch() const screen = useSelector(navigationSelectors.currentScreen) - - // const community = useSelector(communities.selectors.currentCommunity) const invitationLink = useSelector(communities.selectors.invitationUrl) const invitationContextMenu = useContextMenu(MenuName.Invitation) diff --git a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts index d05331b3c8..a8cd03748e 100644 --- a/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts +++ b/packages/state-manager/src/sagas/socket/startConnection/startConnection.saga.ts @@ -203,9 +203,6 @@ export function subscribe(socket: Socket) { ) emit(usersActions.responseSendCertificates(payload)) }) - // socket.on(SocketActionTypes.SAVED_USER_CSR, (payload: SaveCSRPayload) => { - // console.log('SAVEDD USER CSR') - // }) socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => { console.log('Received SEND_USER_CERTIFICATE', payload.communityId) From f1fe68049b797bdaf63efe370f15f3383fc9a18a Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 14:11:40 +0200 Subject: [PATCH 17/28] Temporarly do not show "invitation code invalid" modal Remove unused fields from Libp2pNodeParams type Cleanup --- packages/backend/src/nest/common/utils.ts | 3 --- packages/backend/src/nest/libp2p/libp2p.service.ts | 1 - packages/backend/src/nest/libp2p/libp2p.types.ts | 3 --- .../nest/registration/registration.functions.ts | 1 - .../backend/src/nest/storage/storage.service.ts | 2 -- packages/desktop/src/main/invitation.ts | 4 ++++ packages/desktop/src/main/main.ts | 1 + .../JoinCommunity/JoinCommunity.test.tsx | 14 +++++++------- .../PerformCommunityActionComponent.tsx | 2 -- .../components/CreateUsername/CreateUsername.tsx | 2 -- .../registerUsername/registerUsername.saga.ts | 1 - 11 files changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/backend/src/nest/common/utils.ts b/packages/backend/src/nest/common/utils.ts index f6e2901627..0e271922b1 100644 --- a/packages/backend/src/nest/common/utils.ts +++ b/packages/backend/src/nest/common/utils.ts @@ -201,9 +201,6 @@ export const libp2pInstanceParams = async (): Promise => { listenAddresses: [createLibp2pListenAddress('localhost')], agent: createHttpsProxyAgent({ port: 1234, host: 'localhost' }), localAddress: createLibp2pAddress('localhost', peerId.toString()), - cert: pems.userCert, - key: pems.userKey, - ca: [pems.ca], targetPort: port, peers: [remoteAddress], } diff --git a/packages/backend/src/nest/libp2p/libp2p.service.ts b/packages/backend/src/nest/libp2p/libp2p.service.ts index 82b840ec73..311b8f2b47 100644 --- a/packages/backend/src/nest/libp2p/libp2p.service.ts +++ b/packages/backend/src/nest/libp2p/libp2p.service.ts @@ -45,7 +45,6 @@ export class Libp2pService extends EventEmitter { } public async createInstance(params: Libp2pNodeParams): Promise { - console.log('Libp2p.createInstance::: peers:::', params.peers) if (this.libp2pInstance) { return this.libp2pInstance } diff --git a/packages/backend/src/nest/libp2p/libp2p.types.ts b/packages/backend/src/nest/libp2p/libp2p.types.ts index b8bd0f95a7..d32cc0230f 100644 --- a/packages/backend/src/nest/libp2p/libp2p.types.ts +++ b/packages/backend/src/nest/libp2p/libp2p.types.ts @@ -11,9 +11,6 @@ export interface Libp2pNodeParams { peerId: any listenAddresses: string[] agent: Agent - cert?: string - key?: string - ca?: string[] localAddress: string targetPort: number peers: string[] diff --git a/packages/backend/src/nest/registration/registration.functions.ts b/packages/backend/src/nest/registration/registration.functions.ts index 8438a9de28..178682dd23 100644 --- a/packages/backend/src/nest/registration/registration.functions.ts +++ b/packages/backend/src/nest/registration/registration.functions.ts @@ -205,7 +205,6 @@ export const registerUser = async ( let cert: string const userData = new UserCsrData() userData.csr = csr - console.log('USER DATA', userData) const validationErrors = await validate(userData) if (validationErrors.length > 0) { logger.error(`Received data is not valid: ${validationErrors.toString()}`) diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index 2dcf2d63a9..0742523494 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -424,7 +424,6 @@ export class StorageService extends EventEmitter { }) this.certificatesRequests.events.on('write', async (_address, entry) => { this.logger('Saved CSR locally') - this.logger(entry.payload.value) await this.updatePeersList() }) @@ -906,7 +905,6 @@ export class StorageService extends EventEmitter { const peerId = getReqFieldValue(parsedCert, CertFieldsTypes.peerId) const username = getReqFieldValue(parsedCert, CertFieldsTypes.nickName) const dmPublicKey = getReqFieldValue(parsedCert, CertFieldsTypes.dmPublicKey) - console.log('DATA', onionAddress, peerId, username) if (!onionAddress || !peerId || !username || !dmPublicKey) continue allUsers.push({ onionAddress, peerId, username, dmPublicKey }) } diff --git a/packages/desktop/src/main/invitation.ts b/packages/desktop/src/main/invitation.ts index 00f5c097bd..39bf432962 100644 --- a/packages/desktop/src/main/invitation.ts +++ b/packages/desktop/src/main/invitation.ts @@ -6,6 +6,10 @@ import { BrowserWindow } from 'electron' import { InvitationPair } from '@quiet/types' export const processInvitationCode = (mainWindow: BrowserWindow, codes: InvitationPair[]) => { + if (codes.length === 0) { + console.log('No valid invitation codes, not processing') + return + } mainWindow.webContents.send('invitation', { codes, }) diff --git a/packages/desktop/src/main/main.ts b/packages/desktop/src/main/main.ts index b8c20310f4..fe0c6fbd29 100644 --- a/packages/desktop/src/main/main.ts +++ b/packages/desktop/src/main/main.ts @@ -470,6 +470,7 @@ app.on('ready', async () => { mainWindow.webContents.once('did-finish-load', async () => { log('Event: mainWindow did-finish-load') + log('---', process.argv, 'asdasd', invitationUrl) if (!isBrowserWindow(mainWindow)) { throw new Error(`mainWindow is on unexpected type ${mainWindow}`) } diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx index bfae571455..3f9757af0e 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx @@ -204,13 +204,13 @@ describe('join community', () => { it.each([ [`http://${validCode}`, InviteLinkErrors.InvalidCode], - // ['QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=bbb', InviteLinkErrors.InvalidCode], - // ['bbb=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', InviteLinkErrors.InvalidCode], - // ['QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE= ', InviteLinkErrors.InvalidCode], - // ['nqnw4kc4c77fb47lk52m5l57h4tc', InviteLinkErrors.InvalidCode], - // [`https://otherwebsite.com/${Site.JOIN_PAGE}#${validCode}`, InviteLinkErrors.InvalidCode], - // [`${QUIET_JOIN_PAGE}?param=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, InviteLinkErrors.InvalidCode], - // [`${Site.MAIN_PAGE}/share?${validCode}`, InviteLinkErrors.InvalidCode], + ['QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=bbb', InviteLinkErrors.InvalidCode], + ['bbb=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', InviteLinkErrors.InvalidCode], + ['QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE= ', InviteLinkErrors.InvalidCode], + ['nqnw4kc4c77fb47lk52m5l57h4tc', InviteLinkErrors.InvalidCode], + [`https://otherwebsite.com/${Site.JOIN_PAGE}#${validCode}`, InviteLinkErrors.InvalidCode], + [`${QUIET_JOIN_PAGE}?param=nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad`, InviteLinkErrors.InvalidCode], + [`${Site.MAIN_PAGE}/share?${validCode}`, InviteLinkErrors.InvalidCode], ])('user inserting invalid url %s should see "%s" error', async (url: string, error: string) => { const handleCommunityAction = jest.fn() diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx index e91cc4a470..ead282576a 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx @@ -183,7 +183,6 @@ export const PerformCommunityActionComponent: React.FC void ) => { - console.log('SUBMIT FORM', communityOwnership, values.name) if (communityOwnership === CommunityOwnership.Owner) { setFormSent(true) handleSubmit(parseName(values.name)) @@ -192,7 +191,6 @@ export const PerformCommunityActionComponent: React.FC { useEffect(() => { if (currentCommunity && !currentIdentity?.userCsr && !createUsernameModal.open) { - console.log('createUsernameModal.handleOpen()') createUsernameModal.handleOpen() } if (currentIdentity?.userCsr && createUsernameModal.open) { - console.log('createUsernameModal.handleClose()') createUsernameModal.handleClose() } }, [currentIdentity, currentCommunity]) diff --git a/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts b/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts index 19b48ba03c..8fcf1fbc54 100644 --- a/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts +++ b/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts @@ -60,7 +60,6 @@ export function* registerUsernameSaga(socket: Socket, action: PayloadAction Date: Thu, 7 Sep 2023 14:23:07 +0200 Subject: [PATCH 18/28] Rename address -> onionAddress in InvitationPair type --- packages/common/src/invitationCode.test.ts | 18 +++++++++--------- packages/common/src/invitationCode.ts | 12 ++++++------ packages/desktop/src/main/main.ts | 1 - .../createNetwork/createNetwork.saga.test.ts | 2 +- .../invitationCode/invitationCode.test.ts | 8 ++++---- .../functions/invitationCode/invitationCode.ts | 2 +- packages/types/src/network.ts | 2 +- 7 files changed, 22 insertions(+), 23 deletions(-) diff --git a/packages/common/src/invitationCode.test.ts b/packages/common/src/invitationCode.test.ts index 028c07d512..28254563bc 100644 --- a/packages/common/src/invitationCode.test.ts +++ b/packages/common/src/invitationCode.test.ts @@ -15,8 +15,8 @@ describe('Invitation code helper', () => { it('retrieves invitation code from argv', () => { const expectedCodes = [ - { peerId: peerId1, address: address1 }, - { peerId: peerId2, address: address2 }, + { peerId: peerId1, onionAddress: address1 }, + { peerId: peerId2, onionAddress: address2 }, ] const result = argvInvitationCode([ 'something', @@ -32,16 +32,16 @@ describe('Invitation code helper', () => { it('builds proper invitation deep url', () => { expect( invitationDeepUrl([ - { peerId: 'peerID1', address: 'address1' }, - { peerId: 'peerID2', address: 'address2' }, + { peerId: 'peerID1', onionAddress: 'address1' }, + { peerId: 'peerID2', onionAddress: 'address2' }, ]) ).toEqual('quiet://?peerID1=address1&peerID2=address2') }) it('creates invitation share url based on invitation pairs', () => { const pairs = [ - { peerId: 'peerID1', address: 'address1' }, - { peerId: 'peerID2', address: 'address2' }, + { peerId: 'peerID1', onionAddress: 'address1' }, + { peerId: 'peerID2', onionAddress: 'address2' }, ] const expected = `${QUIET_JOIN_PAGE}#peerID1=address1&peerID2=address2` expect(pairsToInvitationShareUrl(pairs)).toEqual(expected) @@ -61,8 +61,8 @@ describe('Invitation code helper', () => { it('retrieves invitation codes from deep url', () => { const codes = retrieveInvitationCode(`quiet://?${peerId1}=${address1}&${peerId2}=${address2}`) expect(codes).toEqual([ - { peerId: peerId1, address: address1 }, - { peerId: peerId2, address: address2 }, + { peerId: peerId1, onionAddress: address1 }, + { peerId: peerId2, onionAddress: address2 }, ]) }) @@ -70,6 +70,6 @@ describe('Invitation code helper', () => { const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLs' const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' const codes = retrieveInvitationCode(`quiet://?${peerId1}=${address1}&${peerId2}=${address2}}`) - expect(codes).toEqual([{ peerId: peerId1, address: address1 }]) + expect(codes).toEqual([{ peerId: peerId1, onionAddress: address1 }]) }) }) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index a6aa3a9787..e998446d9d 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -15,11 +15,11 @@ export const retrieveInvitationCode = (url: string): InvitationPair[] => { if (!data || data.protocol !== 'quiet:') return [] const params = data.searchParams const codes: InvitationPair[] = [] - for (const [peerId, address] of params.entries()) { - if (!invitationCodeValid(peerId, address)) continue + for (const [peerId, onionAddress] of params.entries()) { + if (!invitationCodeValid(peerId, onionAddress)) continue codes.push({ peerId, - address, + onionAddress, }) } console.log('Retrieved codes:', codes) @@ -64,7 +64,7 @@ export const invitationShareUrl = (peers: string[] = []): string => { export const pairsToP2pAddresses = (pairs: InvitationPair[]): string[] => { const addresses: string[] = [] for (const pair of pairs) { - addresses.push(createLibp2pAddress(pair.address, pair.peerId)) + addresses.push(createLibp2pAddress(pair.onionAddress, pair.peerId)) } return addresses } @@ -72,7 +72,7 @@ export const pairsToP2pAddresses = (pairs: InvitationPair[]): string[] => { export const pairsToInvitationShareUrl = (pairs: InvitationPair[]) => { const url = new URL(`${Site.MAIN_PAGE}${Site.JOIN_PAGE}`) for (const pair of pairs) { - url.searchParams.append(pair.peerId, pair.address) + url.searchParams.append(pair.peerId, pair.onionAddress) } return url.href.replace('?', '#') } @@ -80,7 +80,7 @@ export const pairsToInvitationShareUrl = (pairs: InvitationPair[]) => { export const invitationDeepUrl = (pairs: InvitationPair[] = []): string => { const url = new URL('quiet://') for (const pair of pairs) { - url.searchParams.append(pair.peerId, pair.address) + url.searchParams.append(pair.peerId, pair.onionAddress) } return url.href } diff --git a/packages/desktop/src/main/main.ts b/packages/desktop/src/main/main.ts index fe0c6fbd29..b8c20310f4 100644 --- a/packages/desktop/src/main/main.ts +++ b/packages/desktop/src/main/main.ts @@ -470,7 +470,6 @@ app.on('ready', async () => { mainWindow.webContents.once('did-finish-load', async () => { log('Event: mainWindow did-finish-load') - log('---', process.argv, 'asdasd', invitationUrl) if (!isBrowserWindow(mainWindow)) { throw new Error(`mainWindow is on unexpected type ${mainWindow}`) } diff --git a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts index c23dd92a7f..6e8bf52fe0 100644 --- a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts +++ b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.test.ts @@ -28,7 +28,7 @@ describe('createNetwork', () => { createNetworkSaga, communitiesActions.createNetwork({ ownership: CommunityOwnership.User, - peers: [{ peerId: 'peerId', address: 'address' }], + peers: [{ peerId: 'peerId', onionAddress: 'address' }], }) ) .withReducer(reducer) diff --git a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts index f79bf08445..1d3860c69f 100644 --- a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts +++ b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts @@ -10,8 +10,8 @@ describe('Invitation code helper', () => { it('retrieves invitation code if url is a proper share url', () => { const result = getInvitationCodes(`${QUIET_JOIN_PAGE}#${peerId1}=${address1}&${peerId2}=${address2}`) expect(result).toEqual([ - { peerId: peerId1, address: address1 }, - { peerId: peerId2, address: address2 }, + { peerId: peerId1, onionAddress: address1 }, + { peerId: peerId2, onionAddress: address2 }, ]) }) @@ -23,8 +23,8 @@ describe('Invitation code helper', () => { it('retrieves invitation code if url is a proper code', () => { const result = getInvitationCodes(`${peerId1}=${address1}&${peerId2}=${address2}`) expect(result).toEqual([ - { peerId: peerId1, address: address1 }, - { peerId: peerId2, address: address2 }, + { peerId: peerId1, onionAddress: address1 }, + { peerId: peerId2, onionAddress: address2 }, ]) }) }) diff --git a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts index 1706e589c6..9b1e6debc1 100644 --- a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts +++ b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts @@ -13,7 +13,7 @@ const getInvitationPairs = (code: string) => { if (!invitationCodeValid(peerId, address)) continue codes.push({ peerId: peerId, - address: address, + onionAddress: address, }) } return codes diff --git a/packages/types/src/network.ts b/packages/types/src/network.ts index beb1058ac9..c92e0c5fa1 100644 --- a/packages/types/src/network.ts +++ b/packages/types/src/network.ts @@ -5,5 +5,5 @@ export enum LoadingPanelType { export type InvitationPair = { peerId: string - address: string + onionAddress: string } From 985278d0cbed59abe22810f576dee828e96c6adb Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 14:48:54 +0200 Subject: [PATCH 19/28] Cleanup --- packages/common/src/invitationCode.ts | 1 + .../JoinCommunity/JoinCommunity.test.tsx | 14 +++++----- .../communities/communities.selectors.test.ts | 27 ------------------- .../communities/communities.selectors.ts | 11 -------- .../createNetwork/createNetwork.saga.ts | 8 +----- .../launchCommunity/launchCommunity.saga.ts | 2 +- .../launchRegistrar/launchRegistrar.saga.ts | 1 - .../updateCommunity/updateCommunity.saga.ts | 2 -- .../src/sagas/identity/identity.slice.ts | 1 - .../registerCertificate.saga.ts | 14 ---------- .../identity/saveUserCsr/saveUserCsr.saga.ts | 2 +- .../updateCertificate.saga.ts | 6 ++--- .../messages/sendMessage/sendMessage.saga.ts | 2 +- packages/types/src/identity.ts | 1 - 14 files changed, 16 insertions(+), 76 deletions(-) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index e998446d9d..3949dedfb8 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -31,6 +31,7 @@ export const invitationShareUrl = (peers: string[] = []): string => { * @arg {string[]} peers - List of peer's p2p addresses * @returns {string} - Complete shareable invitation link, e.g. https://tryquiet.org/join/#=&= */ + console.log('Invitation share url, peers:', peers) const pairs = [] for (const peerAddress of peers) { let peerId: string diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx index 3f9757af0e..1e46199714 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx @@ -22,6 +22,12 @@ import { Site, QUIET_JOIN_PAGE } from '@quiet/common' describe('join community', () => { const validCode = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' + const validPair = [ + { + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + }, + ] it('users switches from join to create', async () => { const { store } = await prepareStore({ @@ -131,11 +137,7 @@ describe('join community', () => { await waitFor(() => expect(handleCommunityAction).toBeCalledWith(registrarUrl)) }) - it.each([ - [`${QUIET_JOIN_PAGE}#${validCode}`], - [`${QUIET_JOIN_PAGE}/#${validCode}`], - // [`${QUIET_JOIN_PAGE}?code=${validCode}`], // Old link format - ])( + it.each([[`${QUIET_JOIN_PAGE}#${validCode}`], [`${QUIET_JOIN_PAGE}/#${validCode}`]])( 'joins community on submit if connection is ready and invitation code is a correct invitation url (%s)', async (invitationLink: string) => { const registrarUrl = new URL(invitationLink) @@ -166,7 +168,7 @@ describe('join community', () => { expect(submitButton).toBeEnabled() await userEvent.click(submitButton) - await waitFor(() => expect(handleCommunityAction).toBeCalledWith(validCode)) + await waitFor(() => expect(handleCommunityAction).toBeCalledWith(validPair)) } ) diff --git a/packages/state-manager/src/sagas/communities/communities.selectors.test.ts b/packages/state-manager/src/sagas/communities/communities.selectors.test.ts index 2a582a3c32..966e5cd3f2 100644 --- a/packages/state-manager/src/sagas/communities/communities.selectors.test.ts +++ b/packages/state-manager/src/sagas/communities/communities.selectors.test.ts @@ -97,33 +97,6 @@ describe('communitiesSelectors', () => { expect(invitationUrl).toEqual('') }) - // it('returns proper invitation url if registrationUrl is in old format', async () => { - // const code = 'aznu6kiyutsgjhdue4i4xushjzey6boxf4i4isd53admsibvbt6qyiyd' - // const registrarUrl = `http://${code}` - // const { store } = prepareStore() - // const factory = await getFactory(store) - // await factory.create['payload']>('Community', { - // registrarUrl, - // port: 0, - // onionAddress: '', - // }) - // const invitationUrl = communitiesSelectors.invitationUrl(store.getState()) - // expect(invitationUrl).toEqual(invitationShareUrl(code)) - // }) - - // it('returns proper invitation url if registrationUrl is just onion address', async () => { - // const code = 'aznu6kiyutsgjhdue4i4xushjzey6boxf4i4isd53admsibvbt6qyiyd' - // const { store } = prepareStore() - // const factory = await getFactory(store) - // await factory.create['payload']>('Community', { - // registrarUrl: code, - // port: 0, - // onionAddress: '', - // }) - // const invitationUrl = communitiesSelectors.invitationUrl(store.getState()) - // expect(invitationUrl).toEqual(invitationShareUrl(code)) - // }) - it('returns proper ownerNickname - ownerCertificate exist', async () => { const { store } = prepareStore() expect(identity.userCertificate).not.toBeUndefined() diff --git a/packages/state-manager/src/sagas/communities/communities.selectors.ts b/packages/state-manager/src/sagas/communities/communities.selectors.ts index 9857c2ce09..7c97185122 100644 --- a/packages/state-manager/src/sagas/communities/communities.selectors.ts +++ b/packages/state-manager/src/sagas/communities/communities.selectors.ts @@ -65,17 +65,6 @@ export const invitationUrl = createSelector(currentCommunity, community => { const peerList = community?.peerList if (!peerList || peerList?.length === 0) return '' const initialPeers = peerList.slice(0, 4) - - console.log('invitationUrl INITIAL PEERS', initialPeers) - - // if (!community?.registrarUrl) return '' - // let registrarUrl = '' - // try { - // const url = new URL(community.registrarUrl) - // registrarUrl = url.hostname.split('.')[0] - // } catch (e) { - // registrarUrl = community.registrarUrl - // } return invitationShareUrl(initialPeers) }) diff --git a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts index 66ca0dc57d..eeeabb3fec 100644 --- a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts +++ b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts @@ -1,12 +1,10 @@ import { PayloadAction } from '@reduxjs/toolkit' -import { call, put, select } from 'typed-redux-saga' +import { call, put } from 'typed-redux-saga' import { Time } from 'pkijs' import { generateId } from '../../../utils/cryptography/cryptography' import { communitiesActions } from '../communities.slice' import { createRootCA } from '@quiet/identity' import { type Community, CommunityOwnership } from '@quiet/types' -import { communitiesSelectors } from '../communities.selectors' -import { connectionSelectors } from '../../appConnection/connection.selectors' export function* createNetworkSaga( action: PayloadAction['payload']> @@ -30,13 +28,9 @@ export function* createNetworkSaga( } const id = yield* call(generateId) - - // const registrarUrl = action.payload.registrar ? `http://${action.payload.registrar}.onion` : undefined - const payload: Community = { id, name: action.payload.name, - // registrarUrl, CA, rootCa: CA?.rootCertString, } diff --git a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts index 210669538a..b441f62767 100644 --- a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts @@ -37,7 +37,7 @@ export function* launchCommunitySaga( const identity = yield* select(identitySelectors.selectById(communityId)) if (!identity?.userCsr?.userKey) { - console.error('Could not launch community, Community or Identity is lacking data') + console.error('Could not launch community, No identity private key') return } diff --git a/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts b/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts index f91a9f0395..32a91de270 100644 --- a/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchRegistrar/launchRegistrar.saga.ts @@ -35,7 +35,6 @@ export function* launchRegistrarSaga( rootKeyString: community.CA.rootKeyString, privateKey: community.privateKey, } - console.log('Sending LAUNCH_REGISTRAR') yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.LAUNCH_REGISTRAR, payload)) } } diff --git a/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts b/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts index 3dfc6fed9b..70befbaff2 100644 --- a/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts +++ b/packages/state-manager/src/sagas/communities/updateCommunity/updateCommunity.saga.ts @@ -6,7 +6,6 @@ import { type PayloadAction } from '@reduxjs/toolkit' export function* updateCommunitySaga( action: PayloadAction['payload']> ): Generator { - console.log('updateCommunitySaga', action.payload) const rootCa = loadCertificate(action.payload.rootCa) const communityName = yield* call(getCertFieldValue, rootCa, CertFieldsTypes.commonName) @@ -20,7 +19,6 @@ export function* updateCommunitySaga( rootCa: action.payload.rootCa, name: communityName, } - console.log('updateCommunitySaga::', payload) yield* put(communitiesActions.updateCommunityData(payload)) } diff --git a/packages/state-manager/src/sagas/identity/identity.slice.ts b/packages/state-manager/src/sagas/identity/identity.slice.ts index abecaa5f1b..445ac34449 100644 --- a/packages/state-manager/src/sagas/identity/identity.slice.ts +++ b/packages/state-manager/src/sagas/identity/identity.slice.ts @@ -8,7 +8,6 @@ import { type Identity, type RegisterCertificatePayload, type StoreUserCertificatePayload, - SaveCSRPayload, } from '@quiet/types' export class IdentityState { public identities: EntityState = identityAdapter.getInitialState() diff --git a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts index b80c60d9ed..ade168914d 100644 --- a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts +++ b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.ts @@ -34,18 +34,4 @@ export function* registerCertificateSaga( } else { yield* put(communitiesActions.launchCommunity(action.payload.communityId)) } - - // else { - // if (!currentCommunity.registrarUrl) { - // console.error('Could not register certificate, no registrar url') - // return - // } - // const payload: RegisterUserCertificatePayload = { - // communityId: action.payload.communityId, - // userCsr: action.payload.userCsr.userCsr, - // serviceAddress: currentCommunity.registrarUrl, - // } - - // yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.REGISTER_USER_CERTIFICATE, payload)) - // } } diff --git a/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts b/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts index df82b47dea..55ed536eb1 100644 --- a/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts +++ b/packages/state-manager/src/sagas/identity/saveUserCsr/saveUserCsr.saga.ts @@ -6,7 +6,7 @@ import { identitySelectors } from '../identity.selectors' export function* saveUserCsrSaga(socket: Socket): Generator { const identity = yield* select(identitySelectors.currentIdentity) if (!identity?.userCsr) { - console.error('Cannot save user csr, no identity') + console.error('Cannot save user csr to backend, no userCsr') return } const payload: SaveCSRPayload = { diff --git a/packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts b/packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts index 7cb46c1705..ca304e8e6a 100644 --- a/packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts +++ b/packages/state-manager/src/sagas/identity/updateCertificate/updateCertificate.saga.ts @@ -17,12 +17,12 @@ export function* updateCertificateSaga(action: PayloadAction { const parsedCert = parseCertificate(cert) - const certUsername = getCertFieldValue(parsedCert, CertFieldsTypes.nickName) - if (certUsername === username) return cert + const certPubKey = getCertFieldValue(parsedCert, CertFieldsTypes.dmPublicKey) + if (certPubKey === pubKey) return cert }) if (cert) { diff --git a/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts b/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts index 32b0c020c5..b212976452 100644 --- a/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts +++ b/packages/state-manager/src/sagas/messages/sendMessage/sendMessage.saga.ts @@ -15,7 +15,7 @@ export function* sendMessageSaga( action: PayloadAction['payload']> ): Generator { const identity = yield* select(identitySelectors.currentIdentity) - if (!identity?.userCsr || !identity.userCertificate) { + if (!identity?.userCsr || !identity?.userCertificate) { console.info('No user CSR or user certificate') return } diff --git a/packages/types/src/identity.ts b/packages/types/src/identity.ts index 6c92c7bf4b..09ff51adab 100644 --- a/packages/types/src/identity.ts +++ b/packages/types/src/identity.ts @@ -60,7 +60,6 @@ export interface RegisterCertificatePayload { export interface RegisterUserCertificatePayload { communityId: string userCsr: string - // serviceAddress?: string } export interface PermsData { From 974324aa8af48b18b0663d73820b50202fb7ceec Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 14:58:53 +0200 Subject: [PATCH 20/28] Fix --- packages/desktop/src/main/main.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/desktop/src/main/main.test.ts b/packages/desktop/src/main/main.test.ts index ad6203d06c..8ac62da4be 100644 --- a/packages/desktop/src/main/main.test.ts +++ b/packages/desktop/src/main/main.test.ts @@ -243,7 +243,7 @@ describe('Invitation code', () => { const code = 'invitationCode' expect(mockAppOnCalls[1][0]).toBe('open-url') const event = { preventDefault: () => {} } - mockAppOnCalls[1][1](event, invitationDeepUrl([{ peerId: 'peerId1', address: 'address' }])) + mockAppOnCalls[1][1](event, invitationDeepUrl([{ peerId: 'peerId1', onionAddress: 'address' }])) expect(mockWindowWebContentsSend).toHaveBeenCalledWith('invitation', { code: code }) }) @@ -252,7 +252,7 @@ describe('Invitation code', () => { await mockAppOnCalls[2][1]() const commandLine = [ '/tmp/.mount_Quiet-TVQc6s/quiet', - invitationDeepUrl([{ peerId: 'peerId1', address: 'address' }]), + invitationDeepUrl([{ peerId: 'peerId1', onionAddress: 'address' }]), ] expect(mockAppOnCalls[0][0]).toBe('second-instance') const event = { preventDefault: () => {} } From 1cd5094b6f5d90ce3d92f3eee861d27cb2edf46c Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 15:18:13 +0200 Subject: [PATCH 21/28] Fix backend tests --- .../connections-manager.service.spec.ts | 69 ++++--------------- .../src/nest/storage/storage.service.spec.ts | 6 ++ 2 files changed, 21 insertions(+), 54 deletions(-) diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts index 5f71412024..abc3ad923e 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts @@ -1,34 +1,23 @@ +import { jest } from '@jest/globals' +import { LazyModuleLoader } from '@nestjs/core' import { Test, TestingModule } from '@nestjs/testing' +import { getFactory, prepareStore, type Store, type communities, type identity } from '@quiet/state-manager' +import { type Community, type Identity, type InitCommunityPayload, type LaunchRegistrarPayload } from '@quiet/types' +import { type FactoryGirl } from 'factory-girl' +import PeerId from 'peer-id' import { TestModule } from '../common/test.module' +import { libp2pInstanceParams, removeFilesFromDir } from '../common/utils' import { QUIET_DIR, TOR_PASSWORD_PROVIDER } from '../const' -import { ConnectionsManagerModule } from './connections-manager.module' -import { ConnectionsManagerService } from './connections-manager.service' -import PeerId from 'peer-id' -import { libp2pInstanceParams } from '../common/utils' -import { jest } from '@jest/globals' -import { CustomEvent } from '@libp2p/interfaces/events' -import { type communities, getFactory, prepareStore, type identity, type Store } from '@quiet/state-manager' -import { type FactoryGirl } from 'factory-girl' -import { DateTime } from 'luxon' -import waitForExpect from 'wait-for-expect' -import { - type Community, - type Identity, - type InitCommunityPayload, - type LaunchRegistrarPayload, - type NetworkStats, -} from '@quiet/types' -import { LocalDBKeys } from '../local-db/local-db.types' +import { Libp2pModule } from '../libp2p/libp2p.module' +import { Libp2pService } from '../libp2p/libp2p.service' import { LocalDbModule } from '../local-db/local-db.module' import { LocalDbService } from '../local-db/local-db.service' -import { RegistrationService } from '../registration/registration.service' +import { LocalDBKeys } from '../local-db/local-db.types' import { RegistrationModule } from '../registration/registration.module' -import { LazyModuleLoader } from '@nestjs/core' -import { Libp2pService } from '../libp2p/libp2p.service' -import { Libp2pModule } from '../libp2p/libp2p.module' +import { RegistrationService } from '../registration/registration.service' import { SocketModule } from '../socket/socket.module' -import { removeFilesFromDir } from '../common/utils' -import { Libp2pEvents } from '../libp2p/libp2p.types' +import { ConnectionsManagerModule } from './connections-manager.module' +import { ConnectionsManagerService } from './connections-manager.service' describe('ConnectionsManagerService', () => { let module: TestingModule @@ -126,7 +115,7 @@ describe('ConnectionsManagerService', () => { expect(launchCommunitySpy).toHaveBeenCalledWith(launchCommunityPayload) }) - it('launches community and registrar on init if their data exists in local db', async () => { + it('launches community on init if their data exists in local db', async () => { const launchCommunityPayload: InitCommunityPayload = { id: community.id, peerId: userIdentity.peerId, @@ -141,18 +130,7 @@ describe('ConnectionsManagerService', () => { peers: community.peerList, } - const launchRegistrarPayload: LaunchRegistrarPayload = { - id: community.id, - peerId: userIdentity.peerId.id, - // @ts-expect-error - rootCertString: community.CA?.rootCertString, - // @ts-expect-error - rootKeyString: community.CA?.rootKeyString, - privateKey: 'privateKey', - } - await localDbService.put(LocalDBKeys.COMMUNITY, launchCommunityPayload) - await localDbService.put(LocalDBKeys.REGISTRAR, launchRegistrarPayload) const peerAddress = '/dns4/test.onion/tcp/80/ws/p2p/peerid' await localDbService.put(LocalDBKeys.PEERS, { @@ -166,21 +144,17 @@ describe('ConnectionsManagerService', () => { await connectionsManagerService.closeAllServices() const launchCommunitySpy = jest.spyOn(connectionsManagerService, 'launchCommunity').mockResolvedValue() - const launchRegistrarSpy = jest.spyOn(registrationService, 'launchRegistrar').mockResolvedValue() await connectionsManagerService.init() expect(launchCommunitySpy).toHaveBeenCalledWith(Object.assign(launchCommunityPayload, { peers: [peerAddress] })) - expect(launchRegistrarSpy).toHaveBeenCalledWith(launchRegistrarPayload) }) it('does not launch community on init if its data does not exist in local db', async () => { await connectionsManagerService.closeAllServices() await connectionsManagerService.init() const launchCommunitySpy = jest.spyOn(connectionsManagerService, 'launchCommunity') - const launchRegistrarSpy = jest.spyOn(registrationService, 'launchRegistrar') expect(launchCommunitySpy).not.toHaveBeenCalled() - expect(launchRegistrarSpy).not.toHaveBeenCalled() }) // At this moment, that test have to be skipped, because checking statues is called before launchCommunity method @@ -210,7 +184,7 @@ describe('ConnectionsManagerService', () => { expect(launchSpy).toBeCalledTimes(1) }) - it('Bug reproduction - Error on startup - Error: TOR: Connection already established - Trigger launchCommunity and launchRegistrar from backend and state manager', async () => { + it('Bug reproduction - Error on startup - Error: TOR: Connection already established - Trigger launchCommunity from backend and state manager', async () => { const launchCommunityPayload: InitCommunityPayload = { id: community.id, peerId: userIdentity.peerId, @@ -225,19 +199,8 @@ describe('ConnectionsManagerService', () => { peers: community.peerList, } - const launchRegistrarPayload: LaunchRegistrarPayload = { - id: community.id, - peerId: userIdentity.peerId.id, - // @ts-expect-error - rootCertString: community.CA?.rootCertString, - // @ts-expect-error - rootKeyString: community.CA?.rootKeyString, - privateKey: '', - } - // await connectionsManager.init() await localDbService.put(LocalDBKeys.COMMUNITY, launchCommunityPayload) - await localDbService.put(LocalDBKeys.REGISTRAR, launchRegistrarPayload) const peerAddress = '/dns4/test.onion/tcp/80/ws/p2p/peerid' await localDbService.put(LocalDBKeys.PEERS, { @@ -251,11 +214,9 @@ describe('ConnectionsManagerService', () => { await connectionsManagerService.closeAllServices() const launchCommunitySpy = jest.spyOn(connectionsManagerService, 'launchCommunity').mockResolvedValue() - const launchRegistrarSpy = jest.spyOn(registrationService, 'launchRegistrar').mockResolvedValue() await connectionsManagerService.init() expect(launchCommunitySpy).toBeCalledTimes(1) - expect(launchRegistrarSpy).toBeCalledTimes(1) }) }) diff --git a/packages/backend/src/nest/storage/storage.service.spec.ts b/packages/backend/src/nest/storage/storage.service.spec.ts index ee19696c65..9012cf0785 100644 --- a/packages/backend/src/nest/storage/storage.service.spec.ts +++ b/packages/backend/src/nest/storage/storage.service.spec.ts @@ -255,6 +255,10 @@ describe('StorageService', () => { const channelsDbAddress = storageService.channels?.address // @ts-expect-error 'certificates' is private const certificatesDbAddress = storageService.certificates.address + // @ts-expect-error 'certificatesRequests' is private + const certificatesRequestsDbAddress = storageService.certificatesRequests.address + // @ts-expect-error 'communityMetadata' is private + const communityMetadataDbAddress = storageService.communityMetadata.address expect(channelsDbAddress).not.toBeFalsy() expect(certificatesDbAddress).not.toBeFalsy() expect(subscribeToPubSubSpy).toBeCalledTimes(2) @@ -262,6 +266,8 @@ describe('StorageService', () => { expect(subscribeToPubSubSpy).toHaveBeenNthCalledWith(1, [ StorageService.dbAddress(channelsDbAddress), StorageService.dbAddress(certificatesDbAddress), + StorageService.dbAddress(certificatesRequestsDbAddress), + StorageService.dbAddress(communityMetadataDbAddress), ]) // Creating channel: expect(subscribeToPubSubSpy).toHaveBeenNthCalledWith(2, [StorageService.dbAddress(db.address)]) From 9a2b4020f5b06e48795c8e0f4100c7062efea22d Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 15:32:16 +0200 Subject: [PATCH 22/28] Fix --- .../sagas/invitation/handleInvitationCode.saga.test.ts | 2 +- packages/desktop/src/rtl-tests/community.create.test.tsx | 4 ++-- packages/desktop/src/rtl-tests/customProtocol.test.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts index a98bf1d5e1..d95c7fd035 100644 --- a/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts +++ b/packages/desktop/src/renderer/sagas/invitation/handleInvitationCode.saga.test.ts @@ -28,7 +28,7 @@ describe('Handle invitation code', () => { factory = await getFactory(store) validInvitationPair = [ { - address: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', }, ] diff --git a/packages/desktop/src/rtl-tests/community.create.test.tsx b/packages/desktop/src/rtl-tests/community.create.test.tsx index 7bf3329724..91304eadcc 100644 --- a/packages/desktop/src/rtl-tests/community.create.test.tsx +++ b/packages/desktop/src/rtl-tests/community.create.test.tsx @@ -183,14 +183,12 @@ describe('User', () => { expect(actions).toMatchInlineSnapshot(` Array [ "Communities/createNetwork", - "Communities/clearInvitationCode", "Communities/addNewCommunity", "Communities/setCurrentCommunity", "Modals/closeModal", "Modals/openModal", "Identity/registerUsername", "Communities/responseCreateNetwork", - "Communities/clearInvitationCode", "Communities/updateCommunityData", "Identity/addNewIdentity", "Network/setLoadingPanelType", @@ -201,8 +199,10 @@ describe('User', () => { "Identity/storeUserCertificate", "Identity/savedOwnerCertificate", "Communities/launchRegistrar", + "Identity/saveUserCsr", "Files/checkForMissingFiles", "Network/addInitializedCommunity", + "Communities/clearInvitationCodes", "Identity/saveOwnerCertToDb", "PublicChannels/createGeneralChannel", "PublicChannels/channelsReplicated", diff --git a/packages/desktop/src/rtl-tests/customProtocol.test.tsx b/packages/desktop/src/rtl-tests/customProtocol.test.tsx index 2837451ef5..b0dbcaf697 100644 --- a/packages/desktop/src/rtl-tests/customProtocol.test.tsx +++ b/packages/desktop/src/rtl-tests/customProtocol.test.tsx @@ -66,7 +66,7 @@ describe('Opening app through custom protocol', () => { ) const invitationCodes: InvitationPair[] = [ - { peerId: 'abcdef', address: 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' }, + { peerId: 'abcdef', onionAddress: 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' }, ] store.dispatch(communities.actions.handleInvitationCodes(invitationCodes)) From aed88250c4cfdbee68b04cb6c187c9b4c8d02bca Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 16:58:22 +0200 Subject: [PATCH 23/28] Fix state-manager tests --- packages/common/package.json | 3 +-- .../launchCommunity/launchCommunity.saga.test.ts | 2 -- .../responseCreateNetwork.saga.test.ts | 1 - .../registerCertificate.saga.test.ts | 13 +++---------- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/packages/common/package.json b/packages/common/package.json index b2b28752b9..667c565984 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -27,8 +27,7 @@ "dependencies": { "@quiet/types": "^2.0.0-alpha.0", "cross-env": "^5.2.0", - "debug": "^4.3.1", - "peer-id": "^0.16.0" + "debug": "^4.3.1" }, "jest": { "transform": { diff --git a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.test.ts b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.test.ts index 020a6f8459..253624c057 100644 --- a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.test.ts +++ b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.test.ts @@ -118,7 +118,6 @@ describe('launchCommunity', () => { id: launchCommunityPayload.id, peerId: launchCommunityPayload.peerId, hiddenService: launchCommunityPayload.hiddenService, - certs: launchCommunityPayload.certs, peers: launchCommunityPayload.peers, }, ]) @@ -182,7 +181,6 @@ describe('launchCommunity', () => { id: launchCommunityPayload.id, peerId: launchCommunityPayload.peerId, hiddenService: launchCommunityPayload.hiddenService, - certs: launchCommunityPayload.certs, peers: launchCommunityPayload.peers, }, ]) diff --git a/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts b/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts index 3b068ad007..10ad9f8ce3 100644 --- a/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts +++ b/packages/state-manager/src/sagas/communities/responseCreateNetwork/responseCreateNetwork.saga.test.ts @@ -61,7 +61,6 @@ describe('responseCreateNetwork', () => { .withState(store.getState()) .provide([[call.fn(generateDmKeyPair), dmKeys]]) .call(generateDmKeyPair) - .put(communitiesActions.clearInvitationCodes()) .put(communitiesActions.updateCommunityData(community)) .put(identityActions.addNewIdentity(identity)) .run() diff --git a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.test.ts b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.test.ts index 9e91149243..81e94d2372 100644 --- a/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.test.ts +++ b/packages/state-manager/src/sagas/identity/registerCertificate/registerCertificate.saga.test.ts @@ -5,7 +5,7 @@ import { prepareStore } from '../../../utils/tests/prepareStore' import { getFactory } from '../../../utils/tests/factories' import { combineReducers } from '@reduxjs/toolkit' import { reducers } from '../../reducers' -import { type communitiesActions } from '../../communities/communities.slice' +import { communitiesActions } from '../../communities/communities.slice' import { identityActions } from '../identity.slice' import { registerCertificateSaga } from './registerCertificate.saga' import { type CertData, type RegisterCertificatePayload, SocketActionTypes, type UserCsr } from '@quiet/types' @@ -51,7 +51,7 @@ describe('registerCertificateSaga', () => { .run() }) - it('request certificate registration when user is not community owner', async () => { + it('launch community when user is not community owner', async () => { setupCrypto() const socket = { emit: jest.fn(), on: jest.fn() } as unknown as Socket @@ -102,14 +102,7 @@ describe('registerCertificateSaga', () => { .withReducer(reducer) .withState(store.getState()) .not.apply(socket, socket.emit, [SocketActionTypes.REGISTER_OWNER_CERTIFICATE]) - .apply(socket, socket.emit, [ - SocketActionTypes.REGISTER_USER_CERTIFICATE, - { - communityId: community.id, - userCsr: identity.userCsr.userCsr, - serviceAddress: community.registrarUrl, - }, - ]) + .put(communitiesActions.launchCommunity(community.id)) .run() }) }) From 92182af01e60de03f188b0c1d1e7b5a99c7fa3e7 Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 18:31:46 +0200 Subject: [PATCH 24/28] Fix or skip desktop tests --- packages/desktop/src/main/main.test.ts | 25 +++++++++++------ .../JoinCommunity/JoinCommunity.test.tsx | 28 +++++++++++++++---- .../src/rtl-tests/community.join.test.tsx | 26 ++++++++--------- .../src/rtl-tests/loadingPanel.test.tsx | 27 ++++-------------- .../registerUsername/registerUsername.saga.ts | 1 - 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/packages/desktop/src/main/main.test.ts b/packages/desktop/src/main/main.test.ts index 8ac62da4be..0239a05cd0 100644 --- a/packages/desktop/src/main/main.test.ts +++ b/packages/desktop/src/main/main.test.ts @@ -240,23 +240,30 @@ describe('Invitation code', () => { it('handles invitation code on open-url event (on macos)', async () => { expect(mockAppOnCalls[2][0]).toBe('ready') await mockAppOnCalls[2][1]() - const code = 'invitationCode' + const codes = [ + { + peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + }, + ] expect(mockAppOnCalls[1][0]).toBe('open-url') const event = { preventDefault: () => {} } - mockAppOnCalls[1][1](event, invitationDeepUrl([{ peerId: 'peerId1', onionAddress: 'address' }])) - expect(mockWindowWebContentsSend).toHaveBeenCalledWith('invitation', { code: code }) + mockAppOnCalls[1][1](event, invitationDeepUrl(codes)) + expect(mockWindowWebContentsSend).toHaveBeenCalledWith('invitation', { codes }) }) it('process invitation code on second-instance event', async () => { - const code = 'invitationCodeArgv' - await mockAppOnCalls[2][1]() - const commandLine = [ - '/tmp/.mount_Quiet-TVQc6s/quiet', - invitationDeepUrl([{ peerId: 'peerId1', onionAddress: 'address' }]), + const codes = [ + { + peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + }, ] + await mockAppOnCalls[2][1]() + const commandLine = ['/tmp/.mount_Quiet-TVQc6s/quiet', invitationDeepUrl(codes)] expect(mockAppOnCalls[0][0]).toBe('second-instance') const event = { preventDefault: () => {} } mockAppOnCalls[0][1](event, commandLine) - expect(mockWindowWebContentsSend).toHaveBeenCalledWith('invitation', { code: code }) + expect(mockWindowWebContentsSend).toHaveBeenCalledWith('invitation', { codes }) }) }) diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx index 1e46199714..a9752d46f8 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.test.tsx @@ -106,7 +106,8 @@ describe('join community', () => { }) it('joins community on submit if connection is ready and registrar url is correct', async () => { - const registrarUrl = 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad' + const registrarUrl = + 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' const handleCommunityAction = jest.fn() @@ -134,7 +135,14 @@ describe('join community', () => { expect(submitButton).toBeEnabled() await userEvent.click(submitButton) - await waitFor(() => expect(handleCommunityAction).toBeCalledWith(registrarUrl)) + await waitFor(() => + expect(handleCommunityAction).toBeCalledWith([ + { + peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + }, + ]) + ) }) it.each([[`${QUIET_JOIN_PAGE}#${validCode}`], [`${QUIET_JOIN_PAGE}/#${validCode}`]])( @@ -173,7 +181,8 @@ describe('join community', () => { ) it('trims whitespaces from registrar url', async () => { - const registrarUrl = 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad ' + const registrarUrl = + 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd ' const handleCommunityAction = jest.fn() @@ -201,7 +210,14 @@ describe('join community', () => { expect(submitButton).toBeEnabled() await userEvent.click(submitButton) - await waitFor(() => expect(handleCommunityAction).toBeCalledWith(registrarUrl.trim())) + await waitFor(() => + expect(handleCommunityAction).toBeCalledWith([ + { + peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + }, + ]) + ) }) it.each([ @@ -262,7 +278,7 @@ describe('join community', () => { const textInput = result.queryByPlaceholderText(inviteLinkField().fieldProps.placeholder) expect(textInput).not.toBeNull() // @ts-expect-error - await userEvent.type(textInput, 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad') + await userEvent.type(textInput, validCode) const submitButton = result.getByTestId('continue-joinCommunity') expect(submitButton).not.toBeNull() @@ -286,7 +302,7 @@ describe('join community', () => { ) const textInput = screen.getByPlaceholderText(inviteLinkField().fieldProps.placeholder) - await userEvent.type(textInput, 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad') + await userEvent.type(textInput, validCode) const submitButton = screen.getByText('Continue') expect(submitButton).toBeEnabled() diff --git a/packages/desktop/src/rtl-tests/community.join.test.tsx b/packages/desktop/src/rtl-tests/community.join.test.tsx index b23f4f8692..e2f5984c17 100644 --- a/packages/desktop/src/rtl-tests/community.join.test.tsx +++ b/packages/desktop/src/rtl-tests/community.join.test.tsx @@ -26,7 +26,6 @@ import { getFactory, errors, ResponseCreateNetworkPayload, - connection, } from '@quiet/state-manager' import Channel from '../renderer/components/Channel/Channel' import LoadingPanel from '../renderer/components/LoadingPanel/LoadingPanel' @@ -37,14 +36,14 @@ import { ErrorPayload, ResponseLaunchCommunityPayload, SendOwnerCertificatePayload, - SendUserCertificatePayload, } from '@quiet/types' -import { selectOptions } from 'mathjax-full/js/util/Options' jest.setTimeout(20_000) describe('User', () => { let socket: MockedSocket + const validCode = + 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' // trigger beforeEach(() => { socket = new MockedSocket() @@ -167,7 +166,7 @@ describe('User', () => { // Enter community address and hit button const joinCommunityInput = screen.getByPlaceholderText(dictionary.placeholder) const joinCommunityButton = screen.getByText(dictionary.button) - await userEvent.type(joinCommunityInput, '3lyn5yjwwb74he5olv43eej7knt34folvrgrfsw6vzitvkxmc5wpe4yd') + await userEvent.type(joinCommunityInput, validCode) await userEvent.click(joinCommunityButton) // Confirm user is being redirected to username registration @@ -194,28 +193,24 @@ describe('User', () => { expect(actions).toMatchInlineSnapshot(` Array [ "Communities/createNetwork", - "Communities/clearInvitationCode", + "Communities/setInvitationCodes", "Communities/addNewCommunity", "Communities/setCurrentCommunity", "Modals/closeModal", "Modals/openModal", "Identity/registerUsername", "Communities/responseCreateNetwork", - "Communities/clearInvitationCode", "Communities/updateCommunityData", "Identity/addNewIdentity", "Network/setLoadingPanelType", "Modals/openModal", "Identity/registerCertificate", - "Communities/addOwnerCertificate", - "Communities/storePeerList", - "Identity/storeUserCertificate", - "Communities/updateCommunity", - "Communities/updateCommunityData", "Communities/launchCommunity", "Communities/launchRegistrar", + "Identity/saveUserCsr", "Files/checkForMissingFiles", "Network/addInitializedCommunity", + "Communities/clearInvitationCodes", "PublicChannels/channelsReplicated", "PublicChannels/addChannel", "Messages/addPublicChannelsMessagesBase", @@ -227,7 +222,8 @@ describe('User', () => { `) }) - it('sees proper registration error when trying to join with already taken username', async () => { + // We don't display registration errors right now + it.skip('sees proper registration error when trying to join with already taken username', async () => { const { store, runSaga } = await prepareStore( {}, socket // Fork state manager's sagas @@ -292,7 +288,7 @@ describe('User', () => { // Enter community address and hit button const joinCommunityInput = screen.getByPlaceholderText(dictionary.placeholder) const joinCommunityButton = screen.getByText(dictionary.button) - await userEvent.type(joinCommunityInput, '3lyn5yjwwb74he5olv43eej7knt34folvrgrfsw6vzitvkxmc5wpe4yd') + await userEvent.type(joinCommunityInput, validCode) await userEvent.click(joinCommunityButton) // Confirm user is being redirected to username registration @@ -336,7 +332,7 @@ describe('User', () => { `) }) - it('clears error before sending another username registration request', async () => { + it.skip('clears error before sending another username registration request', async () => { const { store, runSaga } = await prepareStore( {}, socket // Fork state manager's sagas @@ -389,7 +385,7 @@ describe('User', () => { // Enter community address and hit button const joinCommunityInput = screen.getByPlaceholderText(dictionary.placeholder) const joinCommunityButton = screen.getByText(dictionary.button) - await userEvent.type(joinCommunityInput, '3lyn5yjwwb74he5olv43eej7knt34folvrgrfsw6vzitvkxmc5wpe4yd') + await userEvent.type(joinCommunityInput, validCode) await userEvent.click(joinCommunityButton) // Confirm user is being redirected to username registration diff --git a/packages/desktop/src/rtl-tests/loadingPanel.test.tsx b/packages/desktop/src/rtl-tests/loadingPanel.test.tsx index dc226a1ff3..57b6b0cf53 100644 --- a/packages/desktop/src/rtl-tests/loadingPanel.test.tsx +++ b/packages/desktop/src/rtl-tests/loadingPanel.test.tsx @@ -133,7 +133,7 @@ describe('Loading panel', () => { expect(screen.queryByTestId('joiningPanelComponent')).toBeNull() }) - it('Do not display Loading panel when community and identity are created but certificate is missing', async () => { + it('Do not display Loading panel when community and identity are created but user csr is missing', async () => { const { store } = await prepareStore( {}, socket // Fork state manager's sagas @@ -149,20 +149,11 @@ describe('Loading panel', () => { await factory.create['payload']>('Identity', { id: community.id, nickname: 'alice', + userCertificate: null, + userCsr: null, }) - const aliceCertificate = store.getState().Identity.identities.entities[community.id]?.userCertificate - - expect(aliceCertificate).not.toBeUndefined() - expect(aliceCertificate).not.toBeNull() - - store.dispatch( - identity.actions.storeUserCertificate({ - communityId: community.id, - // @ts-expect-error - userCertificate: null, - }) - ) + expect(store.getState().Identity.identities.entities[community.id]?.userCsr).toBeNull() renderComponent( <> @@ -176,14 +167,8 @@ describe('Loading panel', () => { expect(screen.queryByTestId('createUsernameModalActions')).not.toBeNull() // Assertions that we don't see Loading Pannel expect(screen.queryByTestId('spinnerLoader')).toBeNull() - // 'Create username' modal should be closed after receiving certificate - store.dispatch( - identity.actions.storeUserCertificate({ - communityId: community.id, - // @ts-expect-error - userCertificate: aliceCertificate, - }) - ) + // 'Create username' modal should be closed after creating csr + store.dispatch(identity.actions.registerUsername('alice')) await waitFor(() => expect(screen.queryByTestId('createUsernameModalActions')).toBeNull()) }) }) diff --git a/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts b/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts index 8fcf1fbc54..52642d02d2 100644 --- a/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts +++ b/packages/state-manager/src/sagas/identity/registerUsername/registerUsername.saga.ts @@ -7,7 +7,6 @@ import { config } from '../../users/const/certFieldTypes' import { Socket, applyEmitParams } from '../../../types' import { communitiesSelectors } from '../../communities/communities.selectors' import { CreateUserCsrPayload, RegisterCertificatePayload, SocketActionTypes, Community } from '@quiet/types' -import { connectionSelectors } from '../../appConnection/connection.selectors' export function* registerUsernameSaga(socket: Socket, action: PayloadAction): Generator { // Nickname can differ between saga calls From 6232b9cf45693ca11ee31d5e05286e4278e03bc7 Mon Sep 17 00:00:00 2001 From: Emi Date: Thu, 7 Sep 2023 19:27:02 +0200 Subject: [PATCH 25/28] Uncomment deeplink test on mobile --- packages/common/package-lock.json | 664 +----------------- .../store/init/deepLink/deepLink.saga.test.ts | 431 ++++++------ .../src/store/init/deepLink/deepLink.saga.ts | 5 +- 3 files changed, 225 insertions(+), 875 deletions(-) diff --git a/packages/common/package-lock.json b/packages/common/package-lock.json index 89dd1a2d08..425621773a 100644 --- a/packages/common/package-lock.json +++ b/packages/common/package-lock.json @@ -9,10 +9,8 @@ "version": "2.0.0-alpha.0", "license": "ISC", "dependencies": { - "@multiformats/multiaddr": "11.4.0", "cross-env": "^5.2.0", - "debug": "^4.3.1", - "peer-id": "^0.16.0" + "debug": "^4.3.1" }, "devDependencies": { "@types/jest": "^26.0.23", @@ -983,125 +981,6 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/@multiformats/multiaddr": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-11.4.0.tgz", - "integrity": "sha512-rLIhSOCKQhm/fCjg+5tVM9xrtjbZjZKJg6bb65YbFsNoPSYhweEohXO8Pkg2xbRy3NqVEVkS+8DB/+VhNvjd5Q==", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "dns-over-http-resolver": "^2.1.0", - "err-code": "^3.0.1", - "multiformats": "^11.0.0", - "uint8arrays": "^4.0.2", - "varint": "^6.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/@chainsafe/is-ip": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.0.2.tgz", - "integrity": "sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA==" - }, - "node_modules/@multiformats/multiaddr/node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/dns-over-http-resolver": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-2.1.2.tgz", - "integrity": "sha512-Bjbf6aZjr3HMnwGslZnoW3MJVqgbTsh39EZWpikx2yLl9xEjw4eZhlOHCFhkOu89zoWaS4rqe2Go53TXW4Byiw==", - "dependencies": { - "debug": "^4.3.1", - "native-fetch": "^4.0.2", - "receptacle": "^1.3.2", - "undici": "^5.12.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, - "node_modules/@multiformats/multiaddr/node_modules/multiformats": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", - "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/native-fetch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-4.0.2.tgz", - "integrity": "sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg==", - "peerDependencies": { - "undici": "*" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/receptacle": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", - "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/uint8arrays": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-4.0.6.tgz", - "integrity": "sha512-4ZesjQhqOU2Ip6GPReIwN60wRxIupavL8T0Iy36BBHr2qyMrNxsPJvr7vpS4eFt8F8kSguWUPad6ZM9izs/vyw==", - "dependencies": { - "multiformats": "^12.0.1" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/uint8arrays/node_modules/multiformats": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.1.tgz", - "integrity": "sha512-GBSToTmri2vJYs8wqcZQ8kB21dCaeTOzHTIAlr8J06C1eL6UbzqURXFZ5Fl0EYm9GAFz1IlYY8SxGOs9G9NJRg==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/undici": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz", - "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==", - "dependencies": { - "busboy": "^1.6.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/@multiformats/multiaddr/node_modules/varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -1216,7 +1095,8 @@ "node_modules/@types/node": { "version": "17.0.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "dev": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -3019,7 +2899,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/is-accessor-descriptor": { "version": "1.0.0", @@ -4559,246 +4440,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/peer-id": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.16.0.tgz", - "integrity": "sha512-EmL7FurFUduU9m1PS9cfJ5TAuCvxKQ7DKpfx3Yj6IKWyBRtosriFuOag/l3ni/dtPgPLwiA4R9IvpL7hsDLJuQ==", - "dependencies": { - "class-is": "^1.1.0", - "libp2p-crypto": "^0.21.0", - "multiformats": "^9.4.5", - "protobufjs": "^6.10.2", - "uint8arrays": "^3.0.0" - }, - "engines": { - "node": ">=15.0.0" - } - }, - "node_modules/peer-id/node_modules/@noble/ed25519": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", - "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/peer-id/node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/peer-id/node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/peer-id/node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/peer-id/node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/peer-id/node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/peer-id/node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/peer-id/node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/peer-id/node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/peer-id/node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/peer-id/node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/peer-id/node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/peer-id/node_modules/@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, - "node_modules/peer-id/node_modules/class-is": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", - "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" - }, - "node_modules/peer-id/node_modules/err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, - "node_modules/peer-id/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/peer-id/node_modules/iso-random-stream": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/iso-random-stream/-/iso-random-stream-2.0.2.tgz", - "integrity": "sha512-yJvs+Nnelic1L2vH2JzWvvPQFA4r7kSTnpST/+LkAQjSz0hos2oqLD+qIVi9Qk38Hoe7mNDt3j0S27R58MVjLQ==", - "dependencies": { - "events": "^3.3.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/peer-id/node_modules/libp2p-crypto": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.21.2.tgz", - "integrity": "sha512-EXFrhSpiHtJ+/L8xXDvQNK5VjUMG51u878jzZcaT5XhuN/zFg6PWJFnl/qB2Y2j7eMWnvCRP7Kp+ua2H36cG4g==", - "dependencies": { - "@noble/ed25519": "^1.5.1", - "@noble/secp256k1": "^1.3.0", - "err-code": "^3.0.1", - "iso-random-stream": "^2.0.0", - "multiformats": "^9.4.5", - "node-forge": "^1.2.1", - "protobufjs": "^6.11.2", - "uint8arrays": "^3.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/peer-id/node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/peer-id/node_modules/multiformats": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" - }, - "node_modules/peer-id/node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/peer-id/node_modules/protobufjs": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", - "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - } - }, - "node_modules/peer-id/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/peer-id/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/peer-id/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/peer-id/node_modules/uint8arrays": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", - "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", - "dependencies": { - "multiformats": "^9.4.2" - } - }, - "node_modules/peer-id/node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -7325,102 +6966,6 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, - "@multiformats/multiaddr": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-11.4.0.tgz", - "integrity": "sha512-rLIhSOCKQhm/fCjg+5tVM9xrtjbZjZKJg6bb65YbFsNoPSYhweEohXO8Pkg2xbRy3NqVEVkS+8DB/+VhNvjd5Q==", - "requires": { - "@chainsafe/is-ip": "^2.0.1", - "dns-over-http-resolver": "^2.1.0", - "err-code": "^3.0.1", - "multiformats": "^11.0.0", - "uint8arrays": "^4.0.2", - "varint": "^6.0.0" - }, - "dependencies": { - "@chainsafe/is-ip": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.0.2.tgz", - "integrity": "sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA==" - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "dns-over-http-resolver": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-2.1.2.tgz", - "integrity": "sha512-Bjbf6aZjr3HMnwGslZnoW3MJVqgbTsh39EZWpikx2yLl9xEjw4eZhlOHCFhkOu89zoWaS4rqe2Go53TXW4Byiw==", - "requires": { - "debug": "^4.3.1", - "native-fetch": "^4.0.2", - "receptacle": "^1.3.2", - "undici": "^5.12.0" - } - }, - "err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, - "multiformats": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", - "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==" - }, - "native-fetch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-4.0.2.tgz", - "integrity": "sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg==", - "requires": {} - }, - "receptacle": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", - "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", - "requires": { - "ms": "^2.1.1" - } - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "uint8arrays": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-4.0.6.tgz", - "integrity": "sha512-4ZesjQhqOU2Ip6GPReIwN60wRxIupavL8T0Iy36BBHr2qyMrNxsPJvr7vpS4eFt8F8kSguWUPad6ZM9izs/vyw==", - "requires": { - "multiformats": "^12.0.1" - }, - "dependencies": { - "multiformats": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.1.tgz", - "integrity": "sha512-GBSToTmri2vJYs8wqcZQ8kB21dCaeTOzHTIAlr8J06C1eL6UbzqURXFZ5Fl0EYm9GAFz1IlYY8SxGOs9G9NJRg==" - } - } - }, - "undici": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.23.0.tgz", - "integrity": "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==", - "requires": { - "busboy": "^1.6.0" - } - }, - "varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" - } - } - }, "@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -7532,7 +7077,8 @@ "@types/node": { "version": "17.0.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "dev": true }, "@types/normalize-package-data": { "version": "2.4.1", @@ -8916,7 +8462,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "is-accessor-descriptor": { "version": "1.0.0", @@ -10109,199 +9656,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "peer-id": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.16.0.tgz", - "integrity": "sha512-EmL7FurFUduU9m1PS9cfJ5TAuCvxKQ7DKpfx3Yj6IKWyBRtosriFuOag/l3ni/dtPgPLwiA4R9IvpL7hsDLJuQ==", - "requires": { - "class-is": "^1.1.0", - "libp2p-crypto": "^0.21.0", - "multiformats": "^9.4.5", - "protobufjs": "^6.10.2", - "uint8arrays": "^3.0.0" - }, - "dependencies": { - "@noble/ed25519": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", - "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==" - }, - "@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, - "class-is": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", - "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" - }, - "err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "iso-random-stream": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/iso-random-stream/-/iso-random-stream-2.0.2.tgz", - "integrity": "sha512-yJvs+Nnelic1L2vH2JzWvvPQFA4r7kSTnpST/+LkAQjSz0hos2oqLD+qIVi9Qk38Hoe7mNDt3j0S27R58MVjLQ==", - "requires": { - "events": "^3.3.0", - "readable-stream": "^3.4.0" - } - }, - "libp2p-crypto": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.21.2.tgz", - "integrity": "sha512-EXFrhSpiHtJ+/L8xXDvQNK5VjUMG51u878jzZcaT5XhuN/zFg6PWJFnl/qB2Y2j7eMWnvCRP7Kp+ua2H36cG4g==", - "requires": { - "@noble/ed25519": "^1.5.1", - "@noble/secp256k1": "^1.3.0", - "err-code": "^3.0.1", - "iso-random-stream": "^2.0.0", - "multiformats": "^9.4.5", - "node-forge": "^1.2.1", - "protobufjs": "^6.11.2", - "uint8arrays": "^3.0.0" - } - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "multiformats": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" - }, - "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" - }, - "protobufjs": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", - "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "uint8arrays": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", - "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", - "requires": { - "multiformats": "^9.4.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - } - } - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts b/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts index 366c83c1f7..0eddc579e1 100644 --- a/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts +++ b/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts @@ -1,218 +1,213 @@ -// import { expectSaga } from 'redux-saga-test-plan' -// import { combineReducers } from '@reduxjs/toolkit' -// import { reducers } from '../../root.reducer' -// import { Store } from '../../store.types' -// import { prepareStore } from '../../../tests/utils/prepareStore' -// import { communities, Community, connection, identity } from '@quiet/state-manager' -// import { initActions } from '../init.slice' -// import { navigationActions } from '../../navigation/navigation.slice' -// import { ScreenNames } from '../../../const/ScreenNames.enum' -// import { deepLinkSaga } from './deepLink.saga' -// import { CommunityOwnership, ConnectionProcessInfo, Identity } from '@quiet/types' - -// describe('deepLinkSaga', () => { -// let store: Store - -// const id = '00d045ab' - -// const community: Community = { -// id, -// name: '', -// CA: { -// rootCertString: '', -// rootKeyString: '', -// }, -// rootCa: '', -// peerList: [], -// registrar: { -// privateKey: '', -// address: '', -// }, -// registrarUrl: 'https://bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd.onion', -// onionAddress: '', -// privateKey: '', -// port: 0, -// registrationAttempts: 0, -// ownerCertificate: '', -// } - -// const _identity: Partial = { -// id, -// nickname: '', -// userCsr: null, -// userCertificate: null, -// joinTimestamp: 0, -// } - -// beforeEach(async () => { -// store = (await prepareStore()).store -// }) - -// test('joins community', async () => { -// store.dispatch( -// initActions.setWebsocketConnected({ -// dataPort: 5001, -// }) -// ) - -// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - -// const reducer = combineReducers(reducers) -// await expectSaga(deepLinkSaga, initActions.deepLink(code)) -// .withReducer(reducer) -// .withState(store.getState()) -// .put( -// navigationActions.replaceScreen({ -// screen: ScreenNames.JoinCommunityScreen, -// params: { -// code, -// }, -// }) -// ) -// .put( -// communities.actions.createNetwork({ -// ownership: CommunityOwnership.User, -// peers: code, -// }) -// ) -// .run() -// }) - -// test('opens channel list screen if the same url has been used', async () => { -// store.dispatch( -// initActions.setWebsocketConnected({ -// dataPort: 5001, -// }) -// ) - -// store.dispatch(communities.actions.addNewCommunity(community)) - -// store.dispatch( -// // @ts-expect-error -// identity.actions.addNewIdentity({ ..._identity, userCertificate: 'certificate' }) -// ) - -// store.dispatch(communities.actions.setCurrentCommunity(community.id)) - -// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - -// const reducer = combineReducers(reducers) -// await expectSaga(deepLinkSaga, initActions.deepLink(code)) -// .withReducer(reducer) -// .withState(store.getState()) -// .put( -// navigationActions.replaceScreen({ -// screen: ScreenNames.ChannelListScreen, -// }) -// ) -// .not.put( -// communities.actions.createNetwork({ -// ownership: CommunityOwnership.User, -// registrar: code, -// }) -// ) -// .run() -// }) - -// test('displays error if user already belongs to a community', async () => { -// store.dispatch( -// initActions.setWebsocketConnected({ -// dataPort: 5001, -// }) -// ) - -// store.dispatch(communities.actions.addNewCommunity(community)) - -// store.dispatch(communities.actions.setCurrentCommunity(community.id)) - -// const code = 'ctbebt3ixybtu4ty2dr3ychjtxpkhuun4neuavkjjhplgzfde5vgelad' - -// const reducer = combineReducers(reducers) -// await expectSaga(deepLinkSaga, initActions.deepLink(code)) -// .withReducer(reducer) -// .withState(store.getState()) -// .not.put( -// communities.actions.createNetwork({ -// ownership: CommunityOwnership.User, -// registrar: code, -// }) -// ) -// .run() -// }) - -// test('continues if link used mid registration', async () => { -// store.dispatch( -// initActions.setWebsocketConnected({ -// dataPort: 5001, -// }) -// ) - -// store.dispatch(communities.actions.addNewCommunity(community)) - -// store.dispatch( -// // @ts-expect-error -// identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) -// ) - -// store.dispatch(communities.actions.setCurrentCommunity(community.id)) - -// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - -// const reducer = combineReducers(reducers) -// await expectSaga(deepLinkSaga, initActions.deepLink(code)) -// .withReducer(reducer) -// .withState(store.getState()) -// .put( -// navigationActions.replaceScreen({ -// screen: ScreenNames.UsernameRegistrationScreen, -// params: undefined, -// }) -// ) -// .not.put( -// communities.actions.createNetwork({ -// ownership: CommunityOwnership.User, -// registrar: code, -// }) -// ) -// .run() -// }) - -// test('continues if link used mid registration and locks input while waiting for server response', async () => { -// store.dispatch( -// initActions.setWebsocketConnected({ -// dataPort: 5001, -// }) -// ) - -// store.dispatch(communities.actions.addNewCommunity(community)) - -// store.dispatch( -// // @ts-expect-error -// identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) -// ) - -// store.dispatch(communities.actions.setCurrentCommunity(community.id)) - -// store.dispatch(connection.actions.setTorConnectionProcess(ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE)) - -// const code = 'bidrmzr3ee6qa2vvrlcnqvvvsk2gmjktcqkunba326parszr44gibwyd' - -// const reducer = combineReducers(reducers) -// await expectSaga(deepLinkSaga, initActions.deepLink(code)) -// .withReducer(reducer) -// .withState(store.getState()) -// .put( -// navigationActions.replaceScreen({ -// screen: ScreenNames.UsernameRegistrationScreen, -// params: { fetching: true }, -// }) -// ) -// .not.put( -// communities.actions.createNetwork({ -// ownership: CommunityOwnership.User, -// registrar: code, -// }) -// ) -// .run() -// }) -// }) +import { expectSaga } from 'redux-saga-test-plan' +import { combineReducers } from '@reduxjs/toolkit' +import { reducers } from '../../root.reducer' +import { Store } from '../../store.types' +import { prepareStore } from '../../../tests/utils/prepareStore' +import { communities, Community, connection, identity } from '@quiet/state-manager' +import { initActions } from '../init.slice' +import { navigationActions } from '../../navigation/navigation.slice' +import { ScreenNames } from '../../../const/ScreenNames.enum' +import { deepLinkSaga } from './deepLink.saga' +import { CommunityOwnership, ConnectionProcessInfo, Identity } from '@quiet/types' + +describe('deepLinkSaga', () => { + let store: Store + + const id = '00d045ab' + const validCode = + 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' + const validPairs = [ + { + peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', + onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', + }, + ] + const community: Community = { + id, + name: '', + CA: { + rootCertString: '', + rootKeyString: '', + }, + rootCa: '', + peerList: [], + registrar: { + privateKey: '', + address: '', + }, + onionAddress: '', + privateKey: '', + port: 0, + registrationAttempts: 0, + ownerCertificate: '', + } + + const _identity: Partial = { + id, + nickname: '', + userCsr: null, + userCertificate: null, + joinTimestamp: 0, + } + + beforeEach(async () => { + store = (await prepareStore()).store + }) + + test('joins community', async () => { + store.dispatch( + initActions.setWebsocketConnected({ + dataPort: 5001, + }) + ) + + const reducer = combineReducers(reducers) + await expectSaga(deepLinkSaga, initActions.deepLink(validCode)) + .withReducer(reducer) + .withState(store.getState()) + .put( + navigationActions.replaceScreen({ + screen: ScreenNames.JoinCommunityScreen, + params: { + validCode, + }, + }) + ) + .put( + communities.actions.createNetwork({ + ownership: CommunityOwnership.User, + peers: validPairs, + }) + ) + .run() + }) + + test.skip('opens channel list screen if the same url has been used', async () => { + store.dispatch( + initActions.setWebsocketConnected({ + dataPort: 5001, + }) + ) + + store.dispatch(communities.actions.addNewCommunity(community)) + + store.dispatch( + // @ts-expect-error + identity.actions.addNewIdentity({ ..._identity, userCertificate: 'certificate' }) + ) + + store.dispatch(communities.actions.setCurrentCommunity(community.id)) + + const reducer = combineReducers(reducers) + await expectSaga(deepLinkSaga, initActions.deepLink(validCode)) + .withReducer(reducer) + .withState(store.getState()) + .put( + navigationActions.replaceScreen({ + screen: ScreenNames.ChannelListScreen, + }) + ) + .not.put( + communities.actions.createNetwork({ + ownership: CommunityOwnership.User, + peers: validPairs, + }) + ) + .run() + }) + + test('displays error if user already belongs to a community', async () => { + store.dispatch( + initActions.setWebsocketConnected({ + dataPort: 5001, + }) + ) + + store.dispatch(communities.actions.addNewCommunity(community)) + + store.dispatch(communities.actions.setCurrentCommunity(community.id)) + const reducer = combineReducers(reducers) + await expectSaga(deepLinkSaga, initActions.deepLink(validCode)) + .withReducer(reducer) + .withState(store.getState()) + .not.put( + communities.actions.createNetwork({ + ownership: CommunityOwnership.User, + peers: validPairs, + }) + ) + .run() + }) + + test('continues if link used mid registration', async () => { + store.dispatch( + initActions.setWebsocketConnected({ + dataPort: 5001, + }) + ) + + store.dispatch(communities.actions.addNewCommunity(community)) + + store.dispatch( + // @ts-expect-error + identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) + ) + + store.dispatch(communities.actions.setCurrentCommunity(community.id)) + + const reducer = combineReducers(reducers) + await expectSaga(deepLinkSaga, initActions.deepLink(validCode)) + .withReducer(reducer) + .withState(store.getState()) + .put( + navigationActions.replaceScreen({ + screen: ScreenNames.UsernameRegistrationScreen, + params: undefined, + }) + ) + .not.put( + communities.actions.createNetwork({ + ownership: CommunityOwnership.User, + peers: validPairs, + }) + ) + .run() + }) + + test.skip('continues if link used mid registration and locks input while waiting for server response', async () => { + store.dispatch( + initActions.setWebsocketConnected({ + dataPort: 5001, + }) + ) + + store.dispatch(communities.actions.addNewCommunity(community)) + + store.dispatch( + // @ts-expect-error + identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) + ) + + store.dispatch(communities.actions.setCurrentCommunity(community.id)) + + store.dispatch(connection.actions.setTorConnectionProcess(ConnectionProcessInfo.REGISTERING_USER_CERTIFICATE)) + + const reducer = combineReducers(reducers) + await expectSaga(deepLinkSaga, initActions.deepLink(validCode)) + .withReducer(reducer) + .withState(store.getState()) + .put( + navigationActions.replaceScreen({ + screen: ScreenNames.UsernameRegistrationScreen, + params: { fetching: true }, + }) + ) + .not.put( + communities.actions.createNetwork({ + ownership: CommunityOwnership.User, + peers: validPairs, + }) + ) + .run() + }) +}) diff --git a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts index ca965b064a..4d36c1be45 100644 --- a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts +++ b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts @@ -1,6 +1,6 @@ import { PayloadAction } from '@reduxjs/toolkit' import { select, delay, put } from 'typed-redux-saga' -import { communities, connection, identity } from '@quiet/state-manager' +import { communities, connection, getInvitationCodes, identity } from '@quiet/state-manager' import { ScreenNames } from '../../../const/ScreenNames.enum' import { navigationActions } from '../../navigation/navigation.slice' import { initSelectors } from '../init.selectors' @@ -28,6 +28,7 @@ export function* deepLinkSaga(action: PayloadAction Date: Thu, 7 Sep 2023 19:40:51 +0200 Subject: [PATCH 26/28] Adjust e2e tests --- packages/common/src/invitationCode.ts | 18 +++++++++++++++++ .../src/tests/invitationLink.test.ts | 8 +++++--- .../e2e-tests/src/tests/twoClients.test.ts | 3 ++- .../invitationCode/invitationCode.ts | 20 +------------------ 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts index 3949dedfb8..e5e6af26f7 100644 --- a/packages/common/src/invitationCode.ts +++ b/packages/common/src/invitationCode.ts @@ -112,3 +112,21 @@ export const invitationCodeValid = (peerId: string, onionAddress: string): boole } return true } + +export const getInvitationPairs = (code: string) => { + /** + * @param code =&= + */ + const pairs = code.split('&') + const codes: InvitationPair[] = [] + for (const pair of pairs) { + const [peerId, address] = pair.split('=') + if (!peerId || !address) continue + if (!invitationCodeValid(peerId, address)) continue + codes.push({ + peerId: peerId, + onionAddress: address, + }) + } + return codes +} diff --git a/packages/e2e-tests/src/tests/invitationLink.test.ts b/packages/e2e-tests/src/tests/invitationLink.test.ts index 05cce35a94..0b4e917019 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, invitationDeepUrl } from '@quiet/common' +import { capitalizeFirstLetter, getInvitationPairs, invitationDeepUrl } from '@quiet/common' import { execSync } from 'child_process' import { type SupportedPlatformDesktop } from '@quiet/types' @@ -132,7 +132,7 @@ describe('New user joins using invitation link while having app opened', () => { it.skip('Guest clicks invitation link with invalid invitation code', async () => { // Fix when modals ordering is fixed (joining modal hiddes warning modal) console.log('opening invalid code') - execSync(`xdg-open ${invitationDeepUrl('invalidcode')}`) + execSync(`xdg-open ${invitationDeepUrl([{ peerId: 'invalid', onionAddress: 'alsoInvalid' }])}`) }) it.skip('Guest sees modal with warning about invalid code, closes it', async () => { @@ -155,7 +155,9 @@ describe('New user joins using invitation link while having app opened', () => { win32: 'start', } - execSync(`${command[process.platform as SupportedPlatformDesktop]} ${invitationDeepUrl(url.hash.substring(1))}`) + const pairs = getInvitationPairs(url.hash.substring(1)) + expect(pairs).not.toBe([]) + execSync(`${command[process.platform as SupportedPlatformDesktop]} ${invitationDeepUrl(pairs)}`) console.log('Guest opened invitation link') }) diff --git a/packages/e2e-tests/src/tests/twoClients.test.ts b/packages/e2e-tests/src/tests/twoClients.test.ts index 60a85cfdad..fc0ced5a10 100644 --- a/packages/e2e-tests/src/tests/twoClients.test.ts +++ b/packages/e2e-tests/src/tests/twoClients.test.ts @@ -152,7 +152,7 @@ describe('Two Clients', () => { await joinCommunityModal.submit() }) - it('RegisterUsernameModal - User tries to register already taken username, sees error', async () => { + it.skip('RegisterUsernameModal - User tries to register already taken username, sees error', async () => { console.log('new user - 4') registerModal2 = new RegisterUsernameModal(guestApp.driver) const isRegisterModal2 = await registerModal2.element.isDisplayed() @@ -165,6 +165,7 @@ describe('Two Clients', () => { it('RegisterUsernameModal - User successfully register not taken username', async () => { console.log('new user - 5') + registerModal2 = new RegisterUsernameModal(guestApp.driver) const isRegisterModal = await registerModal2.element.isDisplayed() expect(isRegisterModal).toBeTruthy() await registerModal2.clearInput() diff --git a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts index 9b1e6debc1..a3f5aff0a2 100644 --- a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts +++ b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.ts @@ -1,24 +1,6 @@ -import { Site, invitationCodeValid } from '@quiet/common' +import { Site, getInvitationPairs, invitationCodeValid } from '@quiet/common' import { InvitationPair } from '@quiet/types' -const getInvitationPairs = (code: string) => { - /** - * @param code =&= - */ - const pairs = code.split('&') - const codes: InvitationPair[] = [] - for (const pair of pairs) { - const [peerId, address] = pair.split('=') - if (!peerId || !address) continue - if (!invitationCodeValid(peerId, address)) continue - codes.push({ - peerId: peerId, - onionAddress: address, - }) - } - return codes -} - export const getInvitationCodes = (codeOrUrl: string): InvitationPair[] => { /** * Extract codes from invitation share url or return passed value for further validation From 5022d627fc30e44c6b5fe178b646632dfc53d765 Mon Sep 17 00:00:00 2001 From: Emi Date: Mon, 11 Sep 2023 13:13:20 +0200 Subject: [PATCH 27/28] Fix/skip deepLink mobile tests --- .../store/init/deepLink/deepLink.saga.test.ts | 47 ++----------------- .../src/store/init/deepLink/deepLink.saga.ts | 34 +------------- 2 files changed, 5 insertions(+), 76 deletions(-) diff --git a/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts b/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts index 0eddc579e1..7b1dcb5766 100644 --- a/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts +++ b/packages/mobile/src/store/init/deepLink/deepLink.saga.test.ts @@ -3,7 +3,7 @@ import { combineReducers } from '@reduxjs/toolkit' import { reducers } from '../../root.reducer' import { Store } from '../../store.types' import { prepareStore } from '../../../tests/utils/prepareStore' -import { communities, Community, connection, identity } from '@quiet/state-manager' +import { communities, Community, connection, getInvitationCodes, identity } from '@quiet/state-manager' import { initActions } from '../init.slice' import { navigationActions } from '../../navigation/navigation.slice' import { ScreenNames } from '../../../const/ScreenNames.enum' @@ -16,12 +16,7 @@ describe('deepLinkSaga', () => { const id = '00d045ab' const validCode = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd' - const validPairs = [ - { - peerId: 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE', - onionAddress: 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd', - }, - ] + const validPairs = getInvitationCodes(validCode) const community: Community = { id, name: '', @@ -60,7 +55,6 @@ describe('deepLinkSaga', () => { dataPort: 5001, }) ) - const reducer = combineReducers(reducers) await expectSaga(deepLinkSaga, initActions.deepLink(validCode)) .withReducer(reducer) @@ -69,7 +63,7 @@ describe('deepLinkSaga', () => { navigationActions.replaceScreen({ screen: ScreenNames.JoinCommunityScreen, params: { - validCode, + code: validCode, }, }) ) @@ -139,40 +133,7 @@ describe('deepLinkSaga', () => { .run() }) - test('continues if link used mid registration', async () => { - store.dispatch( - initActions.setWebsocketConnected({ - dataPort: 5001, - }) - ) - - store.dispatch(communities.actions.addNewCommunity(community)) - - store.dispatch( - // @ts-expect-error - identity.actions.addNewIdentity({ ..._identity, userCertificate: null }) - ) - - store.dispatch(communities.actions.setCurrentCommunity(community.id)) - - const reducer = combineReducers(reducers) - await expectSaga(deepLinkSaga, initActions.deepLink(validCode)) - .withReducer(reducer) - .withState(store.getState()) - .put( - navigationActions.replaceScreen({ - screen: ScreenNames.UsernameRegistrationScreen, - params: undefined, - }) - ) - .not.put( - communities.actions.createNetwork({ - ownership: CommunityOwnership.User, - peers: validPairs, - }) - ) - .run() - }) + test.todo('continues if link used mid registration') test.skip('continues if link used mid registration and locks input while waiting for server response', async () => { store.dispatch( diff --git a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts index 4d36c1be45..5a0dd0f2ab 100644 --- a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts +++ b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts @@ -23,41 +23,9 @@ export function* deepLinkSaga(action: PayloadAction Date: Mon, 11 Sep 2023 13:56:33 +0200 Subject: [PATCH 28/28] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dec53b4fbd..e264e503de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ [unreleased] +* Changed registration process - user connects to the libp2p network directly instead of using registrar. Invitation link format changed. User csr is now saved to database. + * Fixed android stucking on username registration screen introduced in previous alpha. * Added creator username to initial channel message.