diff --git a/keyserver/flow-typed/npm/@commapp/olm_vx.x.x.js b/keyserver/flow-typed/npm/@commapp/olm_vx.x.x.js --- a/keyserver/flow-typed/npm/@commapp/olm_vx.x.x.js +++ b/keyserver/flow-typed/npm/@commapp/olm_vx.x.x.js @@ -173,6 +173,7 @@ PRIVATE_KEY_LENGTH: typeof PRIVATE_KEY_LENGTH, Account: typeof Account, Utility: typeof Utility, + Session: typeof Session, }; } diff --git a/keyserver/src/creators/olm-session-creator.js b/keyserver/src/creators/olm-session-creator.js new file mode 100644 --- /dev/null +++ b/keyserver/src/creators/olm-session-creator.js @@ -0,0 +1,57 @@ +// @flow + +import type { Account as OlmAccount } from '@commapp/olm'; + +import { ServerError } from 'lib/utils/errors.js'; + +import { dbQuery, SQL } from '../database/database.js'; +import { fetchCallUpdateOlmAccount } from '../updaters/olm-account-updater.js'; +import { createPickledOlmSession } from '../utils/olm-utils.js'; + +async function createOlmSession( + initialEncryptedMessage: string, + olmSessionType: 'primary' | 'notifications', + cookieID: string, +): Promise { + const isPrimary = olmSessionType === 'primary'; + + let account; + const accountCallback = async (callbackAccount: OlmAccount) => { + account = callbackAccount; + }; + await fetchCallUpdateOlmAccount(olmSessionType, accountCallback); + if (!account) { + throw new ServerError('missing_olm_account'); + } + + const [picklingKeyResult] = await dbQuery( + SQL` + SELECT pickling_key + FROM keyserver_olm_accounts + WHERE is_primary = ${isPrimary} + `, + ); + if (picklingKeyResult.length === 0) { + throw new ServerError('missing_account_pickling_key'); + } + const picklingKey = picklingKeyResult[0].pickling_key; + + const pickledOlmSession = await createPickledOlmSession( + account, + picklingKey, + initialEncryptedMessage, + ); + + // We match the native client behavior here where olm session is overwritten + // in case it is initialized twice for the same pair of identities + await dbQuery( + SQL` + INSERT INTO olm_sessions (cookie_id, is_primary, pickled_olm_session) + VALUES (${cookieID}, ${isPrimary}, ${pickledOlmSession}) + ON DUPLICATE KEY UPDATE + pickled_olm_session = ${pickledOlmSession} + `, + ); +} + +export { createOlmSession }; 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 @@ -4,6 +4,7 @@ import type { Account as OlmAccount, Utility as OlmUtility, + Session as OlmSession, } from '@commapp/olm'; import uuid from 'uuid'; @@ -39,6 +40,27 @@ return account; } +async function createPickledOlmSession( + account: OlmAccount, + accountPicklingKey: string, + initialEncryptedMessage: string, +): Promise { + await olm.init(); + const session = new olm.Session(); + session.create_inbound(account, initialEncryptedMessage); + return session.pickle(accountPicklingKey); +} + +async function unpicklePickledOlmSession( + pickledSession: string, + picklingKey: string, +): Promise { + await olm.init(); + const session = new olm.Session(); + session.unpickle(picklingKey, pickledSession); + return session; +} + let cachedOLMUtility: OlmUtility; function getOlmUtility(): OlmUtility { if (cachedOLMUtility) { @@ -79,7 +101,9 @@ export { createPickledOlmAccount, + createPickledOlmSession, getOlmUtility, unpicklePickledOlmAccount, + unpicklePickledOlmSession, validateAccountPrekey, }; diff --git a/web/flow-typed/npm/@commapp/olm_vx.x.x.js b/web/flow-typed/npm/@commapp/olm_vx.x.x.js --- a/web/flow-typed/npm/@commapp/olm_vx.x.x.js +++ b/web/flow-typed/npm/@commapp/olm_vx.x.x.js @@ -173,6 +173,7 @@ PRIVATE_KEY_LENGTH: typeof PRIVATE_KEY_LENGTH, Account: typeof Account, Utility: typeof Utility, + Session: typeof Session, }; }