Skip to content

Commit e66c02b

Browse files
committed
Merge branch 'decrypt-in-nse' into 7.1.0
2 parents c4966d0 + d3dc836 commit e66c02b

10 files changed

Lines changed: 91 additions & 39 deletions

File tree

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ describe('QPSService', () => {
5353

5454
const TOKEN = 'fake-device-token-abc123'
5555
const TEAM_ID = 'test-team-id'
56+
const DEVICE_TOKEN_PAYLOAD = {
57+
deviceToken: TOKEN,
58+
bundleId: 'com.quietmobile',
59+
platform: 'ios' as const,
60+
}
5661

5762
const successResponse = {
5863
ts: DateTime.utc().toMillis(),
@@ -106,14 +111,14 @@ describe('QPSService', () => {
106111
it('sends immediately when ready', async () => {
107112
setReady()
108113

109-
const result = await qpsService.register(TOKEN)
114+
const result = await qpsService.register(DEVICE_TOKEN_PAYLOAD)
110115

111116
expect(result?.payload).toEqual({ ucan: 'test-ucan' })
112117
expect(qssClient.sendMessage).toHaveBeenCalledWith(
113118
WebsocketEvents.REGISTER_DEVICE_TOKEN,
114119
expect.objectContaining({
115120
status: CommunityOperationStatus.SENDING,
116-
payload: { deviceToken: TOKEN, bundleId: 'com.quietmobile', teamId: TEAM_ID },
121+
payload: { ...DEVICE_TOKEN_PAYLOAD, teamId: TEAM_ID },
117122
}),
118123
true
119124
)
@@ -122,7 +127,7 @@ describe('QPSService', () => {
122127
it('stores UCAN in notification tokens store after successful registration', async () => {
123128
setReady()
124129

125-
await qpsService.register(TOKEN)
130+
await qpsService.register(DEVICE_TOKEN_PAYLOAD)
126131

127132
expect(notificationTokensStore.addToken).toHaveBeenCalledWith('test-user-id', 'test-ucan')
128133
})
@@ -131,7 +136,7 @@ describe('QPSService', () => {
131136
setReady()
132137
notificationTokensStore.addToken.mockRejectedValueOnce(new Error('store not initialized'))
133138

134-
const result = await qpsService.register(TOKEN)
139+
const result = await qpsService.register(DEVICE_TOKEN_PAYLOAD)
135140

136141
expect(result?.payload).toEqual({ ucan: 'test-ucan' })
137142
expect(notificationTokensStore.addToken).toHaveBeenCalledWith('test-user-id', 'test-ucan')
@@ -149,7 +154,7 @@ describe('QPSService', () => {
149154
)
150155
setReady()
151156

152-
const result = await disabled.register(TOKEN)
157+
const result = await disabled.register(DEVICE_TOKEN_PAYLOAD)
153158

154159
expect(result).toBeUndefined()
155160
expect(qssClient.sendMessage).not.toHaveBeenCalled()
@@ -162,7 +167,7 @@ describe('QPSService', () => {
162167
roles: { amIMemberOfRole: () => true },
163168
}
164169

165-
const result = await qpsService.register(TOKEN)
170+
const result = await qpsService.register(DEVICE_TOKEN_PAYLOAD)
166171

167172
expect(result).toBeUndefined()
168173
expect(qssClient.sendMessage).not.toHaveBeenCalled()
@@ -172,7 +177,7 @@ describe('QPSService', () => {
172177
qssClient.connected = true
173178
sigChainService.activeChain = null
174179

175-
const result = await qpsService.register(TOKEN)
180+
const result = await qpsService.register(DEVICE_TOKEN_PAYLOAD)
176181

177182
expect(result).toBeUndefined()
178183
expect(qssClient.sendMessage).not.toHaveBeenCalled()
@@ -182,8 +187,8 @@ describe('QPSService', () => {
182187
qssClient.connected = false
183188
sigChainService.activeChain = null
184189

185-
await qpsService.register('old-token')
186-
await qpsService.register(TOKEN)
190+
await qpsService.register({ ...DEVICE_TOKEN_PAYLOAD, deviceToken: 'old-token' })
191+
await qpsService.register(DEVICE_TOKEN_PAYLOAD)
187192

188193
// Now become ready and flush
189194
setReady()
@@ -196,7 +201,7 @@ describe('QPSService', () => {
196201
expect(qssClient.sendMessage).toHaveBeenCalledWith(
197202
WebsocketEvents.REGISTER_DEVICE_TOKEN,
198203
expect.objectContaining({
199-
payload: { deviceToken: TOKEN, bundleId: 'com.quietmobile', teamId: TEAM_ID },
204+
payload: { ...DEVICE_TOKEN_PAYLOAD, teamId: TEAM_ID },
200205
}),
201206
true
202207
)
@@ -208,7 +213,7 @@ describe('QPSService', () => {
208213
// Cache token while not ready
209214
qssClient.connected = false
210215
sigChainService.activeChain = null
211-
await qpsService.register(TOKEN)
216+
await qpsService.register(DEVICE_TOKEN_PAYLOAD)
212217
expect(qssClient.sendMessage).not.toHaveBeenCalled()
213218

214219
// Become ready and emit connected
@@ -220,7 +225,7 @@ describe('QPSService', () => {
220225
expect(qssClient.sendMessage).toHaveBeenCalledWith(
221226
WebsocketEvents.REGISTER_DEVICE_TOKEN,
222227
expect.objectContaining({
223-
payload: { deviceToken: TOKEN, bundleId: 'com.quietmobile', teamId: TEAM_ID },
228+
payload: { ...DEVICE_TOKEN_PAYLOAD, teamId: TEAM_ID },
224229
}),
225230
true
226231
)
@@ -229,7 +234,7 @@ describe('QPSService', () => {
229234
it('does not flush when QSS connects but sigchain is not joined', async () => {
230235
qssClient.connected = false
231236
sigChainService.activeChain = null
232-
await qpsService.register(TOKEN)
237+
await qpsService.register(DEVICE_TOKEN_PAYLOAD)
233238

234239
// QSS connects but sigchain still not joined
235240
qssClient.connected = true
@@ -245,7 +250,7 @@ describe('QPSService', () => {
245250
// Cache token: QSS connected but no sigchain
246251
qssClient.connected = true
247252
sigChainService.activeChain = null
248-
await qpsService.register(TOKEN)
253+
await qpsService.register(DEVICE_TOKEN_PAYLOAD)
249254
expect(qssClient.sendMessage).not.toHaveBeenCalled()
250255

251256
// QSS completes the join flow and the sigchain is now ready
@@ -259,7 +264,7 @@ describe('QPSService', () => {
259264
it('does not flush when QSS fully joins but QSS is not connected', async () => {
260265
qssClient.connected = false
261266
sigChainService.activeChain = null
262-
await qpsService.register(TOKEN)
267+
await qpsService.register(DEVICE_TOKEN_PAYLOAD)
263268

264269
// Join completes but the transport is still disconnected
265270
sigChainService.activeChain = {
@@ -277,7 +282,7 @@ describe('QPSService', () => {
277282
it('does not send twice after flushing', async () => {
278283
qssClient.connected = false
279284
sigChainService.activeChain = null
280-
await qpsService.register(TOKEN)
285+
await qpsService.register(DEVICE_TOKEN_PAYLOAD)
281286

282287
setReady()
283288
qssService.emitEvent(QSSEvents.QSS_FULLY_JOINED)

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@ import { NotificationTokensStore } from '../storage/notifications/notificationTo
1919
import { QSSService } from '../qss/qss.service'
2020
import { JoinStatus } from '../libp2p/libp2p.auth'
2121

22-
const BUNDLE_ID = 'com.quietmobile'
2322
const PUSH_BATCH_SIZE = 500 // FCM allows up to 500 tokens per batch request
2423
const LEAVE_TOMBSTONE_ACK_TIMEOUT_MS = 5_000
2524

25+
interface DeviceTokenPayload {
26+
deviceToken: string
27+
bundleId: string
28+
platform: 'ios' | 'android'
29+
}
30+
2631
@Injectable()
2732
export class QPSService implements OnModuleInit {
2833
private readonly logger = createLogger('qps:service')
29-
private _pendingDeviceToken: string | undefined = undefined
34+
private _pendingDeviceToken: DeviceTokenPayload | undefined = undefined
3035

3136
constructor(
3237
@Inject(QPS_ALLOWED) private readonly qpsAllowed: boolean,
@@ -46,9 +51,9 @@ export class QPSService implements OnModuleInit {
4651
}
4752

4853
onModuleInit() {
49-
this.socketService.on(SocketActions.SEND_DEVICE_TOKEN, async (payload: { deviceToken: string }) => {
54+
this.socketService.on(SocketActions.SEND_DEVICE_TOKEN, async (payload: DeviceTokenPayload) => {
5055
this.logger.info('Received device token from frontend')
51-
await this.register(payload.deviceToken)
56+
await this.register(payload)
5257
})
5358

5459
this.qssService.on(QSSEvents.QSS_FULLY_JOINED, () => this._flushPendingToken())
@@ -59,22 +64,22 @@ export class QPSService implements OnModuleInit {
5964

6065
/**
6166
* Registers the device token with QPS
62-
* @param deviceToken
67+
* @param payload
6368
* @returns
6469
*/
65-
public async register(deviceToken: string): Promise<QPSRegisterResponse | undefined> {
70+
public async register(payload: DeviceTokenPayload): Promise<QPSRegisterResponse | undefined> {
6671
if (!this.enabled) {
6772
this.logger.warn('QPS not enabled, skipping registration')
6873
return undefined
6974
}
7075

7176
if (!this.ready) {
7277
this.logger.info('QSS not connected or sigchain not joined, caching device token')
73-
this._pendingDeviceToken = deviceToken
78+
this._pendingDeviceToken = payload
7479
return undefined
7580
}
7681

77-
return this._register(deviceToken)
82+
return this._register(payload)
7883
}
7984

8085
public async tombstoneCurrentUserNotificationTokens(): Promise<boolean> {
@@ -277,15 +282,20 @@ export class QPSService implements OnModuleInit {
277282
}
278283
}
279284

280-
private async _register(deviceToken: string): Promise<QPSRegisterResponse | undefined> {
285+
private async _register(payload: DeviceTokenPayload): Promise<QPSRegisterResponse | undefined> {
281286
this.logger.info('Registering device token')
282287
try {
283288
const response = await this.qssClient.sendMessage<QPSRegisterResponse>(
284289
WebsocketEvents.REGISTER_DEVICE_TOKEN,
285290
{
286291
ts: DateTime.utc().toMillis(),
287292
status: CommunityOperationStatus.SENDING,
288-
payload: { deviceToken, bundleId: BUNDLE_ID, teamId: this.sigChainService.team.id },
293+
payload: {
294+
deviceToken: payload.deviceToken,
295+
bundleId: payload.bundleId,
296+
platform: payload.platform,
297+
teamId: this.sigChainService.team.id,
298+
},
289299
} satisfies QPSRegisterMessage,
290300
true
291301
)

packages/backend/src/nest/qps/qps.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BaseWebsocketMessage } from '../qss/qss.types'
33
export interface QPSRegisterPayload {
44
deviceToken: string
55
bundleId: string
6+
platform: 'ios' | 'android'
67
teamId: string
78
}
89

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,12 @@ export class SocketService extends EventEmitter implements OnModuleInit {
239239
})
240240

241241
// ====== Push Notifications ======
242-
socket.on(SocketActions.SEND_DEVICE_TOKEN, async (payload: { deviceToken: string }) => {
243-
this.emit(SocketActions.SEND_DEVICE_TOKEN, payload)
244-
})
242+
socket.on(
243+
SocketActions.SEND_DEVICE_TOKEN,
244+
async (payload: { deviceToken: string; bundleId: string; platform: 'ios' | 'android' }) => {
245+
this.emit(SocketActions.SEND_DEVICE_TOKEN, payload)
246+
}
247+
)
245248
})
246249

247250
// Ensure the underlying connections get closed. See:

packages/mobile/src/store/pushNotifications/pushNotifications.master.saga.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { all, fork, takeEvery, call, put, select, take, cancelled, delay } from 'typed-redux-saga'
22
import { eventChannel } from 'redux-saga'
33
import { NativeModules, AppState, AppStateStatus, Platform } from 'react-native'
4+
import DeviceInfo from 'react-native-device-info'
45
import nativeEventEmitter from '../nativeServices/events/nativeEventEmitter'
56
import { pushNotificationsActions } from './pushNotifications.slice'
67
import { pushNotificationsSelectors } from './pushNotifications.selectors'
@@ -76,7 +77,15 @@ function* sendDeviceTokenToBackendSaga(token: string): Generator {
7677
logger.info('Waiting for websocket connection before sending FCM token')
7778
yield* call(waitForWebsocketConnectionSaga)
7879
logger.info('Sending FCM token to backend')
79-
yield* put(pushNotifications.actions.sendDeviceTokenToBackend(token))
80+
const platform = Platform.OS === 'android' ? 'android' : 'ios'
81+
const bundleId = DeviceInfo.getBundleId()
82+
yield* put(
83+
pushNotifications.actions.sendDeviceTokenToBackend({
84+
deviceToken: token,
85+
bundleId,
86+
platform,
87+
})
88+
)
8089
}
8190

8291
function* syncCurrentDeviceTokenSaga(): Generator {

packages/state-manager/src/sagas/pushNotifications/pushNotifications.slice.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ export const pushNotificationsSlice = createSlice({
77
initialState: { ...new PushNotificationsState() },
88
name: StoreKeys.PushNotifications,
99
reducers: {
10-
sendDeviceTokenToBackend: (state, _action: PayloadAction<string>) => state,
10+
sendDeviceTokenToBackend: (
11+
state,
12+
_action: PayloadAction<{
13+
deviceToken: string
14+
bundleId: string
15+
platform: 'ios' | 'android'
16+
}>
17+
) => state,
1118
},
1219
})
1320

packages/state-manager/src/sagas/pushNotifications/sendDeviceToken.saga.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,15 @@ import { applyEmitParams } from '../../types'
77

88
const logger = createLogger('sendDeviceTokenSaga')
99

10-
export function* sendDeviceTokenSaga(socket: Socket, action: PayloadAction<string>): Generator {
11-
const deviceToken = action.payload
10+
export function* sendDeviceTokenSaga(
11+
socket: Socket,
12+
action: PayloadAction<{
13+
deviceToken: string
14+
bundleId: string
15+
platform: 'ios' | 'android'
16+
}>
17+
): Generator {
18+
const payload = action.payload
1219
logger.info('Sending device token to backend')
13-
yield* apply(socket, socket.emit, applyEmitParams(SocketActions.SEND_DEVICE_TOKEN, { deviceToken }))
20+
yield* apply(socket, socket.emit, applyEmitParams(SocketActions.SEND_DEVICE_TOKEN, payload))
1421
}

packages/state-manager/src/utils/tests/factories.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -677,9 +677,15 @@ export const getSocketFactory = async () => {
677677
factory.define<boolean>(SocketActions.TOGGLE_P2P, Object, () => true)
678678

679679
// Push notification events
680-
factory.define<{ deviceToken: string }>(SocketActions.SEND_DEVICE_TOKEN, Object, {
681-
deviceToken: 'test-device-token',
682-
})
680+
factory.define<{ deviceToken: string; bundleId: string; platform: 'ios' | 'android' }>(
681+
SocketActions.SEND_DEVICE_TOKEN,
682+
Object,
683+
{
684+
deviceToken: 'test-device-token',
685+
bundleId: 'com.quietmobile',
686+
platform: 'ios',
687+
}
688+
)
683689

684690
return factory
685691
}

packages/types/src/socket.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,11 @@ export interface SocketActionsMap {
214214
[SocketActions.HCAPTCHA_REQUEST]: EmitEvent<HCaptchaRequest>
215215

216216
// ====== Push Notifications ======
217-
[SocketActions.SEND_DEVICE_TOKEN]: EmitEvent<{ deviceToken: string }>
217+
[SocketActions.SEND_DEVICE_TOKEN]: EmitEvent<{
218+
deviceToken: string
219+
bundleId: string
220+
platform: 'ios' | 'android'
221+
}>
218222

219223
// ====== Misc ======
220224
[SocketActions.TOGGLE_P2P]: EmitEvent<boolean, (response: boolean) => void>

0 commit comments

Comments
 (0)