Skip to content

Commit

Permalink
Merge pull request #1686 from TryQuiet/feature/1557
Browse files Browse the repository at this point in the history
Handle multiple invitation addresses
  • Loading branch information
EmiM authored Sep 11, 2023
2 parents 425abac + 7362b47 commit b2f76dd
Show file tree
Hide file tree
Showing 83 changed files with 895 additions and 617 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
5 changes: 1 addition & 4 deletions packages/backend/src/nest/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +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 '../libp2p/libp2p.utils'
import { createLibp2pAddress, createLibp2pListenAddress } from '@quiet/common'
const log = logger('test')

export interface Ports {
Expand Down Expand Up @@ -201,9 +201,6 @@ export const libp2pInstanceParams = async (): Promise<Libp2pNodeParams> => {
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],
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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, {
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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, {
Expand All @@ -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)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +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 '../libp2p/libp2p.utils'
import { createLibp2pAddress } from '@quiet/common'

jest.setTimeout(100_000)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ import {
StorePeerListPayload,
UploadFilePayload,
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'
Expand Down Expand Up @@ -165,17 +169,9 @@ 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)
if (registrarData) {
if ([ServiceState.LAUNCHING, ServiceState.LAUNCHED].includes(this.registrarState)) return
this.registrarState = ServiceState.LAUNCHING
}
if (community) {
await this.launchCommunity(community)
}
if (registrarData) {
await this.registrationService.launchRegistrar(registrarData)
}
}

public async closeAllServices(options: { saveTor: boolean } = { saveTor: false }) {
Expand Down Expand Up @@ -273,20 +269,22 @@ 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,
}
this.serverIoProvider.io.emit(SocketActionTypes.NETWORK, payload)
}

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) {
Expand Down Expand Up @@ -327,7 +325,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
Expand All @@ -336,6 +333,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
const _peerId = await peerIdFromKeys(restoredRsa.marshalPubKey(), restoredRsa.marshalPrivKey())

let peers = payload.peers
console.log(`Launching community ${payload.id}, payload peers: ${peers}`)
if (!peers || peers.length === 0) {
peers = [this.libp2pService.createLibp2pAddress(onionAddress, _peerId.toString())]
}
Expand All @@ -344,9 +342,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,
Expand Down Expand Up @@ -397,19 +392,9 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
this.registrationService.on(SocketActionTypes.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)
})
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)
})
Expand Down Expand Up @@ -446,18 +431,16 @@ 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) => {
// Event left for setting permsData purposes
this.logger(`socketService - ${SocketActionTypes.LAUNCH_REGISTRAR}`)

const communityData = await this.localDbService.get(LocalDBKeys.REGISTRAR)
if (!communityData) {
await this.localDbService.put(LocalDBKeys.REGISTRAR, args)
this.registrationService.permsData = {
certificate: args.rootCertString,
privKey: args.rootKeyString,
}
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.SEND_COMMUNITY_METADATA, async (payload: CommunityMetadata) => {
await this.storageService?.updateCommunityMetadata(payload)
})
this.socketService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, async (args: SaveOwnerCertificatePayload) => {
const saveCertificatePayload: SaveCertificatePayload = {
Expand All @@ -466,18 +449,10 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
}
await this.storageService?.saveCertificate(saveCertificatePayload)
})
this.socketService.on(SocketActionTypes.REGISTER_USER_CERTIFICATE, async (args: RegisterUserCertificatePayload) => {
// if (!this.socksProxyAgent) {
// this.createAgent()
// }

await this.registrationService.sendCertificateRegistrationRequest(
args.serviceAddress,
args.userCsr,
args.communityId,
120_000,
this.socksProxyAgent
)
this.socketService.on(SocketActionTypes.SAVE_USER_CSR, async (payload: SaveCSRPayload) => {
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_OWNER_CERTIFICATE,
Expand Down Expand Up @@ -592,5 +567,17 @@ 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(StorageEvents.REPLICATED_CSR, async (payload: { csr: string }) => {
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)
})
}
}
6 changes: 4 additions & 2 deletions packages/backend/src/nest/libp2p/libp2p.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -44,7 +44,7 @@ export class Libp2pService extends EventEmitter {
return createLibp2pListenAddress(address)
}

public async createInstance(params: Libp2pNodeParams): Promise<any> {
public async createInstance(params: Libp2pNodeParams): Promise<Libp2p> {
if (this.libp2pInstance) {
return this.libp2pInstance
}
Expand Down Expand Up @@ -118,6 +118,7 @@ export class Libp2pService extends EventEmitter {
dialInChunks.stop()

this.connectedPeers.set(remotePeerId, DateTime.utc().valueOf())
this.logger(`${this.connectedPeers.size} connected peers`)

this.emit(Libp2pEvents.PEER_CONNECTED, {
peers: [remotePeerId],
Expand All @@ -144,6 +145,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,
Expand Down
3 changes: 0 additions & 3 deletions packages/backend/src/nest/libp2p/libp2p.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down
Loading

0 comments on commit b2f76dd

Please sign in to comment.