Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[submodule "3rd-party/auth"]
path = 3rd-party/auth
url = https://github.com/TryQuiet/auth.git
branch = main
branch = fix/qss-auth-errors
[submodule "3rd-party/js-libp2p-noise"]
path = 3rd-party/js-libp2p-noise
url = https://github.com/TryQuiet/js-libp2p-noise.git
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

* Handle AWS QSS endpoints in invite links [#3024](https://github.com/TryQuiet/quiet/issues/3024)
* Fixes dialing on join when using AWS QSS [#3025](https://github.com/TryQuiet/quiet/issues/3025)
* Fix delay between sign-in and historical log entry pull from QSS [#3127](https://github.com/TryQuiet/quiet/issues/3127)

## [6.3.0]

Expand Down
32 changes: 23 additions & 9 deletions packages/backend/src/nest/qss/qss-auth-conn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { RoleName } from '../auth/services/roles/roles'
import { Injectable } from '@nestjs/common'
import { randomUUID } from 'crypto'
import { SigChain } from '../auth/sigchain'
import { QSSAuthConnStatus } from './qss.const'

@Injectable()
export class QSSAuthConnection extends EventEmitter {
Expand All @@ -37,9 +38,14 @@ export class QSSAuthConnection extends EventEmitter {
*/
private _teamId: string | undefined = undefined
/**
* True when connected and operational
* Status of LFA connection
*
* NOT_STARTED = Connection has been created but hasn't been started
* STARTING = Connection is in use but hasn't finished identity handshake
* ACTIVE = Connection is in use and the identity handshake was successful
* INACTIVE = Connection was stopped/disconnected
*/
private _active: boolean = false
private _connStatus: QSSAuthConnStatus = QSSAuthConnStatus.NOT_STARTED
/**
* Random ID for this connection
*/
Expand Down Expand Up @@ -89,8 +95,16 @@ export class QSSAuthConnection extends EventEmitter {
return this._joinStatus
}

public get connStatus(): QSSAuthConnStatus {
return this._connStatus
}

/**
* This is true when the connection is starting up or has successfully completed the identity handshake
* and is actively syncing sigchain updates with QSS
*/
public get active(): boolean {
return this._active
return [QSSAuthConnStatus.STARTING, QSSAuthConnStatus.ACTIVE].includes(this.connStatus)
}

public get id(): string {
Expand Down Expand Up @@ -127,7 +141,7 @@ export class QSSAuthConnection extends EventEmitter {
if (this._authConnection != null) {
// if we have an existing auth connection for this team check if it has been started and is active, if so
// do nothing
if (this._authConnection._started && this._active) {
if (this._authConnection._started && this.active) {
this.logger.error(`Auth connection already started with QSS for this team`, this.teamId)
return
}
Expand All @@ -139,8 +153,8 @@ export class QSSAuthConnection extends EventEmitter {
await this._initNewConn(sigChain)

this.logger.info(`Auth connection established with QSS`)
this._connStatus = QSSAuthConnStatus.STARTING
this._authConnection!.start()
this._active = true
}

/**
Expand Down Expand Up @@ -183,9 +197,9 @@ export class QSSAuthConnection extends EventEmitter {
this._joinStatus = JoinStatus.JOINED
}

// handle connected events and update the sigchain/join status
// Handle connected events and update the sigchain/join status
authConnection.on('connected', () => {
this._active = true
this._connStatus = QSSAuthConnStatus.ACTIVE
if (this.sigChainService.activeChainTeamName != null && this._joinStatus !== JoinStatus.JOINED) {
this.logger.debug(`Sending sync message because our chain is initialized`)
const sigChain = this.sigChainService.getActiveChain()
Expand All @@ -202,7 +216,7 @@ export class QSSAuthConnection extends EventEmitter {
// set the connection to inactive when disconnecting
authConnection.on('disconnected', event => {
this.logger.info(`LFA Disconnected!`, event)
this._active = false
this._connStatus = QSSAuthConnStatus.INACTIVE
this.emit(QSSEvents.QSS_DISCONNECTED, this.teamId)
})

Expand Down Expand Up @@ -285,7 +299,7 @@ export class QSSAuthConnection extends EventEmitter {
} catch (e) {
this.logger.error(`Error while stopping auth connection with QSS for team ID ${this.teamId}`, e)
} finally {
this._active = false
this._connStatus = QSSAuthConnStatus.INACTIVE
}
}
}
7 changes: 7 additions & 0 deletions packages/backend/src/nest/qss/qss.const.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
export const CLIENT_TRANSPORTS = ['websocket']
export const QSS_RECONNECT_DELAY_MS = 60_000

export enum QSSAuthConnStatus {
NOT_STARTED = 'NOT_STARTED',
INACTIVE = 'INACTIVE',
STARTING = 'STARTING',
ACTIVE = 'ACTIVE',
}
17 changes: 17 additions & 0 deletions packages/backend/src/nest/qss/qss.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import { IpfsModule } from '../ipfs/ipfs.module'
import { logEntryToLogUpdate } from '../storage/orbitDb/util'
import { OrbitDbModule } from '../storage/orbitDb/orbitdb.module'
import { QSSAuthConnectionManager } from './qss-auth-conn-manager.service'
import { QSSAuthConnection } from './qss-auth-conn'
import { QSSAuthConnStatus } from './qss.const'

describe('QSSService', () => {
let store: Store
Expand All @@ -63,6 +65,7 @@ describe('QSSService', () => {
let libp2pParams: Libp2pNodeParams
let mockedCreateSocket: any
let mockedGetSocket: any
let mockedGetAuthConnection: any
let mockedSendMessage: any
let mockedJoinStatus: any
let addPendingMessageSpy: any
Expand Down Expand Up @@ -160,6 +163,10 @@ describe('QSSService', () => {
mockedCaptchaVerified.mockRestore()
mockedCaptchaVerified = undefined
}
if (mockedGetAuthConnection != null) {
mockedGetAuthConnection.mockRestore()
mockedGetAuthConnection = undefined
}
})

interface InitCommunitySettings {
Expand Down Expand Up @@ -483,6 +490,16 @@ describe('QSSService', () => {
await initCommunity()
const initStatusOrig = await qssService.getQssInitStatus()
expect(initStatusOrig.qssSetup).toBeFalsy()
mockedGetAuthConnection = jest
.spyOn(qssAuthConnManager, 'getConnection')
.mockImplementation((teamId: string): QSSAuthConnection => {
return {
active: true,
joinStatus: JoinStatus.JOINED,
connStatus: QSSAuthConnStatus.ACTIVE,
on: (...args: any[]) => {},
} as any
})

mockedSendMessage = jest
.spyOn(qssClient, 'sendMessage')
Expand Down
13 changes: 9 additions & 4 deletions packages/backend/src/nest/qss/qss.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { LocalDbService } from '../local-db/local-db.service'
import { DLQDecryptEntry } from '../local-db/local-db.types'
import { LogUpdate } from '../storage/orbitDb/orbitdb.types'
import { logEntryToLogUpdate } from '../storage/orbitDb/util'
import { QSS_RECONNECT_DELAY_MS } from './qss.const'
import { QSS_RECONNECT_DELAY_MS, QSSAuthConnStatus } from './qss.const'
import { CompoundError, InvitationDataV3, SocketActions, SocketEvents } from '@quiet/types'
import { LocalDbEvents } from '../local-db/local-db.types'
import { SocketService } from '../socket/socket.service'
Expand Down Expand Up @@ -552,6 +552,7 @@ export class QSSService extends EventEmitter implements OnModuleDestroy, OnModul
}

private _stopLogPullInterval(teamId: string): void {
this.logger.debug('Stopping log pull interval', teamId)
const existingInterval = this._logPullIntervals.get(teamId)
if (existingInterval != null) {
clearInterval(existingInterval)
Expand All @@ -562,14 +563,15 @@ export class QSSService extends EventEmitter implements OnModuleDestroy, OnModul
public startLogPullInterval(teamId: string): void {
this.logger.debug('Starting log pull interval', teamId)
if (this._logPullIntervals.has(teamId)) {
this.logger.debug('Existing log pull interval, skipping', teamId)
return
}

void this._pullLatestLogEntriesForTeam(teamId)

const interval = setInterval(() => {
void this._pullLatestLogEntriesForTeam(teamId)
}, 30_000)
}, 10_000)

this._logPullIntervals.set(teamId, interval)
}
Expand Down Expand Up @@ -603,13 +605,16 @@ export class QSSService extends EventEmitter implements OnModuleDestroy, OnModul
this.startLogPullInterval(teamId)
}

authConnection?.on(QSSEvents.QSS_AUTH_CONNECTED, startLogPullInterval)
authConnection?.on(QSSEvents.QSS_AUTH_CONNECTED, (teamId: string) => {
this.startLogPullInterval(teamId)
})
authConnection?.on(QSSEvents.QSS_DISCONNECTED, () => {
this.logger.info('Disconnected event received, stopping log entry pull interval', teamId)
this._stopLogPullInterval(teamId)
})

if (authConnection?.active) {
if (authConnection?.connStatus === QSSAuthConnStatus.ACTIVE && authConnection?.joinStatus === JoinStatus.JOINED) {
this.logger.info('Already finished auth connection with QSS, starting log pull interval')
startLogPullInterval()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ class LFAIdentityProvider implements IdentityProvider {
try {
// convert the hex string back to a signed envelope
const signedEnvelope = this._hexToSignedEnvelope(signature)
this.logger.warn('Serialized signature', signedEnvelope)
// validate the user is on the chain
const { user, sigchain } = this.getUserAndChain(signedEnvelope.author.name, signedEnvelope.teamId)
// verify the signature against the keys stored on the chain for this user
Expand Down
Loading