Page MenuHomePhabricator

D10876.id36498.diff
No OneTemporary

D10876.id36498.diff

diff --git a/keyserver/src/updaters/olm-account-updater.js b/keyserver/src/updaters/olm-account-updater.js
--- a/keyserver/src/updaters/olm-account-updater.js
+++ b/keyserver/src/updaters/olm-account-updater.js
@@ -43,7 +43,12 @@
picklingKey,
pickledAccount,
});
- const result = await callback(account, picklingKey);
+ let result;
+ try {
+ result = await callback(account, picklingKey);
+ } catch (e) {
+ throw new ServerError(e.message);
+ }
const updatedAccount = account.pickle(picklingKey);
const [transactionResult] = await dbQuery(
diff --git a/keyserver/src/user/login.js b/keyserver/src/user/login.js
--- a/keyserver/src/user/login.js
+++ b/keyserver/src/user/login.js
@@ -3,10 +3,9 @@
import type { Account as OlmAccount } from '@commapp/olm';
import { getRustAPI } from 'rust-node-addon';
-import { getOneTimeKeyValuesFromBlob } from 'lib/shared/crypto-utils.js';
-import { ONE_TIME_KEYS_NUMBER } from 'lib/types/identity-service-types.js';
import { getCommConfig } from 'lib/utils/comm-config.js';
import { ServerError } from 'lib/utils/errors.js';
+import { retrieveAccountKeysSet } from 'lib/utils/olm-utils.js';
import {
saveIdentityInfo,
@@ -15,40 +14,9 @@
} from './identity.js';
import { getMessageForException } from '../responders/utils.js';
import { fetchCallUpdateOlmAccount } from '../updaters/olm-account-updater.js';
-import {
- getAccountPrekeysSet,
- validateAccountPrekey,
-} from '../utils/olm-utils.js';
type UserCredentials = { +username: string, +password: string };
-export type AccountKeysSet = {
- +identityKeys: string,
- +prekey: string,
- +prekeySignature: string,
- +oneTimeKeys: $ReadOnlyArray<string>,
-};
-
-function retrieveAccountKeysSet(account: OlmAccount): AccountKeysSet {
- const identityKeys = account.identity_keys();
-
- validateAccountPrekey(account);
- const { prekey, prekeySignature } = getAccountPrekeysSet(account);
-
- if (!prekeySignature || !prekey) {
- throw new ServerError('invalid_prekey');
- }
-
- let oneTimeKeys = getOneTimeKeyValuesFromBlob(account.one_time_keys());
-
- if (oneTimeKeys.length < ONE_TIME_KEYS_NUMBER) {
- account.generate_one_time_keys(ONE_TIME_KEYS_NUMBER);
- oneTimeKeys = getOneTimeKeyValuesFromBlob(account.one_time_keys());
- }
-
- return { identityKeys, oneTimeKeys, prekey, prekeySignature };
-}
-
// After register or login is successful
function markKeysAsPublished(account: OlmAccount) {
account.mark_prekey_as_published();
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
@@ -12,7 +12,11 @@
import { getOneTimeKeyValuesFromBlob } from 'lib/shared/crypto-utils.js';
import { olmEncryptedMessageTypes } from 'lib/types/crypto-types.js';
import { ServerError } from 'lib/utils/errors.js';
-import { values } from 'lib/utils/objects.js';
+import {
+ getAccountPrekeysSet,
+ shouldForgetPrekey,
+ shouldRotatePrekey,
+} from 'lib/utils/olm-utils.js';
import {
fetchCallUpdateOlmAccount,
@@ -25,49 +29,6 @@
+pickledAccount: string,
};
-const maxPublishedPrekeyAge = 30 * 24 * 60 * 60 * 1000;
-const maxOldPrekeyAge = 24 * 60 * 60 * 1000;
-
-function getLastPrekeyPublishTime(account: OlmAccount): Date {
- const olmLastPrekeyPublishTime = account.last_prekey_publish_time();
-
- // Olm uses seconds, while in Node we need milliseconds.
- return new Date(olmLastPrekeyPublishTime * 1000);
-}
-
-function shouldRotatePrekey(account: OlmAccount): boolean {
- // Our fork of Olm only remembers two prekeys at a time.
- // If the new one hasn't been published, then the old one is still active.
- // In that scenario, we need to avoid rotating the prekey because it will
- // result in the old active prekey being discarded.
- if (account.unpublished_prekey()) {
- return false;
- }
-
- const currentDate = new Date();
- const lastPrekeyPublishDate = getLastPrekeyPublishTime(account);
-
- return (
- currentDate.getTime() - lastPrekeyPublishDate.getTime() >=
- maxPublishedPrekeyAge
- );
-}
-
-function shouldForgetPrekey(account: OlmAccount): boolean {
- // Our fork of Olm only remembers two prekeys at a time.
- // We have to hold onto the old one until the new one is published.
- if (account.unpublished_prekey()) {
- return false;
- }
-
- const currentDate = new Date();
- const lastPrekeyPublishDate = getLastPrekeyPublishTime(account);
-
- return (
- currentDate.getTime() - lastPrekeyPublishDate.getTime() >= maxOldPrekeyAge
- );
-}
-
async function createPickledOlmAccount(): Promise<PickledOlmAccount> {
await olm.init();
const account = new olm.Account();
@@ -139,15 +100,6 @@
return cachedOLMUtility;
}
-function validateAccountPrekey(account: OlmAccount) {
- if (shouldRotatePrekey(account)) {
- account.generate_prekey();
- }
- if (shouldForgetPrekey(account)) {
- account.forget_old_prekey();
- }
-}
-
async function uploadNewOneTimeKeys(numberOfKeys: number) {
const [rustAPI, identityInfo, deviceID] = await Promise.all([
getRustAPI(),
@@ -192,16 +144,6 @@
return JSON.parse(accountInfo.account.identity_keys()).ed25519;
}
-function getAccountPrekeysSet(account: OlmAccount): {
- +prekey: string,
- +prekeySignature: ?string,
-} {
- const prekeyMap = JSON.parse(account.prekey()).curve25519;
- const [prekey] = values(prekeyMap);
- const prekeySignature = account.prekey_signature();
- return { prekey, prekeySignature };
-}
-
async function validateAndUploadAccountPrekeys(
contentAccount: OlmAccount,
notifAccount: OlmAccount,
@@ -267,10 +209,8 @@
getOlmUtility,
unpickleOlmAccount,
unpickleOlmSession,
- validateAccountPrekey,
uploadNewOneTimeKeys,
getContentSigningKey,
- getAccountPrekeysSet,
validateAndUploadAccountPrekeys,
publishPrekeysToIdentity,
};
diff --git a/lib/flow-typed/npm/@commapp/olm_vx.x.x.js b/lib/flow-typed/npm/@commapp/olm_vx.x.x.js
new file mode 100644
--- /dev/null
+++ b/lib/flow-typed/npm/@commapp/olm_vx.x.x.js
@@ -0,0 +1,182 @@
+// flow-typed signature: 085f002da86534cfd8cee47ffa99dd67
+// flow-typed version: <<STUB>>/@commapp/olm_v3.2.4/flow_v0.182.0
+
+declare module '@commapp/olm' {
+
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+ declare export class Account {
+ constructor(): void;
+ free(): void;
+ create(): void;
+ identity_keys(): string;
+ sign(message: string | Uint8Array): string;
+ one_time_keys(): string;
+ mark_keys_as_published(): void;
+ max_number_of_one_time_keys(): number;
+ generate_one_time_keys(number_of_keys: number): void;
+ remove_one_time_keys(session: Session): void;
+ generate_prekey(): void;
+ prekey(): string;
+ unpublished_prekey(): ?string;
+ prekey_signature(): ?string;
+ forget_old_prekey(): void;
+ mark_prekey_as_published(): void;
+ last_prekey_publish_time(): number;
+ generate_fallback_key(): void;
+ fallback_key(): string;
+ unpublished_fallback_key(): string;
+ forget_old_fallback_key(): void;
+ pickle(key: string | Uint8Array): string;
+ unpickle(key: string | Uint8Array, pickle: string): void;
+ }
+
+ declare export type EncryptResult = {
+ +type: 0 | 1, // 0: PreKey, 1: Message
+ +body: string,
+ };
+ declare export class Session {
+ constructor(): void;
+ free(): void;
+ pickle(key: string | Uint8Array): string;
+ unpickle(key: string | Uint8Array, pickle: string): void;
+ create_outbound(
+ account: Account,
+ their_identity_key: string,
+ their_signing_key: string,
+ their_prekey: string,
+ their_prekey_signature: string,
+ their_one_time_key: string,
+ ): void;
+ create_inbound(account: Account, one_time_key_message: string): void;
+ create_inbound_from(
+ account: Account,
+ identity_key: string,
+ one_time_key_message: string,
+ ): void;
+ session_id(): string;
+ has_received_message(): boolean;
+ matches_inbound(one_time_key_message: string): boolean;
+ matches_inbound_from(
+ identity_key: string,
+ one_time_key_message: string,
+ ): boolean;
+ encrypt(plaintext: string): EncryptResult;
+ decrypt(message_type: number, message: string): string;
+ describe(): string;
+ }
+
+ declare export class Utility {
+ constructor(): void;
+ free(): void;
+ sha256(input: string | Uint8Array): string;
+ ed25519_verify(
+ key: string,
+ message: string | Uint8Array,
+ signature: string,
+ ): void;
+ }
+
+ declare export type DecryptResult = {
+ +message_index: string,
+ +plaintext: string,
+ };
+
+ declare export class InboundGroupSession {
+ constructor(): void;
+ free(): void;
+ pickle(key: string | Uint8Array): string;
+ unpickle(key: string | Uint8Array, pickle: string): void;
+ create(session_key: string): string;
+ import_session(session_key: string): string;
+ decrypt(message: string): DecryptResult;
+ session_id(): string;
+ first_known_index(): number;
+ export_session(message_index: number): string;
+ }
+
+ declare export class OutboundGroupSession {
+ constructor(): void;
+ free(): void;
+ pickle(key: string | Uint8Array): string;
+ unpickle(key: string | Uint8Array, pickle: string): void;
+ create(): void;
+ encrypt(plaintext: string): string;
+ session_id(): string;
+ session_key(): string;
+ message_index(): number;
+ }
+
+ declare export type PkEncryptionEncryptResult = {
+ +ciphertext: string,
+ +mac: string,
+ +ephemeral: string,
+ };
+
+ declare export class PkEncryption {
+ constructor(): void;
+ free(): void;
+ set_recipient_key(key: string): void;
+ encrypt(plaintext: string): PkEncryptionEncryptResult;
+ }
+
+ declare export class PkDecryption {
+ constructor(): void;
+ free(): void;
+ init_with_private_key(key: Uint8Array): string;
+ generate_key(): string;
+ get_private_key(): Uint8Array;
+ pickle(key: string | Uint8Array): string;
+ unpickle(key: string | Uint8Array, pickle: string): string;
+ decrypt(ephemeral_key: string, mac: string, ciphertext: string): string;
+ }
+
+ declare export class PkSigning {
+ constructor(): void;
+ free(): void;
+ init_with_seed(seed: Uint8Array): string;
+ generate_seed(): Uint8Array;
+ sign(message: string): string;
+ }
+
+ declare export class SAS {
+ constructor(): void;
+ free(): void;
+ get_pubkey(): string;
+ set_their_key(their_key: string): void;
+ generate_bytes(info: string, length: number): Uint8Array;
+ calculate_mac(input: string, info: string): string;
+ calculate_mac_fixed_base64(input: string, info: string): string;
+ calculate_mac_long_kdf(input: string, info: string): string;
+ }
+
+ declare export function init(opts?: Object): Promise<void>;
+
+ declare export function get_library_version(): [number, number, number];
+
+ declare export var PRIVATE_KEY_LENGTH: number;
+
+ declare export default {
+ init: typeof init,
+ get_library_version: typeof get_library_version,
+ PRIVATE_KEY_LENGTH: typeof PRIVATE_KEY_LENGTH,
+ Account: typeof Account,
+ Utility: typeof Utility,
+ Session: typeof Session,
+ };
+
+}
diff --git a/lib/package.json b/lib/package.json
--- a/lib/package.json
+++ b/lib/package.json
@@ -35,6 +35,7 @@
"webpack": "^5.76.0"
},
"dependencies": {
+ "@commapp/olm": "0.1.0",
"@rainbow-me/rainbowkit": "^1.1.1",
"dateformat": "^3.0.3",
"emoji-regex": "^10.2.1",
diff --git a/lib/utils/olm-utils.js b/lib/utils/olm-utils.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/olm-utils.js
@@ -0,0 +1,103 @@
+// @flow
+
+import type { Account as OlmAccount } from '@commapp/olm';
+
+import { values } from './objects.js';
+import { getOneTimeKeyValuesFromBlob } from '../shared/crypto-utils.js';
+import { ONE_TIME_KEYS_NUMBER } from '../types/identity-service-types.js';
+
+const maxPublishedPrekeyAge = 30 * 24 * 60 * 60 * 1000;
+const maxOldPrekeyAge = 24 * 60 * 60 * 1000;
+
+type AccountKeysSet = {
+ +identityKeys: string,
+ +prekey: string,
+ +prekeySignature: string,
+ +oneTimeKeys: $ReadOnlyArray<string>,
+};
+
+function validateAccountPrekey(account: OlmAccount) {
+ if (shouldRotatePrekey(account)) {
+ account.generate_prekey();
+ }
+ if (shouldForgetPrekey(account)) {
+ account.forget_old_prekey();
+ }
+}
+
+function shouldRotatePrekey(account: OlmAccount): boolean {
+ // Our fork of Olm only remembers two prekeys at a time.
+ // If the new one hasn't been published, then the old one is still active.
+ // In that scenario, we need to avoid rotating the prekey because it will
+ // result in the old active prekey being discarded.
+ if (account.unpublished_prekey()) {
+ return false;
+ }
+
+ const currentDate = new Date();
+ const lastPrekeyPublishDate = getLastPrekeyPublishTime(account);
+
+ return (
+ currentDate.getTime() - lastPrekeyPublishDate.getTime() >=
+ maxPublishedPrekeyAge
+ );
+}
+
+function shouldForgetPrekey(account: OlmAccount): boolean {
+ // Our fork of Olm only remembers two prekeys at a time.
+ // We have to hold onto the old one until the new one is published.
+ if (account.unpublished_prekey()) {
+ return false;
+ }
+
+ const currentDate = new Date();
+ const lastPrekeyPublishDate = getLastPrekeyPublishTime(account);
+
+ return (
+ currentDate.getTime() - lastPrekeyPublishDate.getTime() >= maxOldPrekeyAge
+ );
+}
+
+function getLastPrekeyPublishTime(account: OlmAccount): Date {
+ const olmLastPrekeyPublishTime = account.last_prekey_publish_time();
+
+ // Olm uses seconds, while the Date() constructor expects milliseconds.
+ return new Date(olmLastPrekeyPublishTime * 1000);
+}
+
+function getAccountPrekeysSet(account: OlmAccount): {
+ +prekey: string,
+ +prekeySignature: ?string,
+} {
+ const prekeyMap = JSON.parse(account.prekey()).curve25519;
+ const [prekey] = values(prekeyMap);
+ const prekeySignature = account.prekey_signature();
+ return { prekey, prekeySignature };
+}
+
+function retrieveAccountKeysSet(account: OlmAccount): AccountKeysSet {
+ const identityKeys = account.identity_keys();
+
+ validateAccountPrekey(account);
+ const { prekey, prekeySignature } = getAccountPrekeysSet(account);
+
+ if (!prekeySignature || !prekey) {
+ throw new Error('invalid_prekey');
+ }
+
+ let oneTimeKeys = getOneTimeKeyValuesFromBlob(account.one_time_keys());
+
+ if (oneTimeKeys.length < ONE_TIME_KEYS_NUMBER) {
+ account.generate_one_time_keys(ONE_TIME_KEYS_NUMBER);
+ oneTimeKeys = getOneTimeKeyValuesFromBlob(account.one_time_keys());
+ }
+
+ return { identityKeys, oneTimeKeys, prekey, prekeySignature };
+}
+
+export {
+ retrieveAccountKeysSet,
+ getAccountPrekeysSet,
+ shouldForgetPrekey,
+ shouldRotatePrekey,
+};

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 14, 7:24 PM (11 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2492227
Default Alt Text
D10876.id36498.diff (15 KB)

Event Timeline