forked from mystiq/hydrogen-web
move textencoder/decoder into platform
This commit is contained in:
parent
b6938dffdb
commit
e49639fda2
6 changed files with 53 additions and 21 deletions
|
@ -184,7 +184,7 @@ export class Session {
|
||||||
if (this._sessionBackup) {
|
if (this._sessionBackup) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const key = await ssssKeyFromCredential(type, credential, this._storage, this._platform.crypto, this._olm);
|
const key = await ssssKeyFromCredential(type, credential, this._storage, this._platform, this._olm);
|
||||||
// and create session backup, which needs to read from accountData
|
// and create session backup, which needs to read from accountData
|
||||||
const readTxn = this._storage.readTxn([
|
const readTxn = this._storage.readTxn([
|
||||||
this._storage.storeNames.accountData,
|
this._storage.storeNames.accountData,
|
||||||
|
@ -206,7 +206,7 @@ export class Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _createSessionBackup(ssssKey, txn) {
|
async _createSessionBackup(ssssKey, txn) {
|
||||||
const secretStorage = new SecretStorage({key: ssssKey, crypto: this._platform.crypto});
|
const secretStorage = new SecretStorage({key: ssssKey, platform: this._platform});
|
||||||
this._sessionBackup = await SessionBackup.fromSecretStorage({olm: this._olm, secretStorage, hsApi: this._hsApi, txn});
|
this._sessionBackup = await SessionBackup.fromSecretStorage({olm: this._olm, secretStorage, hsApi: this._hsApi, txn});
|
||||||
if (this._sessionBackup) {
|
if (this._sessionBackup) {
|
||||||
for (const room of this._rooms.values()) {
|
for (const room of this._rooms.values()) {
|
||||||
|
|
|
@ -17,9 +17,9 @@ limitations under the License.
|
||||||
import base64 from "../../../lib/base64-arraybuffer/index.js";
|
import base64 from "../../../lib/base64-arraybuffer/index.js";
|
||||||
|
|
||||||
export class SecretStorage {
|
export class SecretStorage {
|
||||||
constructor({key, crypto}) {
|
constructor({key, platform}) {
|
||||||
this._key = key;
|
this._key = key;
|
||||||
this._crypto = crypto;
|
this._platform = platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
async readSecret(name, txn) {
|
async readSecret(name, txn) {
|
||||||
|
@ -40,14 +40,11 @@ export class SecretStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _decryptAESSecret(type, encryptedData) {
|
async _decryptAESSecret(type, encryptedData) {
|
||||||
// TODO: we should we move this to platform specific code
|
|
||||||
const textEncoder = new TextEncoder();
|
|
||||||
const textDecoder = new TextDecoder();
|
|
||||||
// now derive the aes and mac key from the 4s key
|
// now derive the aes and mac key from the 4s key
|
||||||
const hkdfKey = await this._crypto.derive.hkdf(
|
const hkdfKey = await this._platform.crypto.derive.hkdf(
|
||||||
this._key.binaryKey,
|
this._key.binaryKey,
|
||||||
new Uint8Array(8).buffer, //zero salt
|
new Uint8Array(8).buffer, //zero salt
|
||||||
textEncoder.encode(type), // info
|
this._platform.utf8.encode(type), // info
|
||||||
"SHA-256",
|
"SHA-256",
|
||||||
512 // 512 bits or 64 bytes
|
512 // 512 bits or 64 bytes
|
||||||
);
|
);
|
||||||
|
@ -56,7 +53,7 @@ export class SecretStorage {
|
||||||
|
|
||||||
const ciphertextBytes = base64.decode(encryptedData.ciphertext);
|
const ciphertextBytes = base64.decode(encryptedData.ciphertext);
|
||||||
|
|
||||||
const isVerified = await this._crypto.hmac.verify(
|
const isVerified = await this._platform.crypto.hmac.verify(
|
||||||
hmacKey, base64.decode(encryptedData.mac),
|
hmacKey, base64.decode(encryptedData.mac),
|
||||||
ciphertextBytes, "SHA-256");
|
ciphertextBytes, "SHA-256");
|
||||||
|
|
||||||
|
@ -64,12 +61,12 @@ export class SecretStorage {
|
||||||
throw new Error("Bad MAC");
|
throw new Error("Bad MAC");
|
||||||
}
|
}
|
||||||
|
|
||||||
const plaintextBytes = await this._crypto.aes.decryptCTR({
|
const plaintextBytes = await this._platform.crypto.aes.decryptCTR({
|
||||||
key: aesKey,
|
key: aesKey,
|
||||||
iv: base64.decode(encryptedData.iv),
|
iv: base64.decode(encryptedData.iv),
|
||||||
data: ciphertextBytes
|
data: ciphertextBytes
|
||||||
});
|
});
|
||||||
|
|
||||||
return textDecoder.decode(plaintextBytes);
|
return this._platform.utf8.decode(plaintextBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,14 +47,14 @@ export async function readKey(txn) {
|
||||||
return new Key(new KeyDescription(keyData.id, keyAccountData), keyData.binaryKey);
|
return new Key(new KeyDescription(keyData.id, keyAccountData), keyData.binaryKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function keyFromCredential(type, credential, storage, crypto, olm) {
|
export async function keyFromCredential(type, credential, storage, platform, olm) {
|
||||||
const keyDescription = await readDefaultKeyDescription(storage);
|
const keyDescription = await readDefaultKeyDescription(storage);
|
||||||
if (!keyDescription) {
|
if (!keyDescription) {
|
||||||
throw new Error("Could not find a default secret storage key in account data");
|
throw new Error("Could not find a default secret storage key in account data");
|
||||||
}
|
}
|
||||||
let key;
|
let key;
|
||||||
if (type === "phrase") {
|
if (type === "phrase") {
|
||||||
key = await keyFromPassphrase(keyDescription, credential, crypto);
|
key = await keyFromPassphrase(keyDescription, credential, platform);
|
||||||
} else if (type === "key") {
|
} else if (type === "key") {
|
||||||
key = keyFromRecoveryKey(olm, keyDescription, credential);
|
key = keyFromRecoveryKey(olm, keyDescription, credential);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,10 +22,10 @@ const DEFAULT_BITSIZE = 256;
|
||||||
/**
|
/**
|
||||||
* @param {KeyDescription} keyDescription
|
* @param {KeyDescription} keyDescription
|
||||||
* @param {string} passphrase
|
* @param {string} passphrase
|
||||||
* @param {Crypto} crypto
|
* @param {Platform} platform
|
||||||
* @return {Key}
|
* @return {Key}
|
||||||
*/
|
*/
|
||||||
export async function keyFromPassphrase(keyDescription, passphrase, crypto) {
|
export async function keyFromPassphrase(keyDescription, passphrase, platform) {
|
||||||
const {passphraseParams} = keyDescription;
|
const {passphraseParams} = keyDescription;
|
||||||
if (!passphraseParams) {
|
if (!passphraseParams) {
|
||||||
throw new Error("not a passphrase key");
|
throw new Error("not a passphrase key");
|
||||||
|
@ -33,13 +33,11 @@ export async function keyFromPassphrase(keyDescription, passphrase, crypto) {
|
||||||
if (passphraseParams.algorithm !== "m.pbkdf2") {
|
if (passphraseParams.algorithm !== "m.pbkdf2") {
|
||||||
throw new Error(`Unsupported passphrase algorithm: ${passphraseParams.algorithm}`);
|
throw new Error(`Unsupported passphrase algorithm: ${passphraseParams.algorithm}`);
|
||||||
}
|
}
|
||||||
// TODO: we should we move this to platform specific code
|
const keyBits = await platform.crypto.derive.pbkdf2(
|
||||||
const textEncoder = new TextEncoder();
|
platform.utf8.encode(passphrase),
|
||||||
const keyBits = await crypto.derive.pbkdf2(
|
|
||||||
textEncoder.encode(passphrase),
|
|
||||||
passphraseParams.iterations || DEFAULT_ITERATIONS,
|
passphraseParams.iterations || DEFAULT_ITERATIONS,
|
||||||
// salt is just a random string, not encoded in any way
|
// salt is just a random string, not encoded in any way
|
||||||
textEncoder.encode(passphraseParams.salt),
|
platform.utf8.encode(passphraseParams.salt),
|
||||||
"SHA-512",
|
"SHA-512",
|
||||||
passphraseParams.bits || DEFAULT_BITSIZE);
|
passphraseParams.bits || DEFAULT_BITSIZE);
|
||||||
return new Key(keyDescription, keyBits);
|
return new Key(keyDescription, keyBits);
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {xhrRequest} from "./dom/request/xhr.js";
|
||||||
import {StorageFactory} from "../../matrix/storage/idb/StorageFactory.js";
|
import {StorageFactory} from "../../matrix/storage/idb/StorageFactory.js";
|
||||||
import {SessionInfoStorage} from "../../matrix/sessioninfo/localstorage/SessionInfoStorage.js";
|
import {SessionInfoStorage} from "../../matrix/sessioninfo/localstorage/SessionInfoStorage.js";
|
||||||
import {SettingsStorage} from "./dom/SettingsStorage.js";
|
import {SettingsStorage} from "./dom/SettingsStorage.js";
|
||||||
|
import {UTF8} from "./dom/UTF8.js";
|
||||||
import {OlmWorker} from "../../matrix/e2ee/OlmWorker.js";
|
import {OlmWorker} from "../../matrix/e2ee/OlmWorker.js";
|
||||||
import {RootView} from "./ui/RootView.js";
|
import {RootView} from "./ui/RootView.js";
|
||||||
import {Clock} from "./dom/Clock.js";
|
import {Clock} from "./dom/Clock.js";
|
||||||
|
@ -83,6 +84,7 @@ export class Platform {
|
||||||
constructor(container, paths, cryptoExtras = null) {
|
constructor(container, paths, cryptoExtras = null) {
|
||||||
this._paths = paths;
|
this._paths = paths;
|
||||||
this._container = container;
|
this._container = container;
|
||||||
|
this.utf8 = new UTF8();
|
||||||
this.clock = new Clock();
|
this.clock = new Clock();
|
||||||
this.history = new History();
|
this.history = new History();
|
||||||
this.onlineStatus = new OnlineStatus();
|
this.onlineStatus = new OnlineStatus();
|
||||||
|
|
35
src/platform/web/dom/UTF8.js
Normal file
35
src/platform/web/dom/UTF8.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
export class UTF8 {
|
||||||
|
constructor() {
|
||||||
|
this._encoder = null;
|
||||||
|
this._decoder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
encode(str) {
|
||||||
|
if (!this._encoder) {
|
||||||
|
this._encoder = new TextEncoder();
|
||||||
|
}
|
||||||
|
return this._encoder.encode(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
decode(buffer) {
|
||||||
|
if (!this._decoder) {
|
||||||
|
this._decoder = new TextDecoder();
|
||||||
|
}
|
||||||
|
return this._decoder.decode(buffer);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue