Skip to content

Commit

Permalink
Refactor owner cert registration
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Leblow committed Mar 8, 2024
1 parent c17cb0d commit 5bd37ad
Show file tree
Hide file tree
Showing 33 changed files with 195 additions and 231 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
NetworkDataPayload,
NetworkInfo,
NetworkStats,
type SavedOwnerCertificatePayload,
PushNotificationPayload,
RegisterOwnerCertificatePayload,
RemoveDownloadStatus,
Expand Down Expand Up @@ -61,7 +62,7 @@ import { StorageEvents } from '../storage/storage.types'
import { LazyModuleLoader } from '@nestjs/core'
import Logger from '../common/logger'
import { emitError } from '../socket/socket.errors'
import { isPSKcodeValid } from '@quiet/common'
import { createLibp2pAddress, isPSKcodeValid } from '@quiet/common'
import { createRootCA } from '@quiet/identity'

@Injectable()
Expand Down Expand Up @@ -139,7 +140,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
}

this.attachSocketServiceListeners()
this.attachRegistrationListeners()
this.attachTorEventsListeners()
this.attachStorageListeners()

Expand Down Expand Up @@ -284,8 +284,8 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
const hiddenService = await this.tor.createNewHiddenService({ targetPort: this.ports.libp2pHiddenService })
await this.tor.destroyHiddenService(hiddenService.onionAddress.split('.')[0])

// Do we want to create the PeerId here? It doesn't necessarily
// have anything to do with Tor.
// TODO: Do we want to create the PeerId here? It doesn't necessarily have
// anything to do with Tor.
const peerId: PeerId = await PeerId.create()
const peerIdJson = peerId.toJSON()
this.logger(`Created network for peer ${peerId.toString()}. Address: ${hiddenService.onionAddress}`)
Expand All @@ -311,26 +311,50 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
return
}

// TODO: Should we save this network info in LevelDB at this point?
return network
}

public async createCommunity(payload: InitCommunityPayload): Promise<Community> {
public async createCommunity(payload: InitCommunityPayload): Promise<Community | undefined> {
this.logger('Creating community: peers:', payload.peers)

const notBeforeDate = new Date(Date.UTC(2010, 11, 28, 10, 10, 10))
const notAfterDate = new Date(Date.UTC(2030, 11, 28, 10, 10, 10))
const CA = createRootCA(
new Time({ type: 0, value: notBeforeDate }),
new Time({ type: 0, value: notAfterDate }),
payload.name
)
if (!payload.CA || !payload.rootCa) {
this.logger.error('CA and rootCa are required to create community')
return
}

if (!payload.ownerCsr) {
this.logger.error('ownerCsr is required to create community')
return
}

const psk = Libp2pService.generateLibp2pPSK().psk
let ownerCertResult: SavedOwnerCertificatePayload

try {
this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.REGISTERING_OWNER_CERTIFICATE)
ownerCertResult = await this.registrationService.registerOwnerCertificate({
communityId: payload.id,
userCsr: payload.ownerCsr,
permsData: {
certificate: payload.CA.rootCertString,
privKey: payload.CA.rootKeyString,
},
})
} catch (e) {
this.logger.error('Failed to register owner certificate')
return
}

const localAddress = createLibp2pAddress(payload.hiddenService.onionAddress, payload.peerId.id)

const community = {
id: payload.id,
name: payload.name,
CA,
rootCa: CA.rootCertString,
CA: payload.CA,
rootCa: payload.rootCa,
peerList: [localAddress],
ownerCertificate: ownerCertResult.network.certificate,
psk: psk,
}

Expand All @@ -354,6 +378,11 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
public async joinCommunity(payload: InitCommunityPayload): Promise<Community | undefined> {
this.logger('Joining community: peers:', payload.peers)

if (!payload.peers || payload.peers.length === 0) {
this.logger.error('Joining community: Peers required')
return
}

if (!payload.psk || !isPSKcodeValid(payload.psk)) {
this.logger.error('Joining community: Libp2p PSK is not valid')
emitError(this.serverIoProvider.io, {
Expand All @@ -374,8 +403,11 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
return
}

const localAddress = createLibp2pAddress(payload.hiddenService.onionAddress, payload.peerId.id)

const community = {
id: payload.id,
peerList: [...new Set([localAddress, ...payload.peers])],
psk: payload.psk,
ownerOrbitDbIdentity: payload.ownerOrbitDbIdentity,
}
Expand Down Expand Up @@ -459,19 +491,16 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
const restoredRsa = await PeerId.createFromJSON(network.peerId)
const peerId = await peerIdFromKeys(restoredRsa.marshalPubKey(), restoredRsa.marshalPrivKey())

let peers = community.peerList
const peers = community.peerList
this.logger(`Launching community ${community.id}: payload peers: ${peers}`)
if (!peers || peers.length === 0) {
peers = [this.libp2pService.createLibp2pAddress(onionAddress, peerId.toString())]
}

const params: Libp2pNodeParams = {
peerId,
listenAddresses: [this.libp2pService.createLibp2pListenAddress(onionAddress)],
agent: this.socksProxyAgent,
localAddress: this.libp2pService.createLibp2pAddress(onionAddress, peerId.toString()),
targetPort: this.ports.libp2pHiddenService,
peers,
peers: peers ?? [],
psk: Libp2pService.generateLibp2pPSK(community.psk).fullKey,
}
await this.libp2pService.createInstance(params)
Expand Down Expand Up @@ -524,16 +553,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
})
}

private attachRegistrationListeners() {
this.registrationService.on(SocketActionTypes.OWNER_CERTIFICATE_ISSUED, payload => {
// TODO: Update community in local DB and emit COMMUNITY_UPDATED event
this.serverIoProvider.io.emit(SocketActionTypes.OWNER_CERTIFICATE_ISSUED, payload)
})
this.registrationService.on(RegistrationEvents.ERROR, payload => {
emitError(this.serverIoProvider.io, payload)
})
}

private attachSocketServiceListeners() {
// Community
this.socketService.on(SocketActionTypes.CONNECTION, async () => {
Expand Down Expand Up @@ -562,7 +581,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
)
this.socketService.on(
SocketActionTypes.CREATE_COMMUNITY,
async (args: InitCommunityPayload, callback: (response: Community) => void) => {
async (args: InitCommunityPayload, callback: (response: Community | undefined) => void) => {
this.logger(`socketService - ${SocketActionTypes.CREATE_COMMUNITY}`)
callback(await this.createCommunity(args))
}
Expand Down Expand Up @@ -596,12 +615,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
this.logger(`socketService - ${SocketActionTypes.ADD_CSR}`)
await this.storageService?.saveCSR(payload)
})
this.socketService.on(
SocketActionTypes.REGISTER_OWNER_CERTIFICATE,
async (args: RegisterOwnerCertificatePayload) => {
await this.registrationService.registerOwnerCertificate(args)
}
)
// TODO: With the Community model on the backend, there is no need to call
// SET_COMMUNITY_CA_DATA anymore. We can call setPermsData when
// creating the community.
Expand Down
9 changes: 0 additions & 9 deletions packages/backend/src/nest/libp2p/libp2p.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,3 @@ export interface Libp2pNodeParams {
peers: string[]
psk: Uint8Array
}

export interface InitLibp2pParams {
peerId: any
address: string
addressPort: number
targetPort: number
bootstrapMultiaddrs: string[]
certs: Certificates
}
2 changes: 1 addition & 1 deletion packages/backend/src/nest/local-db/local-db.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common'
import { Level } from 'level'
import { InitCommunityPayload, NetworkInfo, NetworkStats, Identity, Community } from '@quiet/types'
import { type Community, type Identity, InitCommunityPayload, type NetworkInfo, NetworkStats } from '@quiet/types'
import { createLibp2pAddress, filterAndSortPeers } from '@quiet/common'
import { LEVEL_DB } from '../const'
import { LocalDBKeys, LocalDbStatus } from './local-db.types'
Expand Down
28 changes: 18 additions & 10 deletions packages/backend/src/nest/registration/registration.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Injectable, OnModuleInit } from '@nestjs/common'
import { EventEmitter } from 'events'
import { extractPendingCsrs, issueCertificate } from './registration.functions'
import { ErrorCodes, ErrorMessages, PermsData, RegisterOwnerCertificatePayload, SocketActionTypes } from '@quiet/types'
import {
ErrorCodes,
ErrorMessages,
PermsData,
RegisterOwnerCertificatePayload,
type SavedOwnerCertificatePayload,
SocketActionTypes,
} from '@quiet/types'
import { RegistrationEvents } from './registration.types'
import Logger from '../common/logger'
import { StorageService } from '../storage/storage.service'
Expand Down Expand Up @@ -93,21 +100,22 @@ export class RegistrationService extends EventEmitter implements OnModuleInit {
)
}

public async registerOwnerCertificate(payload: RegisterOwnerCertificatePayload): Promise<void> {
// TODO: This doesn't save the owner's certificate in OrbitDB, so perhaps we
// should rename it or look into refactoring so that it does save to OrbitDB.
// However, currently, this is called before the storage service is
// initialized.
public async registerOwnerCertificate(
payload: RegisterOwnerCertificatePayload
): Promise<SavedOwnerCertificatePayload> {
this.permsData = payload.permsData
const result = await issueCertificate(payload.userCsr.userCsr, this.permsData)
if (result?.cert) {
this.emit(SocketActionTypes.OWNER_CERTIFICATE_ISSUED, {
return {
communityId: payload.communityId,
network: { certificate: result.cert },
})
}
} else {
this.emit(SocketActionTypes.ERROR, {
type: SocketActionTypes.REGISTER_OWNER_CERTIFICATE,
code: ErrorCodes.SERVER_ERROR,
message: ErrorMessages.REGISTRATION_FAILED,
community: payload.communityId,
})
throw new Error('Failed to register owner certificate')
}
}

Expand Down
1 change: 0 additions & 1 deletion packages/backend/src/nest/socket/socket.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ describe('SocketService', () => {
SocketActionTypes.CREATE_NETWORK.valueOf(),
SocketActionTypes.CREATE_COMMUNITY.valueOf(),
SocketActionTypes.LAUNCH_COMMUNITY.valueOf(),
SocketActionTypes.REGISTER_OWNER_CERTIFICATE.valueOf(),
SocketActionTypes.REGISTER_USER_CERTIFICATE.valueOf(),
SocketActionTypes.ADD_CSR.valueOf(),
SocketActionTypes.SET_COMMUNITY_METADATA.valueOf(),
Expand Down
9 changes: 1 addition & 8 deletions packages/backend/src/nest/socket/socket.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,10 @@ export class SocketService extends EventEmitter implements OnModuleInit {
this.emit(SocketActionTypes.ADD_CSR, payload)
})

socket.on(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, async (payload: RegisterOwnerCertificatePayload) => {
this.logger(`Registering owner certificate (${payload.communityId})`)

this.emit(SocketActionTypes.REGISTER_OWNER_CERTIFICATE, payload)
this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.REGISTERING_OWNER_CERTIFICATE)
})

// ====== Community ======
socket.on(
SocketActionTypes.CREATE_COMMUNITY,
async (payload: InitCommunityPayload, callback: (response: Community) => void) => {
async (payload: InitCommunityPayload, callback: (response: Community | undefined) => void) => {
this.logger(`Creating community ${payload.id}`)
this.emit(SocketActionTypes.CREATE_COMMUNITY, payload, callback)
}
Expand Down
9 changes: 0 additions & 9 deletions packages/backend/src/nest/storage/storage.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@ export enum StorageEvents {
COMMUNITY_METADATA_STORED = 'communityMetadataStored',
}

export interface InitStorageParams {
communityId: string
peerId: any
onionAddress: string
targetPort: number
peers?: string[]
certs: Certificates
}

export interface CsrReplicatedPromiseValues {
promise: Promise<unknown>
resolveFunction: any
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
"type-check": "tsc -p tsconfig.build.json --noEmit",
"test": "jest --runInBand",
"test:watch": "jest --watchAll",
"rtl-test": "jest ./src/rtl-tests",
"rtl-test": "jest ./src/rtl-tests/community.create.test.tsx",
"regression-test:update": "cypress install && ./node_modules/.bin/cypress run --component --env type=base --config screenshotsFolder=cypress/snapshots/base-local",
"regression-test": "./node_modules/.bin/cypress run --component --env type=actual,SNAPSHOT_BASE_DIRECTORY=cypress/snapshots/base-local",
"regression-test:ci": "cypress install && ./node_modules/.bin/cypress run --component --env type=actual",
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src/rtl-tests/channel.main.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ describe('Channel', () => {

const community: Community = await factory.create<
ReturnType<typeof communities.actions.addNewCommunity>['payload']
>('Community', { rootCa: 'rootCa', privateKey: 'privateKey' })
>('Community', { rootCa: 'rootCa' })

const alice = await factory.create<ReturnType<typeof identity.actions.addNewIdentity>['payload']>('Identity', {
id: community.id,
Expand Down
19 changes: 4 additions & 15 deletions packages/desktop/src/rtl-tests/community.create.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,6 @@ describe('User', () => {
},
}
}
if (action === SocketActionTypes.REGISTER_OWNER_CERTIFICATE) {
const payload = input[1] as RegisterOwnerCertificatePayload
socket.socketClient.emit<SavedOwnerCertificatePayload>(SocketActionTypes.OWNER_CERTIFICATE_ISSUED, {
communityId: payload.communityId,
network: {
certificate: payload.permsData.certificate,
},
})
}
if (action === SocketActionTypes.CREATE_COMMUNITY) {
const payload = input[1] as InitCommunityPayload
socket.socketClient.emit<ResponseLaunchCommunityPayload>(SocketActionTypes.COMMUNITY_LAUNCHED, {
Expand All @@ -112,7 +103,7 @@ describe('User', () => {
},
})

return { id: payload.id }
return { id: payload.id, ownerCertificate: 'cert' }
}
}

Expand Down Expand Up @@ -175,19 +166,17 @@ describe('User', () => {
"Network/setLoadingPanelType",
"Modals/openModal",
"Identity/registerCertificate",
"Communities/updateCommunity",
"Identity/storeUserCertificate",
"Identity/savedOwnerCertificate",
"Communities/updateCommunityData",
"Communities/createCommunity",
"Communities/sendCommunityCaData",
"Files/checkForMissingFiles",
"Network/addInitializedCommunity",
"Communities/clearInvitationCodes",
"PublicChannels/channelsReplicated",
"Communities/updateCommunityData",
"PublicChannels/addChannel",
"Communities/sendCommunityMetadata",
"Identity/storeUserCertificate",
"Messages/addPublicChannelsMessagesBase",
"Communities/sendCommunityMetadata",
"PublicChannels/createGeneralChannel",
"PublicChannels/createChannel",
"Identity/saveUserCsr",
Expand Down
4 changes: 2 additions & 2 deletions packages/desktop/src/rtl-tests/community.join.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ describe('User', () => {
expect(actions).toMatchInlineSnapshot(`
Array [
"Communities/createNetwork",
"Communities/setInvitationCodes",
"Communities/addNewCommunity",
"Communities/setCurrentCommunity",
"Communities/setInvitationCodes",
"Identity/addNewIdentity",
"Modals/closeModal",
"Modals/openModal",
"Identity/addNewIdentity",
"Identity/registerUsername",
"Network/setLoadingPanelType",
"Modals/openModal",
Expand Down
2 changes: 0 additions & 2 deletions packages/desktop/src/rtl-tests/customProtocol.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ describe('Opening app through custom protocol', () => {
rootCa: '',
peerList: [],
onionAddress: '',
privateKey: '',
port: 0,
ownerCertificate: '',
}

Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src/rtl-tests/deep.linking.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ describe('Deep linking', () => {
Array [
"Communities/customProtocol",
"Communities/createNetwork",
"Communities/setInvitationCodes",
"Communities/addNewCommunity",
"Communities/setCurrentCommunity",
"Communities/setInvitationCodes",
"Communities/customProtocol",
]
`)
Expand Down
Loading

0 comments on commit 5bd37ad

Please sign in to comment.