diff --git a/lib/types/identity-service-types.js b/lib/types/identity-service-types.js --- a/lib/types/identity-service-types.js +++ b/lib/types/identity-service-types.js @@ -128,6 +128,11 @@ // on native, publishing prekeys to Identity is called directly from C++, // there is no need to expose it to JS +publishWebPrekeys?: (prekeys: SignedPrekeys) => Promise; + +getDeviceListHistoryForUser: ( + userID: string, + sinceTimestamp?: number, + ) => Promise<$ReadOnlyArray>; + +updateDeviceList?: (newDeviceList: SignedDeviceList) => Promise; } export type IdentityServiceAuthLayer = { @@ -159,6 +164,18 @@ +notifOneTimeKeys: $ReadOnlyArray, }; +// Device list types + +export type RawDeviceList = { + +devices: $ReadOnlyArray, + +timestamp: number, +}; + +export type SignedDeviceList = { + // JSON-stringified RawDeviceList + +rawDeviceList: string, +}; + export const ONE_TIME_KEYS_NUMBER = 10; export const identityDeviceTypes = Object.freeze({ diff --git a/native/identity-service/identity-service-context-provider.react.js b/native/identity-service/identity-service-context-provider.react.js --- a/native/identity-service/identity-service-context-provider.react.js +++ b/native/identity-service/identity-service-context-provider.react.js @@ -10,6 +10,7 @@ type OneTimeKeysResultValues, } from 'lib/types/crypto-types.js'; import { + type SignedDeviceList, type DeviceOlmOutboundKeys, deviceOlmOutboundKeysValidator, type IdentityServiceClient, @@ -449,6 +450,42 @@ return validatedResult; }, generateNonce: commRustModule.generateNonce, + getDeviceListHistoryForUser: async ( + userID: string, + sinceTimestamp?: number, + ) => { + const { + deviceID: authDeviceID, + userID: authUserID, + accessToken: token, + } = await getAuthMetadata(); + const result = await commRustModule.getDeviceListForUser( + authUserID, + authDeviceID, + token, + userID, + sinceTimestamp, + ); + const rawPayloads: string[] = JSON.parse(result); + const deviceLists: SignedDeviceList[] = rawPayloads.map(payload => + JSON.parse(payload), + ); + return deviceLists; + }, + updateDeviceList: async (newDeviceList: SignedDeviceList) => { + const { + deviceID: authDeviceID, + userID, + accessToken: authAccessToken, + } = await getAuthMetadata(); + const payload = JSON.stringify(newDeviceList); + await commRustModule.updateDeviceList( + userID, + authDeviceID, + authAccessToken, + payload, + ); + }, }), [getAuthMetadata], ); diff --git a/web/grpc/identity-service-client-wrapper.js b/web/grpc/identity-service-client-wrapper.js --- a/web/grpc/identity-service-client-wrapper.js +++ b/web/grpc/identity-service-client-wrapper.js @@ -8,6 +8,7 @@ SignedPrekeys, } from 'lib/types/crypto-types.js'; import { + type SignedDeviceList, type IdentityServiceAuthLayer, type IdentityServiceClient, type DeviceOlmOutboundKeys, @@ -432,6 +433,30 @@ request.setNewNotifPrekeys(notifPrekeyUpload); await client.refreshUserPrekeys(request); }; + + getDeviceListHistoryForUser: ( + userID: string, + sinceTimestamp?: number, + ) => Promise<$ReadOnlyArray> = async ( + userID, + sinceTimestamp, + ) => { + const client = this.authClient; + if (!client) { + throw new Error('Identity service client is not initialized'); + } + const request = new IdentityAuthStructs.GetDeviceListRequest(); + request.setUserId(userID); + if (sinceTimestamp) { + request.setSinceTimestamp(sinceTimestamp); + } + const response = await client.getDeviceListForUser(request); + const rawPayloads = response.getDeviceListUpdatesList(); + const deviceListUpdates: SignedDeviceList[] = rawPayloads.map(payload => + JSON.parse(payload), + ); + return deviceListUpdates; + }; } function authDeviceKeyUpload( @@ -473,5 +498,4 @@ return deviceKeyUpload; } - export { IdentityServiceClientWrapper };