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 @@ -62,6 +62,13 @@ +getOutboundKeysForUser: ( userID: string, ) => Promise; + +getDeviceListHistoryForUser: ( + userID: string, + sinceTimestamp?: number, + ) => Promise<$ReadOnlyArray>; + +updateDeviceList: ( + newDeviceList: RawDeviceListPayload, + ) => Promise; } export type IdentityServiceAuthLayer = { @@ -90,4 +97,20 @@ +username: string, }; +// Device list types + +export type RawDeviceList = { + +devices: $ReadOnlyArray, + +timestamp: number, +}; + +export type RawDeviceListPayload = { + +devices: $ReadOnlyArray, +}; + +export type SignedDeviceList = { + // JSON-stringified RawDeviceList + +rawDeviceList: string, +}; + export const ONE_TIME_KEYS_NUMBER = 10; 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 @@ -9,6 +9,8 @@ identityKeysBlobValidator, } from 'lib/types/crypto-types.js'; import { + type RawDeviceListPayload, + type SignedDeviceList, type DeviceOlmOutboundKeys, deviceOlmOutboundKeysValidator, type IdentityServiceClient, @@ -221,6 +223,44 @@ const { userID, accessToken } = JSON.parse(registrationResult); return { accessToken, userID, username }; }, + getDeviceListHistoryForUser: async ( + userID: string, + sinceTimestamp?: number, + ) => { + const { + deviceID: authDeviceID, + userID: authUserID, + accessToken, + } = await getAuthMetadata(); + const result = await commRustModule.getDeviceListForUser( + authUserID, + authDeviceID, + accessToken, + userID, + sinceTimestamp, + ); + const rawPayloads: string[] = JSON.parse(result); + const deviceLists: SignedDeviceList[] = rawPayloads.map(payload => + JSON.parse(payload), + ); + return deviceLists; + }, + updateDeviceList: async (newDeviceList: RawDeviceListPayload) => { + const { + deviceID: authDeviceID, + userID, + accessToken, + } = await getAuthMetadata(); + const payload = JSON.stringify(newDeviceList); + const response = await commRustModule.updateDeviceList( + userID, + authDeviceID, + accessToken, + payload, + ); + const signedDeviceList: SignedDeviceList = JSON.parse(response); + return signedDeviceList; + }, }), [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 @@ -2,6 +2,8 @@ import identityServiceConfig from 'lib/facts/identity-service.js'; import { + type RawDeviceListPayload, + type SignedDeviceList, type IdentityServiceAuthLayer, type IdentityServiceClient, type DeviceOlmOutboundKeys, @@ -202,6 +204,36 @@ return devicesKeys.filter(Boolean); }; + + 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; + }; + + updateDeviceList: ( + newDeviceList: RawDeviceListPayload, + ) => Promise = () => { + return Promise.reject('Updating device list is unsupported on web'); + }; } export { IdentityServiceClientWrapper };