Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Leblow committed Nov 16, 2023
1 parent ba5fd3e commit 01ce34e
Show file tree
Hide file tree
Showing 14 changed files with 119 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
PeerId as PeerIdType,
SaveCSRPayload,
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 @@ -479,7 +478,8 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
}
})
this.socketService.on(SocketActionTypes.SEND_COMMUNITY_METADATA, async (payload: CommunityMetadata) => {
await this.storageService?.updateCommunityMetadata(payload)
const meta = await this.storageService?.updateCommunityMetadata(payload)
this.serverIoProvider.io.emit(SocketActionTypes.COMMUNITY_METADATA_SAVED, meta)
})
this.socketService.on(SocketActionTypes.SAVE_USER_CSR, async (payload: SaveCSRPayload) => {
this.logger(`socketService - ${SocketActionTypes.SAVE_USER_CSR}`)
Expand Down Expand Up @@ -608,11 +608,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
)
this.storageService.on(StorageEvents.REPLICATED_COMMUNITY_METADATA, (payload: CommunityMetadata) => {
this.logger(`Storage - ${StorageEvents.REPLICATED_COMMUNITY_METADATA}: ${payload}`)
const communityMetadataPayload: CommunityMetadataPayload = {
rootCa: payload.rootCa,
ownerCertificate: payload.ownerCertificate,
}
this.serverIoProvider.io.emit(SocketActionTypes.SAVE_COMMUNITY_METADATA, communityMetadataPayload)
})
}
}
18 changes: 18 additions & 0 deletions packages/backend/src/nest/local-db/local-db.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,22 @@ export class LocalDbService {
const sortedPeers = sortPeers(peersAddresses, stats)
return sortedPeers
}

public async putOwnerOrbitDbIdentity(id: string): Promise<void> {
this.put(LocalDBKeys.OWNER_ORBIT_DB_IDENTITY, id)
}

public async getOwnerOrbitDbIdentity(): Promise<string> {
return this.get(LocalDBKeys.OWNER_ORBIT_DB_IDENTITY)
}

public async putUserRole(role: string): Promise<undefined> {
// FIXME: Implement
throw new Error('Implement me!')
}

public async getUserRole(): Promise<string> {
// FIXME: Implement
return 'owner'
}
}
1 change: 1 addition & 0 deletions packages/backend/src/nest/local-db/local-db.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export enum LocalDBKeys {
REGISTRAR = 'registrar',
PEERS = 'peers',
PSK = 'psk',
OWNER_ORBIT_DB_IDENTITY = 'ownerOrbitDbIdentity',
}
export type LocalDbStatus = 'opening' | 'open' | 'closing' | 'closed'
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@ export class RegistrationService extends EventEmitter implements OnModuleInit {
this.on(
RegistrationEvents.REGISTER_USER_CERTIFICATE,
async (payload: { csrs: string[]; certificates: string[]; id: string }) => {
// Lack of permsData means that we are not the owner of the community in the official model of the app, however anyone can modify the source code, put malicious permsData here, issue false certificates and try to trick other users.
await this.issueCertificates(payload)
}
)
}

private async issueCertificates(payload: { csrs: string[]; certificates: string[]; id?: string }) {
// Lack of permsData means that we are not the owner of the
// community in the official model of the app, however anyone can
// modify the source code, put malicious permsData here, issue
// false certificates and try to trick other users. To prevent
// that, peers verify that anything that is written to the
// certificate store is signed by the owner.
if (!this._permsData) {
if (payload.id) this.emit(RegistrationEvents.FINISHED_ISSUING_CERTIFICATES_FOR_ID, { id: payload.id })
return
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/nest/socket/socket.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ export class SocketService extends EventEmitter implements OnModuleInit {

const communityMetadataPayload: CommunityMetadata = {
id: payload.id,
ownerCertificate: payload.certificate,
rootCa: payload.permsData.certificate,
ownerCertificate: payload.certificate,
}
this.emit(SocketActionTypes.SEND_COMMUNITY_METADATA, communityMetadataPayload)
})
Expand Down
28 changes: 20 additions & 8 deletions packages/backend/src/nest/storage/storage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ export class StorageService extends EventEmitter {
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<CommunityMetadata>('community-metadata', {
Expand All @@ -265,16 +266,27 @@ export class StorageService extends EventEmitter {
await this.communityMetadata.load({ fetchEntryTimeout: 15000 })
}

public async updateCommunityMetadata(communityMetadata: CommunityMetadata) {
public async updateCommunityMetadata(newMeta: CommunityMetadata): Promise<CommunityMetadata | undefined> {
this.logger(`About to update community metadata`)
if (!communityMetadata.id) return
const meta = this.communityMetadata.get(communityMetadata.id)
if (meta?.ownerCertificate && meta?.rootCa) return
if (!newMeta.id) return

const oldMeta = this.communityMetadata.get(newMeta.id)
if (oldMeta?.ownerCertificate && oldMeta?.rootCa) {
return oldMeta
}

this.logger(`Updating community metadata`)
await this.communityMetadata.put(communityMetadata.id, {
...meta,
...communityMetadata,
})
// @ts-expect-error - OrbitDB's type declaration of OrbitDB lacks identity
const orbitDbIdentity = this.orbitDb.identity.id
const meta = {
...oldMeta,
...newMeta,
orbitDbIdentity,
}
await this.communityMetadata.put(meta.id, meta)
this.localDbService.putOwnerOrbitDbIdentity(orbitDbIdentity)

return meta
}

private async __stopOrbitDb() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export const psk = createSelector(communitiesSlice, reducerState => {
return reducerState.psk
})

export const ownerOrbitDbIdentity = createSelector(currentCommunity, currentCommunity => {
return currentCommunity?.orbitDbIdentity
})

export const invitationUrl = createSelector(currentCommunity, psk, (community, communityPsk) => {
const peerList = community?.peerList
if (!peerList || peerList?.length === 0) return ''
Expand Down
34 changes: 30 additions & 4 deletions packages/state-manager/src/sagas/communities/communities.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import {
type ResponseCreateNetworkPayload,
type ResponseRegistrarPayload,
type StorePeerListPayload,
type UpdateCommunityPayload,
type UpdateRegistrationAttemptsPayload,
CommunityMetadataPayload,
CommunityMetadata,
InvitationData,
} from '@quiet/types'

Expand All @@ -22,6 +21,33 @@ export class CommunitiesState {
public psk: string | undefined
}

// TODO: remove after setting strict in 'desktop' and 'mobile' packages
export interface Community {
// TODO: how to set default values for Community?
id: string
name?: string
CA?: null | {
rootCertString: string
rootKeyString: string
}
rootCa?: string
peerList?: string[]
registrarUrl?: string
registrar?: null | {
privateKey: string
address: string
}
onionAddress?: string
privateKey?: string
port?: number
registrationAttempts?: number
ownerCertificate?: string
// It might be nice to have community metadata be sort of mirrored
// on the backend and frontend in terms of structure. Perhaps a
// field like Community.meta that is of type CommunityMetadata.
orbitDbIdentity?: string
}

export const communitiesSlice = createSlice({
initialState: { ...new CommunitiesState() },
name: StoreKeys.Communities,
Expand All @@ -32,7 +58,7 @@ export const communitiesSlice = createSlice({
addNewCommunity: (state, action: PayloadAction<CommunityType>) => {
communitiesAdapter.addOne(state.communities, action.payload)
},
updateCommunity: (state, _action: PayloadAction<UpdateCommunityPayload>) => state,
updateCommunity: (state, _action: PayloadAction<CommunityType>) => state,
updateCommunityData: (state, action: PayloadAction<CommunityType>) => {
communitiesAdapter.updateOne(state.communities, {
id: action.payload.id,
Expand Down Expand Up @@ -89,7 +115,7 @@ export const communitiesSlice = createSlice({
},
})
},
saveCommunityMetadata: (state, _action: PayloadAction<CommunityMetadataPayload>) => state,
saveCommunityMetadata: (state, _action: PayloadAction<CommunityMetadata>) => state,
savePSK: (state, action: PayloadAction<string>) => {
state.psk = action.payload
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ export interface InitCommunityPayload {
peers?: string[]
}

export interface UpdateCommunityPayload {
id: string
rootCa: string
}

export interface LaunchRegistrarPayload {
id: string
peerId: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function* saveCommunityMetadataSaga(
communitiesActions.updateCommunity({
id: communityId,
rootCa: action.payload.rootCa,
orbitDbIdentity: action.payload.orbitDbIdentity,
})
)
yield* put(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
import { CertFieldsTypes, getCertFieldValue, loadCertificate } from '@quiet/identity'
import { call, put } from 'typed-redux-saga'
import { communitiesActions } from '../communities.slice'
import { type Certificate } from 'pkijs'

import { CertFieldsTypes, getCertFieldValue, loadCertificate } from '@quiet/identity'
import { type PayloadAction } from '@reduxjs/toolkit'

import { communitiesActions } from '../communities.slice'

export function* updateCommunitySaga(
action: PayloadAction<ReturnType<typeof communitiesActions.updateCommunity>['payload']>
): Generator {
const rootCa = loadCertificate(action.payload.rootCa)

const communityName = yield* call(getCertFieldValue, rootCa, CertFieldsTypes.commonName)
if (!communityName) {
console.error(`Could not retrieve ${CertFieldsTypes.commonName} from rootca`)
return
let rootCa: Certificate
let communityName: string | null = null

if (action.payload.rootCa) {
rootCa = loadCertificate(action.payload.rootCa)
communityName = yield* call(getCertFieldValue, rootCa, CertFieldsTypes.commonName)

if (!communityName) {
console.error(`Could not retrieve ${CertFieldsTypes.commonName} from rootca`)
}
}

const payload: { id: string, name?: string, rootCa?: string, orbitDbIdentity?: string } = {
id: action.payload.id
}

if (communityName) {
payload.name = communityName
}

if (action.payload.rootCa) {
payload.rootCa = action.payload.rootCa
}

const payload = {
id: action.payload.id,
rootCa: action.payload.rootCa,
name: communityName,
if (action.payload.orbitDbIdentity) {
payload.orbitDbIdentity = action.payload.orbitDbIdentity
}

yield* put(communitiesActions.updateCommunityData(payload))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,14 +255,9 @@ export function subscribe(socket: Socket) {
)
emit(identityActions.savedOwnerCertificate(payload.communityId))
})
socket.on(SocketActionTypes.SAVE_COMMUNITY_METADATA, (payload: CommunityMetadata) => {
log(`${SocketActionTypes.SAVE_COMMUNITY_METADATA}: ${payload}`)
emit(
communitiesActions.saveCommunityMetadata({
rootCa: payload.rootCa,
ownerCertificate: payload.ownerCertificate,
})
)
socket.on(SocketActionTypes.COMMUNITY_METADATA_SAVED, (payload: CommunityMetadata) => {
log(`${SocketActionTypes.COMMUNITY_METADATA_SAVED}: ${payload}`)
emit(communitiesActions.saveCommunityMetadata(payload))
})
socket.on(SocketActionTypes.LIBP2P_PSK_SAVED, (payload: { psk: string }) => {
log(`${SocketActionTypes.LIBP2P_PSK_SAVED}`)
Expand Down
13 changes: 3 additions & 10 deletions packages/types/src/community.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface Community {
registrationAttempts?: number
ownerCertificate?: string
psk?: string
orbitDbIdentity?: string
}

export enum CommunityOwnership {
Expand Down Expand Up @@ -59,11 +60,6 @@ export interface InitCommunityPayload {
peers?: string[]
}

export interface UpdateCommunityPayload {
id: string
rootCa: string
}

export interface LaunchRegistrarPayload {
id: string
peerId: string
Expand Down Expand Up @@ -110,9 +106,6 @@ export interface CommunityMetadata {
id: string
rootCa: string
ownerCertificate: string
}

export interface CommunityMetadataPayload {
rootCa: string
ownerCertificate: string
// Owner's OrbitDB identity
orbitDbIdentity?: string
}
2 changes: 1 addition & 1 deletion packages/types/src/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,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',
COMMUNITY_METADATA_SAVED = 'communityMetadataSaved',
SUBSCRIBE_FOR_ALL_CONVERSATIONS = 'subscribeToAllConversations',
SUBSCRIBE_FOR_DIRECT_MESSAGE_THREAD = 'subscribeToDirectMessageThread',
// T
Expand Down

0 comments on commit 01ce34e

Please sign in to comment.