RocketChat/Rocket.Chat

View on GitHub
apps/meteor/app/e2e/client/helper.js

Summary

Maintainability
A
0 mins
Test Coverage
import { Random } from '@rocket.chat/random';
import ByteBuffer from 'bytebuffer';

// eslint-disable-next-line no-proto
const StaticArrayBufferProto = new ArrayBuffer().__proto__;

export function toString(thing) {
    if (typeof thing === 'string') {
        return thing;
    }
    // eslint-disable-next-line new-cap
    return new ByteBuffer.wrap(thing).toString('binary');
}

export function toArrayBuffer(thing) {
    if (thing === undefined) {
        return undefined;
    }
    if (thing === Object(thing)) {
        // eslint-disable-next-line no-proto
        if (thing.__proto__ === StaticArrayBufferProto) {
            return thing;
        }
    }

    if (typeof thing !== 'string') {
        throw new Error(`Tried to convert a non-string of type ${typeof thing} to an array buffer`);
    }
    // eslint-disable-next-line new-cap
    return new ByteBuffer.wrap(thing, 'binary').toArrayBuffer();
}

export function joinVectorAndEcryptedData(vector, encryptedData) {
    const cipherText = new Uint8Array(encryptedData);
    const output = new Uint8Array(vector.length + cipherText.length);
    output.set(vector, 0);
    output.set(cipherText, vector.length);
    return output;
}

export function splitVectorAndEcryptedData(cipherText) {
    const vector = cipherText.slice(0, 16);
    const encryptedData = cipherText.slice(16);

    return [vector, encryptedData];
}

export async function encryptRSA(key, data) {
    return crypto.subtle.encrypt({ name: 'RSA-OAEP' }, key, data);
}

export async function encryptAES(vector, key, data) {
    return crypto.subtle.encrypt({ name: 'AES-CBC', iv: vector }, key, data);
}

export async function encryptAESCTR(vector, key, data) {
    return crypto.subtle.encrypt({ name: 'AES-CTR', counter: vector, length: 64 }, key, data);
}

export async function decryptRSA(key, data) {
    return crypto.subtle.decrypt({ name: 'RSA-OAEP' }, key, data);
}

export async function decryptAES(vector, key, data) {
    return crypto.subtle.decrypt({ name: 'AES-CBC', iv: vector }, key, data);
}

export async function generateAESKey() {
    return crypto.subtle.generateKey({ name: 'AES-CBC', length: 128 }, true, ['encrypt', 'decrypt']);
}

export async function generateAESCTRKey() {
    return crypto.subtle.generateKey({ name: 'AES-CTR', length: 256 }, true, ['encrypt', 'decrypt']);
}

export async function generateRSAKey() {
    return crypto.subtle.generateKey(
        {
            name: 'RSA-OAEP',
            modulusLength: 2048,
            publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            hash: { name: 'SHA-256' },
        },
        true,
        ['encrypt', 'decrypt'],
    );
}

export async function exportJWKKey(key) {
    return crypto.subtle.exportKey('jwk', key);
}

export async function importRSAKey(keyData, keyUsages = ['encrypt', 'decrypt']) {
    return crypto.subtle.importKey(
        'jwk',
        keyData,
        {
            name: 'RSA-OAEP',
            modulusLength: 2048,
            publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            hash: { name: 'SHA-256' },
        },
        true,
        keyUsages,
    );
}

export async function importAESKey(keyData, keyUsages = ['encrypt', 'decrypt']) {
    return crypto.subtle.importKey('jwk', keyData, { name: 'AES-CBC' }, true, keyUsages);
}

export async function importRawKey(keyData, keyUsages = ['deriveKey']) {
    return crypto.subtle.importKey('raw', keyData, { name: 'PBKDF2' }, false, keyUsages);
}

export async function deriveKey(salt, baseKey, keyUsages = ['encrypt', 'decrypt']) {
    const iterations = 1000;
    const hash = 'SHA-256';

    return crypto.subtle.deriveKey({ name: 'PBKDF2', salt, iterations, hash }, baseKey, { name: 'AES-CBC', length: 256 }, true, keyUsages);
}

export async function readFileAsArrayBuffer(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = function (evt) {
            resolve(evt.target.result);
        };
        reader.onerror = function (evt) {
            reject(evt);
        };
        reader.readAsArrayBuffer(file);
    });
}

export async function generateMnemonicPhrase(n, sep = ' ') {
    const { default: wordList } = await import('./wordList');
    const result = new Array(n);
    let len = wordList.length;
    const taken = new Array(len);

    while (n--) {
        const x = Math.floor(Random.fraction() * len);
        result[n] = wordList[x in taken ? taken[x] : x];
        taken[x] = --len in taken ? taken[len] : len;
    }
    return result.join(sep);
}