diff --git a/ts/textsecure/AccountManager.preload.ts b/ts/textsecure/AccountManager.preload.ts index 7d730401dc..3977bbd182 100644 --- a/ts/textsecure/AccountManager.preload.ts +++ b/ts/textsecure/AccountManager.preload.ts @@ -9,6 +9,7 @@ import { BackupKey, } from '@signalapp/libsignal-client/dist/AccountKeys.js'; import type { RegisterAccountResponse } from '@signalapp/libsignal-client/dist/net'; +import { Base64 } from '@signalapp/types'; import EventTarget from './EventTarget.std.ts'; import { @@ -295,7 +296,7 @@ export default class AccountManager extends EventTarget { encryptDeviceName( name: string, identityKey: KeyPairType - ): string | undefined { + ): Base64 | undefined { if (!name) { return undefined; } @@ -306,17 +307,17 @@ export default class AccountManager extends EventTarget { syntheticIv: encrypted.syntheticIv, ciphertext: encrypted.ciphertext, }); - return Bytes.toBase64(bytes); + return Base64.fromBytes(bytes); } - async decryptDeviceName(base64: string): Promise { + async decryptDeviceName(base64: Base64): Promise { const ourAci = itemStorage.user.getCheckedAci(); const identityKey = signalProtocolStore.getIdentityKeyPair(ourAci); if (!identityKey) { throw new Error('decryptDeviceName: No identity key pair!'); } - const bytes = Bytes.fromBase64(base64); + const bytes = Base64.toBytes(base64); const proto = Proto.DeviceName.decode(bytes); strictAssert( proto.ephemeralPublic, @@ -341,7 +342,7 @@ export default class AccountManager extends EventTarget { async _encryptDeviceCreatedAt( createdAt: number, deviceId: number - ): Promise { + ): Promise { const ourAci = itemStorage.user.getCheckedAci(); const identityKey = signalProtocolStore.getIdentityKeyPair(ourAci); const registrationId = @@ -356,11 +357,11 @@ export default class AccountManager extends EventTarget { identityKey.publicKey ); - return Bytes.toBase64(createdAtCiphertextBytes); + return Base64.fromBytes(createdAtCiphertextBytes); } async decryptDeviceCreatedAt( - createdAtCiphertextBase64: string, + createdAtCiphertextBase64: Base64, deviceId: number ): Promise { const ourAci = itemStorage.user.getCheckedAci(); @@ -405,7 +406,10 @@ export default class AccountManager extends EventTarget { const base64 = this.encryptDeviceName(deviceName || '', identityKeyPair); if (base64) { - await updateDeviceName(base64); + await updateDeviceName({ + deviceId: itemStorage.user.getCheckedDeviceId(), + encryptedName: Base64.toBytes(base64), + }); await itemStorage.user.setDeviceNameEncrypted(); } } diff --git a/ts/textsecure/WebAPI.preload.ts b/ts/textsecure/WebAPI.preload.ts index bcecae3b1d..39a884adfb 100644 --- a/ts/textsecure/WebAPI.preload.ts +++ b/ts/textsecure/WebAPI.preload.ts @@ -22,6 +22,7 @@ import { import { AccountAttributes } from '@signalapp/libsignal-client/dist/net.js'; import type { BackupAuth, + LinkedDevice, ProvisioningConnection, ProvisioningConnectionListener, RegisterAccountResponse, @@ -819,7 +820,6 @@ const CHAT_CALLS = { subscriptions: 'v1/subscription', subscriptionConfiguration: 'v1/subscription/configuration', transferArchive: 'v1/devices/transfer_archive', - updateDeviceName: 'v1/accounts/name', username: 'v1/accounts/username_hash', reserveUsername: 'v1/accounts/username_hash/reserve', confirmUsername: 'v1/accounts/username_hash/confirm', @@ -1004,19 +1004,6 @@ export type GetAccountForUsernameOptionsType = Readonly<{ export type GetAccountForUsernameResultType = AciString | null; -const getDevicesResultZod = z.object({ - devices: z.array( - z.object({ - id: z.number(), - name: z.string().nullish(), // primary devices may not have a name - lastSeen: z.number().nullish(), - createdAtCiphertext: z.string(), - }) - ), -}); - -export type GetDevicesResultType = z.infer; - export type GetIceServersResultType = Readonly<{ relays?: ReadonlyArray; }>; @@ -3094,24 +3081,23 @@ export async function disableRegistrationLock(): Promise { }); } -export async function getDevices(): Promise { - return _ajax({ - host: 'chatService', - call: 'devices', - httpType: 'GET', - responseType: 'json', - zodSchema: getDevicesResultZod, +export async function getDevices(): Promise> { + return _retry(async () => { + const chat = await socketManager.getAuthenticatedApi(); + return chat.getDevices(); }); } -export async function updateDeviceName(deviceName: string): Promise { - await _ajax({ - host: 'chatService', - call: 'updateDeviceName', - httpType: 'PUT', - jsonData: { - deviceName, - }, +export async function updateDeviceName({ + deviceId, + encryptedName, +}: { + deviceId: number; + encryptedName: Uint8Array; +}): Promise { + await _retry(async () => { + const chat = await socketManager.getAuthenticatedApi(); + await chat.setDeviceName({ deviceId, encryptedName }); }); } diff --git a/ts/util/onDeviceNameChangeSync.preload.ts b/ts/util/onDeviceNameChangeSync.preload.ts index 8746b3296f..4dc727bf4f 100644 --- a/ts/util/onDeviceNameChangeSync.preload.ts +++ b/ts/util/onDeviceNameChangeSync.preload.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import PQueue from 'p-queue'; +import { Base64 } from '@signalapp/types'; import type { DeviceNameChangeSyncEvent } from '../textsecure/messageReceiverEvents.std.ts'; import { getDevices } from '../textsecure/WebAPI.preload.ts'; import { MINUTE } from './durations/index.std.ts'; @@ -57,7 +58,7 @@ export async function maybeQueueDeviceInfoFetch(): Promise { } async function fetchAndUpdateDeviceInfo() { - const { devices } = await getDevices(); + const devices = await getDevices(); const localDeviceId = parseIntOrThrow( itemStorage.user.getDeviceId(), 'fetchAndUpdateDeviceInfo: localDeviceId' @@ -70,15 +71,16 @@ async function fetchAndUpdateDeviceInfo() { localDeviceId ); - const newNameEncrypted = ourDevice.name; - if (!newNameEncrypted) { + if (ourDevice.encryptedName.length === 0) { log.error('fetchAndUpdateDeviceInfo: device had empty name'); return; } let newName: string; try { - newName = await accountManager.decryptDeviceName(newNameEncrypted); + newName = await accountManager.decryptDeviceName( + Base64.fromBytes(ourDevice.encryptedName) + ); } catch (e) { const deviceNameWasEncrypted = itemStorage.user.getDeviceNameEncrypted(); log.error( @@ -101,7 +103,7 @@ async function fetchAndUpdateDeviceInfo() { } async function maybeUpdateDeviceCreatedAt( - createdAtCiphertext: string, + createdAtCiphertext: Uint8Array, deviceId: number ): Promise { const existingCreatedAt = itemStorage.user.getDeviceCreatedAt(); @@ -109,11 +111,10 @@ async function maybeUpdateDeviceCreatedAt( return; } - const createdAtEncrypted = createdAtCiphertext; let createdAt: number | undefined; try { createdAt = await accountManager.decryptDeviceCreatedAt( - createdAtEncrypted, + Base64.fromBytes(createdAtCiphertext), deviceId ); } catch (e) {