diff --git a/keyserver/src/socket/tunnelbroker.js b/keyserver/src/socket/tunnelbroker.js --- a/keyserver/src/socket/tunnelbroker.js +++ b/keyserver/src/socket/tunnelbroker.js @@ -2,11 +2,15 @@ import WebSocket from 'ws'; -import { type TBKeyserverConnectionInitializationMessage } from 'lib/types/tunnelbroker-messages.js'; +import { + type TBKeyserverConnectionInitializationMessage, + type TBRefreshKeysRequest, +} from 'lib/types/tunnelbroker-messages.js'; import sleep from 'lib/utils/sleep.js'; import { fetchOlmAccount } from '../updaters/olm-account-updater.js'; -import type { IdentityInfo } from '../user/identity.js'; +import { type IdentityInfo } from '../user/identity.js'; +import { uploadNewOneTimeKeys } from '../utils/olm-utils.js'; async function createAndMaintainTunnelbrokerWebsocket( identityInfo: IdentityInfo, @@ -21,6 +25,18 @@ ); } +async function handleTBMessageEvent(event: MessageEvent) { + if (typeof event.data !== 'string') { + return; + } + + // Currently, there is only one message type which is sent from tunnelbroker + const content: string = event.data; + const message: TBRefreshKeysRequest = JSON.parse(content); + + await uploadNewOneTimeKeys(message.numberOfKeys); +} + function openTunnelbrokerConnection( deviceId: string, userId: string, @@ -52,6 +68,8 @@ tunnelbrokerSocket.on('error', (error: Error) => { console.error('Tunnelbroker socket error: ' + error.message); }); + + tunnelbrokerSocket.on('message', handleTBMessageEvent); } catch (err) { console.log('Failed to open connection with tunnelbroker'); } diff --git a/keyserver/src/utils/olm-utils.js b/keyserver/src/utils/olm-utils.js --- a/keyserver/src/utils/olm-utils.js +++ b/keyserver/src/utils/olm-utils.js @@ -10,8 +10,11 @@ import uuid from 'uuid'; import { olmEncryptedMessageTypes } from 'lib/types/crypto-types.js'; +import type { OLMOneTimeKeys } from 'lib/types/crypto-types.js'; +import { ServerError } from 'lib/utils/errors.js'; import { values } from 'lib/utils/objects.js'; +import { fetchCallUpdateOlmAccount } from '../updaters/olm-account-updater.js'; import { fetchIdentityInfo } from '../user/identity.js'; type PickledOlmAccount = { @@ -174,6 +177,45 @@ notifAccount.mark_prekey_as_published(); } +async function uploadNewOneTimeKeys(numberOfKeys: number) { + const rustAPIPromise = getRustAPI(); + const identityInfoPromise = fetchIdentityInfo(); + + const [rustAPI, identityInfo] = await Promise.all([ + rustAPIPromise, + identityInfoPromise, + ]); + + if (!identityInfo) { + throw new ServerError('missing_identity_info'); + } + + await fetchCallUpdateOlmAccount('content', (contentAccount: OlmAccount) => { + contentAccount.generate_one_time_keys(numberOfKeys); + const contentOneTimeKeys = getOneTimeKeyValues( + contentAccount.one_time_keys(), + ); + const deviceId = JSON.parse(contentAccount.identity_keys()).curve25519; + + fetchCallUpdateOlmAccount('notifications', (notifAccount: OlmAccount) => { + notifAccount.generate_one_time_keys(numberOfKeys); + const notifOneTimeKeys = getOneTimeKeyValues( + notifAccount.one_time_keys(), + ); + rustAPI.uploadOneTimeKeys( + identityInfo.userId, + deviceId, + identityInfo.accessToken, + contentOneTimeKeys, + notifOneTimeKeys, + ); + + notifAccount.mark_keys_as_published(); + contentAccount.mark_keys_as_published(); + }); + }); +} + function validateAccountPrekey(account: OlmAccount) { if (shouldRotatePrekey(account)) { // If there is no prekey or the current prekey is older than month @@ -196,4 +238,5 @@ validateAccountPrekey, revalidateAccountPrekeys, publishNewPrekeys, + uploadNewOneTimeKeys, }; diff --git a/lib/types/tunnelbroker-messages.js b/lib/types/tunnelbroker-messages.js --- a/lib/types/tunnelbroker-messages.js +++ b/lib/types/tunnelbroker-messages.js @@ -28,3 +28,9 @@ | TBKeyserverConnectionInitializationMessage | TBClientConnectionInitializationMessage | TBNotifyClientConnectionInitializationMessage; + +export type TBRefreshKeysRequest = { + +type: 'refreshKeysRequest', + +deviceId: string, + +numberOfKeys: number, +};