Skip to content

Commit 93ca0f7

Browse files
authored
Merge branch 'develop' into chore/run-e2e-on-mac-intel
2 parents 679864c + b415dc0 commit 93ca0f7

10 files changed

Lines changed: 122 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* Fixed trace logger toggles [#3045](https://github.com/TryQuiet/quiet/issues/3045)
2424
* Fixed auth issues when using QSS in AWS [#3128](https://github.com/TryQuiet/quiet/issues/3128)
2525
* Fixed bug around killing old tor process that results in an unhandled exception [#3135](https://github.com/TryQuiet/quiet/issues/3135)
26-
26+
* Fixed bug that caused a registration loop when QSS_ALLOWED is true but the endpoint is unset [#3140](https://github.com/TryQuiet/quiet/issues/3140)
2727

2828
### Chores
2929

@@ -35,6 +35,7 @@
3535

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

3940
## [6.3.0]
4041

packages/backend/src/nest/qss/qss-auth-conn.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { RoleName } from '../auth/services/roles/roles'
2121
import { Injectable } from '@nestjs/common'
2222
import { randomUUID } from 'crypto'
2323
import { SigChain } from '../auth/sigchain'
24+
import { QSSAuthConnStatus } from './qss.const'
2425

2526
@Injectable()
2627
export class QSSAuthConnection extends EventEmitter {
@@ -37,9 +38,14 @@ export class QSSAuthConnection extends EventEmitter {
3738
*/
3839
private _teamId: string | undefined = undefined
3940
/**
40-
* True when connected and operational
41+
* Status of LFA connection
42+
*
43+
* NOT_STARTED = Connection has been created but hasn't been started
44+
* STARTING = Connection is in use but hasn't finished identity handshake
45+
* ACTIVE = Connection is in use and the identity handshake was successful
46+
* INACTIVE = Connection was stopped/disconnected
4147
*/
42-
private _active: boolean = false
48+
private _connStatus: QSSAuthConnStatus = QSSAuthConnStatus.NOT_STARTED
4349
/**
4450
* Random ID for this connection
4551
*/
@@ -89,8 +95,16 @@ export class QSSAuthConnection extends EventEmitter {
8995
return this._joinStatus
9096
}
9197

98+
public get connStatus(): QSSAuthConnStatus {
99+
return this._connStatus
100+
}
101+
102+
/**
103+
* This is true when the connection is starting up or has successfully completed the identity handshake
104+
* and is actively syncing sigchain updates with QSS
105+
*/
92106
public get active(): boolean {
93-
return this._active
107+
return [QSSAuthConnStatus.STARTING, QSSAuthConnStatus.CONNECTED].includes(this.connStatus)
94108
}
95109

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

141155
this.logger.info(`Auth connection established with QSS`)
156+
this._connStatus = QSSAuthConnStatus.STARTING
142157
this._authConnection!.start()
143-
this._active = true
144158
}
145159

146160
/**
@@ -183,9 +197,9 @@ export class QSSAuthConnection extends EventEmitter {
183197
this._joinStatus = JoinStatus.JOINED
184198
}
185199

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

@@ -285,7 +299,7 @@ export class QSSAuthConnection extends EventEmitter {
285299
} catch (e) {
286300
this.logger.error(`Error while stopping auth connection with QSS for team ID ${this.teamId}`, e)
287301
} finally {
288-
this._active = false
302+
this._connStatus = QSSAuthConnStatus.INACTIVE
289303
}
290304
}
291305
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
export const CLIENT_TRANSPORTS = ['websocket']
22
export const QSS_RECONNECT_DELAY_MS = 60_000
3+
4+
export enum QSSAuthConnStatus {
5+
NOT_STARTED = 'NOT_STARTED',
6+
INACTIVE = 'INACTIVE',
7+
STARTING = 'STARTING',
8+
CONNECTED = 'CONNECTED',
9+
}

packages/backend/src/nest/qss/qss.service.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ import { IpfsModule } from '../ipfs/ipfs.module'
4747
import { logEntryToLogUpdate } from '../storage/orbitDb/util'
4848
import { OrbitDbModule } from '../storage/orbitDb/orbitdb.module'
4949
import { QSSAuthConnectionManager } from './qss-auth-conn-manager.service'
50+
import { QSSAuthConnection } from './qss-auth-conn'
51+
import { QSSAuthConnStatus } from './qss.const'
5052

5153
describe('QSSService', () => {
5254
let store: Store
@@ -63,6 +65,7 @@ describe('QSSService', () => {
6365
let libp2pParams: Libp2pNodeParams
6466
let mockedCreateSocket: any
6567
let mockedGetSocket: any
68+
let mockedGetAuthConnection: any
6669
let mockedSendMessage: any
6770
let mockedJoinStatus: any
6871
let addPendingMessageSpy: any
@@ -160,6 +163,10 @@ describe('QSSService', () => {
160163
mockedCaptchaVerified.mockRestore()
161164
mockedCaptchaVerified = undefined
162165
}
166+
if (mockedGetAuthConnection != null) {
167+
mockedGetAuthConnection.mockRestore()
168+
mockedGetAuthConnection = undefined
169+
}
163170
})
164171

165172
interface InitCommunitySettings {
@@ -483,6 +490,16 @@ describe('QSSService', () => {
483490
await initCommunity()
484491
const initStatusOrig = await qssService.getQssInitStatus()
485492
expect(initStatusOrig.qssSetup).toBeFalsy()
493+
mockedGetAuthConnection = jest
494+
.spyOn(qssAuthConnManager, 'getConnection')
495+
.mockImplementation((teamId: string): QSSAuthConnection => {
496+
return {
497+
active: true,
498+
joinStatus: JoinStatus.JOINED,
499+
connStatus: QSSAuthConnStatus.CONNECTED,
500+
on: (...args: any[]) => {},
501+
} as any
502+
})
486503

487504
mockedSendMessage = jest
488505
.spyOn(qssClient, 'sendMessage')

packages/backend/src/nest/qss/qss.service.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import { LocalDbService } from '../local-db/local-db.service'
4141
import { DLQDecryptEntry } from '../local-db/local-db.types'
4242
import { LogUpdate } from '../storage/orbitDb/orbitdb.types'
4343
import { logEntryToLogUpdate } from '../storage/orbitDb/util'
44-
import { QSS_RECONNECT_DELAY_MS } from './qss.const'
44+
import { QSS_RECONNECT_DELAY_MS, QSSAuthConnStatus } from './qss.const'
4545
import { CompoundError, InvitationDataV3, SocketActions, SocketEvents } from '@quiet/types'
4646
import { LocalDbEvents } from '../local-db/local-db.types'
4747
import { SocketService } from '../socket/socket.service'
@@ -558,6 +558,7 @@ export class QSSService extends EventEmitter implements OnModuleDestroy, OnModul
558558
}
559559

560560
private _stopLogPullInterval(teamId: string): void {
561+
this.logger.debug('Stopping log pull interval', teamId)
561562
const existingInterval = this._logPullIntervals.get(teamId)
562563
if (existingInterval != null) {
563564
clearInterval(existingInterval)
@@ -568,14 +569,15 @@ export class QSSService extends EventEmitter implements OnModuleDestroy, OnModul
568569
public startLogPullInterval(teamId: string): void {
569570
this.logger.debug('Starting log pull interval', teamId)
570571
if (this._logPullIntervals.has(teamId)) {
572+
this.logger.debug('Existing log pull interval, skipping', teamId)
571573
return
572574
}
573575

574576
void this._pullLatestLogEntriesForTeam(teamId)
575577

576578
const interval = setInterval(() => {
577579
void this._pullLatestLogEntriesForTeam(teamId)
578-
}, 30_000)
580+
}, 10_000)
579581

580582
this._logPullIntervals.set(teamId, interval)
581583
}
@@ -609,13 +611,19 @@ export class QSSService extends EventEmitter implements OnModuleDestroy, OnModul
609611
this.startLogPullInterval(teamId)
610612
}
611613

612-
authConnection?.on(QSSEvents.QSS_AUTH_CONNECTED, startLogPullInterval)
614+
authConnection?.on(QSSEvents.QSS_AUTH_CONNECTED, (teamId: string) => {
615+
this.startLogPullInterval(teamId)
616+
})
613617
authConnection?.on(QSSEvents.QSS_DISCONNECTED, () => {
614618
this.logger.info('Disconnected event received, stopping log entry pull interval', teamId)
615619
this._stopLogPullInterval(teamId)
616620
})
617621

618-
if (authConnection?.active) {
622+
if (
623+
authConnection?.connStatus === QSSAuthConnStatus.CONNECTED &&
624+
authConnection?.joinStatus === JoinStatus.JOINED
625+
) {
626+
this.logger.info('Already finished auth connection with QSS, starting log pull interval')
619627
startLogPullInterval()
620628
}
621629
}

packages/backend/src/nest/storage/orbitDb/identity/lfa/lfa-identity.provider.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ class LFAIdentityProvider implements IdentityProvider {
157157
try {
158158
// convert the hex string back to a signed envelope
159159
const signedEnvelope = this._hexToSignedEnvelope(signature)
160-
this.logger.warn('Serialized signature', signedEnvelope)
161160
// validate the user is on the chain
162161
const { user, sigchain } = this.getUserAndChain(signedEnvelope.author.name, signedEnvelope.teamId)
163162
// verify the signature against the keys stored on the chain for this user

packages/desktop/src/main/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ let browserWidth: number
177177
let browserHeight: number
178178

179179
// Default title bar must be hidden for macos because we have custom styles for it
180-
const titleBarStyle = process.platform !== 'win32' ? 'hidden' : 'default'
180+
const titleBarStyle = process.platform === 'darwin' ? 'hidden' : 'default'
181181
export const createWindow = async () => {
182182
logger.trace('Creating splash and main windows')
183183
logger.trace('Creating main window')

packages/desktop/src/renderer/components/CreateJoinCommunity/CreateCommunity/CreateCommunity.test.tsx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,54 @@ describe('Create community', () => {
263263
const OLD_ENV = process.env
264264
beforeEach(() => {
265265
jest.resetModules()
266-
process.env = { ...OLD_ENV, QSS_ALLOWED: 'true' }
266+
process.env = { ...OLD_ENV, QSS_ALLOWED: 'true', QSS_ENDPOINT: 'ws://localhost:80/' }
267267
})
268268
afterEach(() => {
269269
process.env = OLD_ENV
270270
})
271271

272-
it('shows ServerOfferComponent when QSS_ALLOWED is true and user submits community name', async () => {
272+
it(`doesn't ServerOfferComponent when QSS_ALLOWED is true and QSS_ENDPOINT is invalid and user submits community name`, async () => {
273+
const { store } = await prepareStore({
274+
[StoreKeys.Socket]: {
275+
...new SocketState(),
276+
isConnected: true,
277+
},
278+
[StoreKeys.Modals]: {
279+
...new ModalsInitialState(),
280+
[ModalName.createCommunityModal]: { open: true },
281+
},
282+
})
283+
284+
process.env.QSS_ENDPOINT = ''
285+
286+
renderComponent(
287+
<>
288+
<JoinCommunity />
289+
<CreateCommunity />
290+
</>,
291+
store
292+
)
293+
294+
// Confirm proper modal title is displayed
295+
const createCommunityDictionary = CreateCommunityDictionary()
296+
const createCommunityTitle = screen.getByText(createCommunityDictionary.header)
297+
expect(createCommunityTitle).toBeVisible()
298+
299+
// Click redirecting link
300+
const link = screen.getByTestId('CreateCommunityLink')
301+
await userEvent.click(link)
302+
303+
// Confirm user is being redirected to join community
304+
const joinCommunityDictionary = JoinCommunityDictionary()
305+
const joinCommunityTitle = await screen.findByText(joinCommunityDictionary.header)
306+
expect(joinCommunityTitle).toBeVisible()
307+
308+
// ServerOffer modal should appear
309+
expect(() => screen.getByTestId('ServerOffer-UseQuietServer')).toThrow()
310+
expect(() => screen.getByTestId('ServerOffer-NotNow')).toThrow()
311+
})
312+
313+
it('shows ServerOfferComponent when QSS_ALLOWED is true and QSS_ENDPOINT is valid and user submits community name', async () => {
273314
const { store } = await prepareStore({
274315
[StoreKeys.Socket]: {
275316
...new SocketState(),

packages/desktop/src/renderer/components/CreateJoinCommunity/CreateCommunity/CreateCommunity.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,25 @@ const CreateCommunity = () => {
4141
return
4242
}
4343
setPendingCommunityName(name)
44-
logger.warn(process.env.QSS_ALLOWED)
45-
if (process.env.QSS_ALLOWED === 'true') {
46-
setShowServerOffer(true)
47-
} else {
44+
logger.warn('QSS settings', process.env.QSS_ALLOWED, process.env.QSS_ENDPOINT)
45+
const createCommunityWithoutQSS = () => {
4846
dispatch(communities.actions.createCommunity({ name, useServer: false }))
4947
createUsernameModal.handleOpen()
5048
}
49+
if (process.env.QSS_ALLOWED === 'true') {
50+
try {
51+
new URL(process.env.QSS_ENDPOINT ?? '')
52+
setShowServerOffer(true)
53+
} catch (error) {
54+
logger.error(
55+
`QSS is allowed but the endpoint is invalid (endpoint provided = "${process.env.QSS_ENDPOINT}"`,
56+
error
57+
)
58+
createCommunityWithoutQSS()
59+
}
60+
} else {
61+
createCommunityWithoutQSS()
62+
}
5163
}
5264

5365
const handleServerOfferClose = (useServer: boolean) => {

0 commit comments

Comments
 (0)