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 d96a878b46..206c19740d 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -392,15 +392,51 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI return community } + public async downloadCommunityData(inviteData: any) { + this.logger('Downloading invite data', inviteData) + this.storageServerProxyService.setServerAddress(inviteData.serverAddress) + let downloadedData: ServerStoredCommunityMetadata + try { + downloadedData = await this.storageServerProxyService.downloadData(inviteData.cid) + } catch (e) { + this.logger.error(`Downloading community data failed`, e) + return + } + return { + psk: downloadedData.psk, + peers: downloadedData.peerList, + ownerOrbitDbIdentity: downloadedData.ownerOrbitDbIdentity, + } + } + public async joinCommunity(payload: InitCommunityPayload): Promise { this.logger('Joining community: peers:', payload.peers) + let metadata = { + psk: payload.psk, + peers: payload.peers, + ownerOrbitDbIdentity: payload.ownerOrbitDbIdentity, + } - if (!payload.peers || payload.peers.length === 0) { + const inviteData = payload.inviteData + if (inviteData) { + const downloadedData = await this.downloadCommunityData(inviteData) + if (!downloadedData) { + emitError(this.serverIoProvider.io, { + type: SocketActionTypes.DOWNLOAD_INVITE_DATA, + message: ErrorMessages.STORAGE_SERVER_CONNECTION_FAILED, + }) + return + } + metadata = downloadedData + } + this.logger('Joining community: metadata:', metadata) + + if (!metadata.peers || metadata.peers.length === 0) { this.logger.error('Joining community: Peers required') return } - if (!payload.psk || !isPSKcodeValid(payload.psk)) { + if (!metadata.psk || !isPSKcodeValid(metadata.psk)) { this.logger.error('Joining community: Libp2p PSK is not valid') emitError(this.serverIoProvider.io, { type: SocketActionTypes.LAUNCH_COMMUNITY, @@ -410,7 +446,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI return } - if (!payload.ownerOrbitDbIdentity) { + if (!metadata.ownerOrbitDbIdentity) { this.logger.error('Joining community: ownerOrbitDbIdentity is not valid') emitError(this.serverIoProvider.io, { type: SocketActionTypes.LAUNCH_COMMUNITY, @@ -424,9 +460,9 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI const community = { id: payload.id, - peerList: [...new Set([localAddress, ...payload.peers])], - psk: payload.psk, - ownerOrbitDbIdentity: payload.ownerOrbitDbIdentity, + peerList: [...new Set([localAddress, ...metadata.peers])], + psk: metadata.psk, + ownerOrbitDbIdentity: metadata.ownerOrbitDbIdentity, } const network = { diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx index c15a598c2c..99925cb42d 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/JoinCommunity/JoinCommunity.tsx @@ -1,5 +1,5 @@ import { communities, connection, errors, identity } from '@quiet/state-manager' -import { CommunityOwnership, InvitationData, SocketActionTypes } from '@quiet/types' +import { CommunityOwnership, CreateNetworkPayload, InvitationData, SocketActionTypes } from '@quiet/types' import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import PerformCommunityActionComponent from '../../../components/CreateJoinCommunity/PerformCommunityActionComponent' @@ -41,7 +41,11 @@ const JoinCommunity = () => { }, [currentCommunity]) const handleCommunityAction = (data: InvitationData) => { - dispatch(communities.actions.joinNetwork(data)) + const createNetworkPayload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + inviteData: data, + } + dispatch(communities.actions.createNetwork(createNetworkPayload)) } // From 'You can create a new community instead' link diff --git a/packages/desktop/src/renderer/sagas/invitation/customProtocol.saga.ts b/packages/desktop/src/renderer/sagas/invitation/customProtocol.saga.ts index 0e889f7ed1..5bbf2053c1 100644 --- a/packages/desktop/src/renderer/sagas/invitation/customProtocol.saga.ts +++ b/packages/desktop/src/renderer/sagas/invitation/customProtocol.saga.ts @@ -1,6 +1,6 @@ import { PayloadAction } from '@reduxjs/toolkit' import { select, put, delay } from 'typed-redux-saga' -import { InvitationData, InvitationDataVersion } from '@quiet/types' +import { CommunityOwnership, CreateNetworkPayload, InvitationData, InvitationDataVersion } from '@quiet/types' import { communities } from '@quiet/state-manager' import { socketSelectors } from '../socket/socket.selectors' import { ModalName } from '../modals/modals.types' @@ -102,5 +102,12 @@ export function* customProtocolSaga( return } - yield* put(communities.actions.joinNetwork(data)) + const payload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + inviteData: data, + } + + yield* put(communities.actions.createNetwork(payload)) + + // yield* put(communities.actions.joinNetwork(data)) } diff --git a/packages/mobile/src/screens/JoinCommunity/JoinCommunity.screen.tsx b/packages/mobile/src/screens/JoinCommunity/JoinCommunity.screen.tsx index f992945a03..7ffb1c5c2b 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 { InvitationData } from '@quiet/types' +import { CommunityOwnership, CreateNetworkPayload, InvitationData } from '@quiet/types' import { JoinCommunity } from '../../components/JoinCommunity/JoinCommunity.component' import { navigationActions } from '../../store/navigation/navigation.slice' import { ScreenNames } from '../../const/ScreenNames.enum' @@ -36,7 +36,11 @@ export const JoinCommunityScreen: FC = ({ route }) => const joinCommunityAction = useCallback( (data: InvitationData) => { - dispatch(communities.actions.joinNetwork(data)) + const payload: CreateNetworkPayload = { + ownership: CommunityOwnership.User, + inviteData: data, + } + dispatch(communities.actions.createNetwork(payload)) dispatch( navigationActions.navigation({ screen: ScreenNames.UsernameRegistrationScreen, diff --git a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts index 28d7a03fc8..0181a5003c 100644 --- a/packages/mobile/src/store/init/deepLink/deepLink.saga.ts +++ b/packages/mobile/src/store/init/deepLink/deepLink.saga.ts @@ -7,7 +7,7 @@ import { initSelectors } from '../init.selectors' import { initActions } from '../init.slice' import { appImages } from '../../../assets' import { replaceScreen } from '../../../RootNavigation' -import { InvitationData, InvitationDataVersion } from '@quiet/types' +import { CommunityOwnership, CreateNetworkPayload, InvitationData, InvitationDataVersion } from '@quiet/types' export function* deepLinkSaga(action: PayloadAction['payload']>): Generator { const code = action.payload @@ -102,7 +102,12 @@ export function* deepLinkSaga(action: PayloadAction state[StoreKeys.Connection] @@ -55,6 +56,15 @@ export const invitationUrl = createSelector( if (!ownerOrbitDbIdentity) return '' const initialPeers = sortedPeerList.slice(0, 3) const pairs = p2pAddressesToPairs(initialPeers) + const v2Data = { + id: '209348023', + ownerCertificate: 'ownerCertificate', + rootCa: 'rootCa', + ownerOrbitDbIdentity: ownerOrbitDbIdentity, + peerList: pairsToP2pAddresses(pairs), + psk: communityPsk, + } + console.log('V2 DATA:', JSON.stringify(v2Data)) return composeInvitationShareUrl({ pairs, psk: communityPsk, ownerOrbitDbIdentity }) } ) 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 719d9c2354..181c360eaa 100644 --- a/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts +++ b/packages/state-manager/src/sagas/communities/createNetwork/createNetwork.saga.ts @@ -5,15 +5,22 @@ import { generateId } from '../../../utils/cryptography/cryptography' import { communitiesActions } from '../communities.slice' import { identityActions } from '../../identity/identity.slice' import { createRootCA } from '@quiet/identity' -import { type Community, CommunityOwnership, type Identity, SocketActionTypes, NetworkInfo } from '@quiet/types' +import { + type Community, + CommunityOwnership, + type Identity, + SocketActionTypes, + NetworkInfo, + InvitationDataVersion, +} from '@quiet/types' import { Socket, applyEmitParams } from '../../../types' export function* createNetworkSaga( socket: Socket, action: PayloadAction['payload']> ) { - console.log('create network saga') - + const payload = action.payload + console.log('create network saga', payload) // Community IDs are only local identifiers const id = yield* call(generateId) @@ -29,7 +36,7 @@ export function* createNetworkSaga( rootKeyString: string } = null - if (action.payload.ownership === CommunityOwnership.Owner) { + if (payload.ownership === CommunityOwnership.Owner) { const notBeforeDate = new Date(Date.UTC(2010, 11, 28, 10, 10, 10)) const notAfterDate = new Date(Date.UTC(2030, 11, 28, 10, 10, 10)) @@ -43,13 +50,24 @@ export function* createNetworkSaga( const community: Community = { id, - name: action.payload.name, + name: payload.name, CA, rootCa: CA?.rootCertString, - psk: action.payload.psk, + psk: payload.psk, ownerOrbitDbIdentity: action.payload.ownerOrbitDbIdentity, } + if (payload.inviteData) { + switch (payload.inviteData.version) { + case InvitationDataVersion.v2: + community.inviteData = { + serverAddress: payload.inviteData.serverAddress, + cid: payload.inviteData.cid, + token: payload.inviteData.token, + } + } + } + yield* put(communitiesActions.addNewCommunity(community)) 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 c7f620567d..9260ded78c 100644 --- a/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts +++ b/packages/state-manager/src/sagas/communities/launchCommunity/launchCommunity.saga.ts @@ -61,6 +61,7 @@ export function* launchCommunitySaga( peers: peerList, psk: community.psk, ownerOrbitDbIdentity: community.ownerOrbitDbIdentity, + inviteData: community.inviteData, } yield* apply(socket, socket.emitWithAck, applyEmitParams(SocketActionTypes.LAUNCH_COMMUNITY, payload)) diff --git a/packages/types/src/community.ts b/packages/types/src/community.ts index 607a00fe1a..7c5441e951 100644 --- a/packages/types/src/community.ts +++ b/packages/types/src/community.ts @@ -1,5 +1,5 @@ import { type HiddenService, type PeerId, type Identity, type UserCsr } from './identity' -import { InvitationPair } from './network' +import { InvitationData, InvitationPair } from './network' export interface Community { id: string @@ -13,6 +13,11 @@ export interface Community { onionAddress?: string ownerCertificate?: string psk?: string + inviteData?: { + serverAddress: string + cid: string + token?: string + } ownerOrbitDbIdentity?: string } @@ -27,6 +32,7 @@ export interface CreateNetworkPayload { peers?: InvitationPair[] psk?: string ownerOrbitDbIdentity?: string + inviteData?: InvitationData } export interface NetworkInfo { @@ -54,6 +60,11 @@ export interface InitCommunityPayload { psk?: string ownerOrbitDbIdentity?: string ownerCsr?: UserCsr + inviteData?: { + serverAddress: string + cid: string + token?: string + } } export interface StorePeerListPayload {