From 827a8585995b64437ae03c29b83e6711a21d1363 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Thu, 29 Oct 2020 19:11:09 +0200 Subject: [PATCH] Remove jsbn dependency from client --- src/helpers/blob.ts | 39 ++- src/helpers/bytes.ts | 172 +++++++++++ src/helpers/fileName.ts | 28 ++ src/helpers/random.ts | 8 + src/lib/appManagers/appDocsManager.ts | 2 +- src/lib/appManagers/appDownloadManager.ts | 2 +- src/lib/appManagers/appMessagesManager.ts | 31 +- src/lib/appManagers/appPhotosManager.ts | 3 +- src/lib/bin_utils.ts | 356 ---------------------- src/lib/cacheStorage.ts | 2 +- src/lib/crypto/crypto.worker.js | 2 +- src/lib/crypto/crypto_methods.ts | 2 +- src/lib/crypto/crypto_utils.ts | 4 +- src/lib/crypto/srp.ts | 2 +- src/lib/filemanager.ts | 2 +- src/lib/mtproto/apiFileManager.ts | 3 +- src/lib/mtproto/apiManager.ts | 3 +- src/lib/mtproto/authorizer.ts | 2 +- src/lib/mtproto/bin_utils.ts | 115 +++++++ src/lib/mtproto/mtproto.worker.ts | 3 +- src/lib/mtproto/networker.ts | 8 +- src/lib/mtproto/referenceDatabase.ts | 2 +- src/lib/mtproto/rsaKeysManager.ts | 3 +- src/lib/mtproto/timeManager.ts | 3 +- src/lib/mtproto/tl_utils.ts | 3 +- src/lib/mtproto/transports/http.ts | 2 +- src/lib/mtproto/transports/obfuscation.ts | 2 +- src/lib/mtproto/transports/padded.ts | 2 +- src/lib/polyfill.ts | 12 +- src/pages/pageSignQR.ts | 2 +- src/tests/crypto_methods.test.ts | 2 +- 31 files changed, 416 insertions(+), 406 deletions(-) create mode 100644 src/helpers/bytes.ts create mode 100644 src/helpers/fileName.ts create mode 100644 src/helpers/random.ts delete mode 100644 src/lib/bin_utils.ts create mode 100644 src/lib/mtproto/bin_utils.ts diff --git a/src/helpers/blob.ts b/src/helpers/blob.ts index a85fa514..ebd94715 100644 --- a/src/helpers/blob.ts +++ b/src/helpers/blob.ts @@ -7,4 +7,41 @@ export const readBlobAsText = (blob: Blob) => { }); reader.readAsText(blob); }); -}; \ No newline at end of file +}; + +export function blobConstruct(blobParts: any, mimeType: string = ''): Blob { + let blob; + const safeMimeType = blobSafeMimeType(mimeType); + try { + blob = new Blob(blobParts, {type: safeMimeType}); + } catch(e) { + // @ts-ignore + let bb = new BlobBuilder; + blobParts.forEach((blobPart: any) => { + bb.append(blobPart); + }); + blob = bb.getBlob(safeMimeType); + } + return blob; +} + +export function blobSafeMimeType(mimeType: string) { + if([ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/bmp', + 'video/mp4', + 'video/webm', + 'video/quicktime', + 'audio/ogg', + 'audio/mpeg', + 'audio/mp4', + 'application/json' + ].indexOf(mimeType) === -1) { + return 'application/octet-stream'; + } + + return mimeType; +} \ No newline at end of file diff --git a/src/helpers/bytes.ts b/src/helpers/bytes.ts new file mode 100644 index 00000000..0fc77e58 --- /dev/null +++ b/src/helpers/bytes.ts @@ -0,0 +1,172 @@ +export function bytesToHex(bytes: ArrayLike) { + bytes = bytes || []; + var arr = []; + for(var i = 0; i < bytes.length; i++) { + arr.push((bytes[i] < 16 ? '0' : '') + (bytes[i] || 0).toString(16)); + } + return arr.join(''); +} + +export function bytesFromHex(hexString: string) { + var len = hexString.length, + i; + var start = 0; + var bytes = []; + + if(hexString.length % 2) { + bytes.push(parseInt(hexString.charAt(0), 16)); + start++; + } + + for(i = start; i < len; i += 2) { + bytes.push(parseInt(hexString.substr(i, 2), 16)); + } + + return bytes; +} + +export function bytesToBase64(bytes: number[] | Uint8Array) { + var mod3 + var result = '' + + for (var nLen = bytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) { + mod3 = nIdx % 3 + nUint24 |= bytes[nIdx] << (16 >>> mod3 & 24) + if (mod3 === 2 || nLen - nIdx === 1) { + result += String.fromCharCode( + uint6ToBase64(nUint24 >>> 18 & 63), + uint6ToBase64(nUint24 >>> 12 & 63), + uint6ToBase64(nUint24 >>> 6 & 63), + uint6ToBase64(nUint24 & 63) + ) + nUint24 = 0 + } + } + + return result.replace(/A(?=A$|$)/g, '=') +} + +export function uint6ToBase64(nUint6: number) { + return nUint6 < 26 + ? nUint6 + 65 + : nUint6 < 52 + ? nUint6 + 71 + : nUint6 < 62 + ? nUint6 - 4 + : nUint6 === 62 + ? 43 + : nUint6 === 63 + ? 47 + : 65 +} + +export function bytesCmp(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) { + var len = bytes1.length; + if(len != bytes2.length) { + return false; + } + + for(var i = 0; i < len; i++) { + if(bytes1[i] != bytes2[i]) { + return false; + } + } + + return true; +} + +export function bytesXor(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) { + var len = bytes1.length; + var bytes = []; + + for (var i = 0; i < len; ++i) { + bytes[i] = bytes1[i] ^ bytes2[i]; + } + + return bytes; +} + +export function bytesToArrayBuffer(b: number[]) { + return (new Uint8Array(b)).buffer; +} + +export function convertToArrayBuffer(bytes: any | ArrayBuffer | Uint8Array) { + // Be careful with converting subarrays!! + if(bytes instanceof ArrayBuffer) { + return bytes; + } + if(bytes.buffer !== undefined && + bytes.buffer.byteLength == bytes.length * bytes.BYTES_PER_ELEMENT) { + return bytes.buffer; + } + return bytesToArrayBuffer(bytes); +} + +export function convertToUint8Array(bytes: Uint8Array | number[]): Uint8Array { + if((bytes as Uint8Array).buffer !== undefined) { + return bytes as Uint8Array; + } + + return new Uint8Array(bytes); +} + +export function bytesFromArrayBuffer(buffer: ArrayBuffer) { + var len = buffer.byteLength; + var byteView = new Uint8Array(buffer); + var bytes = []; + + for(var i = 0; i < len; ++i) { + bytes[i] = byteView[i]; + } + + return bytes; +} + +export function bufferConcat(buffer1: any, buffer2: any) { + var l1 = buffer1.byteLength || buffer1.length; + var l2 = buffer2.byteLength || buffer2.length; + var tmp = new Uint8Array(l1 + l2); + tmp.set(buffer1 instanceof ArrayBuffer ? new Uint8Array(buffer1) : buffer1, 0); + tmp.set(buffer2 instanceof ArrayBuffer ? new Uint8Array(buffer2) : buffer2, l1); + + return tmp.buffer; +} + +export function bufferConcats(...args: any[]) { + let length = 0; + args.forEach(b => length += b.byteLength || b.length); + + var tmp = new Uint8Array(length); + + let lastLength = 0; + args.forEach(b => { + tmp.set(b instanceof ArrayBuffer ? new Uint8Array(b) : b, lastLength); + lastLength += b.byteLength || b.length; + }); + + return tmp/* .buffer */; +} + +export function bytesFromWordss(input: Uint32Array) { + var o = []; + for(var i = 0; i < input.length * 4; i++) { + o.push((input[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff); + } + + return o; +} + +export function bytesToWordss(input: ArrayBuffer | Uint8Array) { + let bytes: Uint8Array; + if(input instanceof ArrayBuffer) bytes = new Uint8Array(input); + else bytes = input; + + var len = bytes.length; + var words: number[] = []; + var i; + for(i = 0; i < len; i++) { + words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8); + } + + return new Uint32Array(words); +} \ No newline at end of file diff --git a/src/helpers/fileName.ts b/src/helpers/fileName.ts new file mode 100644 index 00000000..3c1851c7 --- /dev/null +++ b/src/helpers/fileName.ts @@ -0,0 +1,28 @@ +import { InputFileLocation, FileLocation } from "../layer"; + +export function getFileNameByLocation(location: InputFileLocation | FileLocation, options?: Partial<{ + fileName: string +}>) { + const fileName = '';//(options?.fileName || '').split('.'); + const ext = fileName[fileName.length - 1] || ''; + + switch(location._) { + case 'inputPhotoFileLocation': + case 'inputDocumentFileLocation': { + const thumbPart = location.thumb_size ? '_' + location.thumb_size : ''; + return (fileName[0] ? fileName[0] + '_' : '') + location.id + thumbPart + (ext ? '.' + ext : ext); + } + + case 'fileLocationToBeDeprecated': + case 'inputPeerPhotoFileLocation': + case 'inputStickerSetThumb': + case 'inputFileLocation': { + return location.volume_id + '_' + location.local_id + (ext ? '.' + ext : ext); + } + + default: { + console.error('Unrecognized location:', location); + return ''; + } + } +} \ No newline at end of file diff --git a/src/helpers/random.ts b/src/helpers/random.ts new file mode 100644 index 00000000..a52cdd00 --- /dev/null +++ b/src/helpers/random.ts @@ -0,0 +1,8 @@ +export function nextRandomInt(maxValue: number) { + return Math.floor(Math.random() * maxValue); +} + +export function randomLong() { + return '' + nextRandomInt(0xFFFFFFFF) + nextRandomInt(0xFFFFFF); + //return '' + parseInt(nextRandomInt(0xFFFFFFFF).toString(16) + nextRandomInt(0xFFFFFFFF).toString(16), 16); +} \ No newline at end of file diff --git a/src/lib/appManagers/appDocsManager.ts b/src/lib/appManagers/appDocsManager.ts index d74e36d9..f854c321 100644 --- a/src/lib/appManagers/appDocsManager.ts +++ b/src/lib/appManagers/appDocsManager.ts @@ -1,5 +1,5 @@ +import { getFileNameByLocation } from '../../helpers/fileName'; import { Document, InputFileLocation, PhotoSize } from '../../layer'; -import { getFileNameByLocation } from '../bin_utils'; import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config'; import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase'; import opusDecodeController from '../opusDecodeController'; diff --git a/src/lib/appManagers/appDownloadManager.ts b/src/lib/appManagers/appDownloadManager.ts index 67a2d348..7ebcd07f 100644 --- a/src/lib/appManagers/appDownloadManager.ts +++ b/src/lib/appManagers/appDownloadManager.ts @@ -2,11 +2,11 @@ import $rootScope from "../rootScope"; import apiManager from "../mtproto/mtprotoworker"; import { deferredPromise, CancellablePromise } from "../../helpers/cancellablePromise"; import type { DownloadOptions } from "../mtproto/apiFileManager"; -import { getFileNameByLocation } from "../bin_utils"; import { InputFile } from "../../layer"; import referenceDatabase, {ReferenceBytes} from "../mtproto/referenceDatabase"; import type { ApiError } from "../mtproto/apiManager"; import cacheStorage from "../cacheStorage"; +import { getFileNameByLocation } from "../../helpers/fileName"; export type ResponseMethodBlob = 'blob'; export type ResponseMethodJson = 'json'; diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index e672d585..9e5a6e67 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -1,8 +1,8 @@ import ProgressivePreloader from "../../components/preloader"; import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise"; +import { randomLong } from "../../helpers/random"; import { Dialog as MTDialog, DialogFilter, DialogPeer, DocumentAttribute, InputMessage, Message, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, PhotoSize, SendMessageAction, Update } from "../../layer"; import { InvokeApiOptions, Modify } from "../../types"; -import { bigint, nextRandomInt } from "../bin_utils"; import { langPack } from "../langPack"; import { logger, LogLevels } from "../logger"; import type { ApiFileManager } from '../mtproto/apiFileManager'; @@ -772,8 +772,7 @@ export class AppMessagesManager { } var messageID = this.tempID--; - var randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; - var randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(); + var randomIDS = randomLong(); var historyStorage = this.historiesStorage[peerID]; var pFlags: any = {}; var replyToMsgID = options.replyToMsgID; @@ -844,7 +843,7 @@ export class AppMessagesManager { if(options.viaBotID) { apiPromise = apiManager.invokeApiAfter('messages.sendInlineBotResult', { peer: appPeersManager.getInputPeerByID(peerID), - random_id: randomID as any, + random_id: randomIDS, reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined, query_id: options.queryID, id: options.resultID, @@ -855,7 +854,7 @@ export class AppMessagesManager { no_webpage: options.noWebPage, peer: appPeersManager.getInputPeerByID(peerID), message: text, - random_id: randomID as any, + random_id: randomIDS, reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined, entities: sendEntites, clear_draft: options.clearDraft @@ -947,8 +946,7 @@ export class AppMessagesManager { }> = {}) { peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID; var messageID = this.tempID--; - var randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; - var randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(); + var randomIDS = randomLong(); var historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {count: null, history: [], pending: []}); var flags = 0; var pFlags: any = {}; @@ -1178,7 +1176,7 @@ export class AppMessagesManager { peer: appPeersManager.getInputPeerByID(peerID), media: inputMedia, message: caption, - random_id: randomID as any, + random_id: randomIDS, reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID) }).then((updates) => { apiUpdatesManager.processUpdateMessage(updates); @@ -1349,8 +1347,7 @@ export class AppMessagesManager { //let messageID = this.tempID--; //if(!groupID) groupID = messageID; let messageID = ids[idx]; - let randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; - let randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(); + let randomIDS = randomLong(); let preloader = new ProgressivePreloader(null, true, false, 'prepend'); let details = options.sendFileDetails[idx]; @@ -1425,7 +1422,6 @@ export class AppMessagesManager { message: caption, media: media, random_id: randomIDS, - randomID: randomID, reply_to: {reply_to_msg_id: replyToMsgID}, views: asChannel && 1, pending: true, @@ -1562,7 +1558,7 @@ export class AppMessagesManager { inputs.push({ _: 'inputSingleMedia', media: inputMedia, - random_id: message.randomID, + random_id: message.random_id, message: caption, entities: [] }); @@ -1594,8 +1590,7 @@ export class AppMessagesManager { peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID; const messageID = this.tempID--; - const randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; - const randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(); + const randomIDS = randomLong(); const historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {count: null, history: [], pending: []}); const replyToMsgID = options.replyToMsgID; const isChannel = appPeersManager.isChannel(peerID); @@ -1740,7 +1735,7 @@ export class AppMessagesManager { if(options.viaBotID) { apiPromise = apiManager.invokeApiAfter('messages.sendInlineBotResult', { peer: appPeersManager.getInputPeerByID(peerID), - random_id: randomID as any, + random_id: randomIDS, reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined, query_id: options.queryID, id: options.resultID, @@ -1750,7 +1745,7 @@ export class AppMessagesManager { apiPromise = apiManager.invokeApiAfter('messages.sendMedia', { peer: appPeersManager.getInputPeerByID(peerID), media: inputMedia, - random_id: randomID as any, + random_id: randomIDS, reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined, message: '', clear_draft: options.clearDraft @@ -2032,7 +2027,7 @@ export class AppMessagesManager { for(const channelID in splitted.msgIDs) { const msgIDs = splitted.msgIDs[channelID]; - const randomIDs: [number, number][] = msgIDs.map(() => [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]); + const randomIDs: string[] = msgIDs.map(() => randomLong()); const sentRequestOptions: InvokeApiOptions = {}; if(this.pendingAfterMsgs[peerID]) { @@ -2042,7 +2037,7 @@ export class AppMessagesManager { const promise = apiManager.invokeApiAfter('messages.forwardMessages', { from_peer: appPeersManager.getInputPeerByID(-channelID), id: msgIDs, - random_id: randomIDs as any, + random_id: randomIDs, to_peer: appPeersManager.getInputPeerByID(peerID), with_my_score: options.withMyScore }, sentRequestOptions).then((updates) => { diff --git a/src/lib/appManagers/appPhotosManager.ts b/src/lib/appManagers/appPhotosManager.ts index 5af6739b..f63c1c72 100644 --- a/src/lib/appManagers/appPhotosManager.ts +++ b/src/lib/appManagers/appPhotosManager.ts @@ -1,7 +1,8 @@ +import { bytesFromHex } from "../../helpers/bytes"; import { CancellablePromise } from "../../helpers/cancellablePromise"; +import { getFileNameByLocation } from "../../helpers/fileName"; import { isSafari } from "../../helpers/userAgent"; import { FileLocation, InputFileLocation, Photo, PhotoSize, PhotosPhotos } from "../../layer"; -import { bytesFromHex, getFileNameByLocation } from "../bin_utils"; import { DownloadOptions } from "../mtproto/apiFileManager"; import apiManager from "../mtproto/mtprotoworker"; import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase"; diff --git a/src/lib/bin_utils.ts b/src/lib/bin_utils.ts deleted file mode 100644 index d354734f..00000000 --- a/src/lib/bin_utils.ts +++ /dev/null @@ -1,356 +0,0 @@ -//import {str2bigInt, divInt_, int2bigInt, bigInt2str, bigInt2bytes} from '../vendor/leemon'; - -// @ts-ignore -import {BigInteger, SecureRandom} from 'jsbn'; -import type { InputFileLocation, FileLocation } from '../layer'; - -/// #if !MTPROTO_WORKER -// @ts-ignore -import pako from 'pako/dist/pako_inflate.min.js'; - -export function gzipUncompress(bytes: ArrayBuffer, toString: true): string; -export function gzipUncompress(bytes: ArrayBuffer, toString?: false): Uint8Array; -export function gzipUncompress(bytes: ArrayBuffer, toString?: boolean): string | Uint8Array { - //console.log(dT(), 'Gzip uncompress start'); - var result = pako.inflate(bytes, toString ? {to: 'string'} : undefined); - //console.log(dT(), 'Gzip uncompress finish'/* , result */); - return result; -} -/// #endif - -export function isObject(object: any) { - return typeof(object) === 'object' && object !== null; -} - -export function bigint(num: number) { - return new BigInteger(num.toString(16), 16); -} - -export function bigStringInt(strNum: string) { - return new BigInteger(strNum, 10); -} - -export function bytesToHex(bytes: ArrayLike) { - bytes = bytes || []; - var arr = []; - for(var i = 0; i < bytes.length; i++) { - arr.push((bytes[i] < 16 ? '0' : '') + (bytes[i] || 0).toString(16)); - } - return arr.join(''); -} - -export function bytesFromHex(hexString: string) { - var len = hexString.length, - i; - var start = 0; - var bytes = []; - - if(hexString.length % 2) { - bytes.push(parseInt(hexString.charAt(0), 16)); - start++; - } - - for(i = start; i < len; i += 2) { - bytes.push(parseInt(hexString.substr(i, 2), 16)); - } - - return bytes; -} - -export function bytesToBase64(bytes: number[] | Uint8Array) { - var mod3 - var result = '' - - for (var nLen = bytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) { - mod3 = nIdx % 3 - nUint24 |= bytes[nIdx] << (16 >>> mod3 & 24) - if (mod3 === 2 || nLen - nIdx === 1) { - result += String.fromCharCode( - uint6ToBase64(nUint24 >>> 18 & 63), - uint6ToBase64(nUint24 >>> 12 & 63), - uint6ToBase64(nUint24 >>> 6 & 63), - uint6ToBase64(nUint24 & 63) - ) - nUint24 = 0 - } - } - - return result.replace(/A(?=A$|$)/g, '=') -} - -export function uint6ToBase64(nUint6: number) { - return nUint6 < 26 - ? nUint6 + 65 - : nUint6 < 52 - ? nUint6 + 71 - : nUint6 < 62 - ? nUint6 - 4 - : nUint6 === 62 - ? 43 - : nUint6 === 63 - ? 47 - : 65 -} - -/* export function base64ToBlob(base64str: string, mimeType: string) { - var sliceSize = 1024; - var byteCharacters = atob(base64str); - var bytesLength = byteCharacters.length; - var slicesCount = Math.ceil(bytesLength / sliceSize); - var byteArrays = new Array(slicesCount); - - for(var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) { - var begin = sliceIndex * sliceSize; - var end = Math.min(begin + sliceSize, bytesLength); - - var bytes = new Array(end - begin); - for(var offset = begin, i = 0; offset < end; ++i, ++offset) { - bytes[i] = byteCharacters[offset].charCodeAt(0); - } - byteArrays[sliceIndex] = new Uint8Array(bytes); - } - - return blobConstruct(byteArrays, mimeType); -} - -export function dataUrlToBlob(url: string) { - // var name = 'b64blob ' + url.length - // console.time(name) - var urlParts = url.split(','); - var base64str = urlParts[1]; - var mimeType = urlParts[0].split(':')[1].split(';')[0]; - var blob = base64ToBlob(base64str, mimeType); - // console.timeEnd(name) - return blob; -} */ - -export function blobConstruct(blobParts: any, mimeType: string = ''): Blob { - let blob; - const safeMimeType = blobSafeMimeType(mimeType); - try { - blob = new Blob(blobParts, {type: safeMimeType}); - } catch(e) { - // @ts-ignore - let bb = new BlobBuilder; - blobParts.forEach((blobPart: any) => { - bb.append(blobPart); - }); - blob = bb.getBlob(safeMimeType); - } - return blob; -} - -export function blobSafeMimeType(mimeType: string) { - if([ - 'image/jpeg', - 'image/png', - 'image/gif', - 'image/webp', - 'image/bmp', - 'video/mp4', - 'video/webm', - 'video/quicktime', - 'audio/ogg', - 'audio/mpeg', - 'audio/mp4', - 'application/json' - ].indexOf(mimeType) === -1) { - return 'application/octet-stream'; - } - - return mimeType; -} - -export function bytesCmp(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) { - var len = bytes1.length; - if(len != bytes2.length) { - return false; - } - - for(var i = 0; i < len; i++) { - if(bytes1[i] != bytes2[i]) { - return false; - } - } - - return true; -} - -export function bytesXor(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) { - var len = bytes1.length; - var bytes = []; - - for (var i = 0; i < len; ++i) { - bytes[i] = bytes1[i] ^ bytes2[i]; - } - - return bytes; -} - -export function bytesFromBigInt(bigInt: BigInteger, len?: number) { - var bytes = bigInt.toByteArray(); - - if(len && bytes.length < len) { - var padding = []; - for(var i = 0, needPadding = len - bytes.length; i < needPadding; i++) { - padding[i] = 0; - } - if(bytes instanceof ArrayBuffer) { - bytes = bufferConcat(padding, bytes); - } else { - bytes = padding.concat(bytes); - } - } else { - while (!bytes[0] && (!len || bytes.length > len)) { - bytes = bytes.slice(1); - } - } - - return bytes; -} - -export function bytesToArrayBuffer(b: number[]) { - return (new Uint8Array(b)).buffer; -} - -export function convertToArrayBuffer(bytes: any | ArrayBuffer | Uint8Array) { - // Be careful with converting subarrays!! - if(bytes instanceof ArrayBuffer) { - return bytes; - } - if(bytes.buffer !== undefined && - bytes.buffer.byteLength == bytes.length * bytes.BYTES_PER_ELEMENT) { - return bytes.buffer; - } - return bytesToArrayBuffer(bytes); -} - -export function convertToUint8Array(bytes: Uint8Array | number[]): Uint8Array { - if((bytes as Uint8Array).buffer !== undefined) { - return bytes as Uint8Array; - } - - return new Uint8Array(bytes); -} - -export function bytesFromArrayBuffer(buffer: ArrayBuffer) { - var len = buffer.byteLength; - var byteView = new Uint8Array(buffer); - var bytes = []; - - for(var i = 0; i < len; ++i) { - bytes[i] = byteView[i]; - } - - return bytes; -} - -export function bufferConcat(buffer1: any, buffer2: any) { - var l1 = buffer1.byteLength || buffer1.length; - var l2 = buffer2.byteLength || buffer2.length; - var tmp = new Uint8Array(l1 + l2); - tmp.set(buffer1 instanceof ArrayBuffer ? new Uint8Array(buffer1) : buffer1, 0); - tmp.set(buffer2 instanceof ArrayBuffer ? new Uint8Array(buffer2) : buffer2, l1); - - return tmp.buffer; -} - -export function bufferConcats(...args: any[]) { - let length = 0; - args.forEach(b => length += b.byteLength || b.length); - - var tmp = new Uint8Array(length); - - let lastLength = 0; - args.forEach(b => { - tmp.set(b instanceof ArrayBuffer ? new Uint8Array(b) : b, lastLength); - lastLength += b.byteLength || b.length; - }); - - return tmp/* .buffer */; -} - -export function bytesFromWordss(input: Uint32Array) { - var o = []; - for(var i = 0; i < input.length * 4; i++) { - o.push((input[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff); - } - - return o; -} - -export function bytesToWordss(input: ArrayBuffer | Uint8Array) { - let bytes: Uint8Array; - if(input instanceof ArrayBuffer) bytes = new Uint8Array(input); - else bytes = input; - - var len = bytes.length; - var words: number[] = []; - var i; - for(i = 0; i < len; i++) { - words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8); - } - - return new Uint32Array(words); -} - -export function longFromInts(high: number, low: number) { - return bigint(high).shiftLeft(32).add(bigint(low)).toString(10); -} - -export function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean, full = false, prepend = false) { - let len = bytes.byteLength || bytes.length; - let needPadding = blockSize - (len % blockSize); - if(needPadding > 0 && (needPadding < blockSize || full)) { - ////console.log('addPadding()', len, blockSize, needPadding); - let padding = new Array(needPadding); - if(zeroes) { - for(let i = 0; i < needPadding; i++) { - padding[i] = 0; - } - } else { - (new SecureRandom()).nextBytes(padding); - } - - if(bytes instanceof ArrayBuffer) { - bytes = (prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding)).buffer; - } else if(bytes instanceof Uint8Array) { - bytes = prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding); - } else { - bytes = prepend ? padding.concat(bytes) : bytes.concat(padding); - } - } - - return bytes; -} - -export function nextRandomInt(maxValue: number) { - return Math.floor(Math.random() * maxValue); -} - -export function getFileNameByLocation(location: InputFileLocation | FileLocation, options?: Partial<{ - fileName: string -}>) { - const fileName = '';//(options?.fileName || '').split('.'); - const ext = fileName[fileName.length - 1] || ''; - - switch(location._) { - case 'inputPhotoFileLocation': - case 'inputDocumentFileLocation': { - const thumbPart = location.thumb_size ? '_' + location.thumb_size : ''; - return (fileName[0] ? fileName[0] + '_' : '') + location.id + thumbPart + (ext ? '.' + ext : ext); - } - - case 'fileLocationToBeDeprecated': - case 'inputPeerPhotoFileLocation': - case 'inputStickerSetThumb': - case 'inputFileLocation': { - return location.volume_id + '_' + location.local_id + (ext ? '.' + ext : ext); - } - - default: { - console.error('Unrecognized location:', location); - return ''; - } - } -} diff --git a/src/lib/cacheStorage.ts b/src/lib/cacheStorage.ts index c7e86643..6c09a5f3 100644 --- a/src/lib/cacheStorage.ts +++ b/src/lib/cacheStorage.ts @@ -1,4 +1,4 @@ -import {blobConstruct} from './bin_utils'; +import { blobConstruct } from '../helpers/blob'; import FileManager from './filemanager'; import { MOUNT_CLASS_TO } from './mtproto/mtproto_config'; //import { logger } from './polyfill'; diff --git a/src/lib/crypto/crypto.worker.js b/src/lib/crypto/crypto.worker.js index cb23fa12..a321d74a 100644 --- a/src/lib/crypto/crypto.worker.js +++ b/src/lib/crypto/crypto.worker.js @@ -8,7 +8,7 @@ secureRandom; import {pqPrimeFactorization, bytesModPow, sha1HashSync, aesEncryptSync, aesDecryptSync, hash_pbkdf2, sha256HashSync, rsaEncrypt} from './crypto_utils'; -import {gzipUncompress} from '../bin_utils'; +import {gzipUncompress} from '../mtproto/bin_utils'; ctx.onmessage = function(e) { var taskID = e.data.taskID, diff --git a/src/lib/crypto/crypto_methods.ts b/src/lib/crypto/crypto_methods.ts index 8e0b056b..8b94b045 100644 --- a/src/lib/crypto/crypto_methods.ts +++ b/src/lib/crypto/crypto_methods.ts @@ -1,4 +1,4 @@ -import { convertToArrayBuffer } from "../bin_utils"; +import { convertToArrayBuffer } from "../../helpers/bytes"; import type { InputCheckPasswordSRP } from "../../layer"; import type { aesEncryptSync } from "./crypto_utils"; diff --git a/src/lib/crypto/crypto_utils.ts b/src/lib/crypto/crypto_utils.ts index a513478a..0f209782 100644 --- a/src/lib/crypto/crypto_utils.ts +++ b/src/lib/crypto/crypto_utils.ts @@ -12,7 +12,9 @@ import {str2bigInt, bpe, equalsInt, greater, // @ts-ignore import {BigInteger} from 'jsbn'; -import { addPadding, bytesToHex, bytesFromHex, nextRandomInt, bytesFromBigInt, bytesToWordss, bytesFromWordss } from '../bin_utils'; +import { addPadding, bytesFromBigInt } from '../mtproto/bin_utils'; +import { bytesToWordss, bytesFromWordss, bytesToHex, bytesFromHex } from '../../helpers/bytes'; +import { nextRandomInt } from '../../helpers/random'; export function longToBytes(sLong: string) { /* let perf = performance.now(); diff --git a/src/lib/crypto/srp.ts b/src/lib/crypto/srp.ts index ce99ea55..53c74edd 100644 --- a/src/lib/crypto/srp.ts +++ b/src/lib/crypto/srp.ts @@ -1,10 +1,10 @@ -import { bufferConcats, bytesToHex, bytesFromHex, bufferConcat, bytesXor } from "../bin_utils"; import CryptoWorker from "../crypto/cryptoworker"; import {str2bigInt, isZero, bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, add, greater} from '../../vendor/leemon'; import {logger, LogLevels} from '../logger'; import { AccountPassword, PasswordKdfAlgo } from "../../layer"; +import { bufferConcats, bytesToHex, bytesFromHex, bufferConcat, bytesXor } from "../../helpers/bytes"; const log = logger('SRP', LogLevels.error); diff --git a/src/lib/filemanager.ts b/src/lib/filemanager.ts index cb16ecef..589c5312 100644 --- a/src/lib/filemanager.ts +++ b/src/lib/filemanager.ts @@ -1,4 +1,4 @@ -import {blobConstruct} from './bin_utils'; +import { blobConstruct } from "../helpers/blob"; export class FileManager { public blobSupported = true; diff --git a/src/lib/mtproto/apiFileManager.ts b/src/lib/mtproto/apiFileManager.ts index 9c374641..03525d63 100644 --- a/src/lib/mtproto/apiFileManager.ts +++ b/src/lib/mtproto/apiFileManager.ts @@ -1,8 +1,9 @@ import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise"; import { notifyAll, notifySomeone } from "../../helpers/context"; +import { getFileNameByLocation } from "../../helpers/fileName"; +import { nextRandomInt } from "../../helpers/random"; import { isSafari } from "../../helpers/userAgent"; import { FileLocation, InputFile, InputFileLocation, UploadFile } from "../../layer"; -import { getFileNameByLocation, nextRandomInt } from "../bin_utils"; import cacheStorage from "../cacheStorage"; import cryptoWorker from "../crypto/cryptoworker"; import FileManager from "../filemanager"; diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index ad96f48f..30835e48 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -1,7 +1,7 @@ import AppStorage from '../storage'; import MTPNetworker, { MTMessage } from './networker'; -import { bytesFromHex, bytesToHex, isObject } from '../bin_utils'; +import { isObject } from './bin_utils'; import networkerFactory from './networkerFactory'; //import { telegramMeWebService } from './mtproto'; import authorizer from './authorizer'; @@ -11,6 +11,7 @@ import { logger } from '../logger'; import type { InvokeApiOptions } from '../../types'; import type { MethodDeclMap } from '../../layer'; import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise'; +import { bytesFromHex, bytesToHex } from '../../helpers/bytes'; /// #if !MTPROTO_WORKER import $rootScope from '../rootScope'; diff --git a/src/lib/mtproto/authorizer.ts b/src/lib/mtproto/authorizer.ts index 61c92472..babd92ed 100644 --- a/src/lib/mtproto/authorizer.ts +++ b/src/lib/mtproto/authorizer.ts @@ -1,6 +1,5 @@ import { TLSerialization, TLDeserialization } from "./tl_utils"; import dcConfigurator from "./dcConfigurator"; -import { bytesToHex, bytesCmp, bytesFromHex, bytesXor } from "../bin_utils"; import rsaKeysManager from "./rsaKeysManager"; import timeManager from "./timeManager"; @@ -10,6 +9,7 @@ import { BigInteger } from "jsbn"; import CryptoWorker from "../crypto/cryptoworker"; import { logger, LogLevels } from "../logger"; +import { bytesCmp, bytesToHex, bytesFromHex, bytesXor } from "../../helpers/bytes"; //import { bigInt2str, greater, int2bigInt, one, powMod, str2bigInt, sub } from "../../vendor/leemon"; /* let fNewNonce: any = bytesFromHex('8761970c24cb2329b5b2459752c502f3057cb7e8dbab200e526e8767fdc73b3c').reverse(); diff --git a/src/lib/mtproto/bin_utils.ts b/src/lib/mtproto/bin_utils.ts new file mode 100644 index 00000000..d5650026 --- /dev/null +++ b/src/lib/mtproto/bin_utils.ts @@ -0,0 +1,115 @@ +//import {str2bigInt, divInt_, int2bigInt, bigInt2str, bigInt2bytes} from '../vendor/leemon'; + +// @ts-ignore +import {BigInteger, SecureRandom} from 'jsbn'; +import { bufferConcat, bufferConcats } from '../../helpers/bytes'; + +/// #if !MTPROTO_WORKER +// @ts-ignore +import pako from 'pako/dist/pako_inflate.min.js'; + +export function gzipUncompress(bytes: ArrayBuffer, toString: true): string; +export function gzipUncompress(bytes: ArrayBuffer, toString?: false): Uint8Array; +export function gzipUncompress(bytes: ArrayBuffer, toString?: boolean): string | Uint8Array { + //console.log(dT(), 'Gzip uncompress start'); + var result = pako.inflate(bytes, toString ? {to: 'string'} : undefined); + //console.log(dT(), 'Gzip uncompress finish'/* , result */); + return result; +} +/// #endif + +export function isObject(object: any) { + return typeof(object) === 'object' && object !== null; +} + +export function bigint(num: number) { + return new BigInteger(num.toString(16), 16); +} + +export function bigStringInt(strNum: string) { + return new BigInteger(strNum, 10); +} + +/* export function base64ToBlob(base64str: string, mimeType: string) { + var sliceSize = 1024; + var byteCharacters = atob(base64str); + var bytesLength = byteCharacters.length; + var slicesCount = Math.ceil(bytesLength / sliceSize); + var byteArrays = new Array(slicesCount); + + for(var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) { + var begin = sliceIndex * sliceSize; + var end = Math.min(begin + sliceSize, bytesLength); + + var bytes = new Array(end - begin); + for(var offset = begin, i = 0; offset < end; ++i, ++offset) { + bytes[i] = byteCharacters[offset].charCodeAt(0); + } + byteArrays[sliceIndex] = new Uint8Array(bytes); + } + + return blobConstruct(byteArrays, mimeType); +} + +export function dataUrlToBlob(url: string) { + // var name = 'b64blob ' + url.length + // console.time(name) + var urlParts = url.split(','); + var base64str = urlParts[1]; + var mimeType = urlParts[0].split(':')[1].split(';')[0]; + var blob = base64ToBlob(base64str, mimeType); + // console.timeEnd(name) + return blob; +} */ + +export function bytesFromBigInt(bigInt: BigInteger, len?: number) { + var bytes = bigInt.toByteArray(); + + if(len && bytes.length < len) { + var padding = []; + for(var i = 0, needPadding = len - bytes.length; i < needPadding; i++) { + padding[i] = 0; + } + if(bytes instanceof ArrayBuffer) { + bytes = bufferConcat(padding, bytes); + } else { + bytes = padding.concat(bytes); + } + } else { + while (!bytes[0] && (!len || bytes.length > len)) { + bytes = bytes.slice(1); + } + } + + return bytes; +} + +export function longFromInts(high: number, low: number) { + return bigint(high).shiftLeft(32).add(bigint(low)).toString(10); +} + +export function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean, full = false, prepend = false) { + let len = bytes.byteLength || bytes.length; + let needPadding = blockSize - (len % blockSize); + if(needPadding > 0 && (needPadding < blockSize || full)) { + ////console.log('addPadding()', len, blockSize, needPadding); + let padding = new Array(needPadding); + if(zeroes) { + for(let i = 0; i < needPadding; i++) { + padding[i] = 0; + } + } else { + (new SecureRandom()).nextBytes(padding); + } + + if(bytes instanceof ArrayBuffer) { + bytes = (prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding)).buffer; + } else if(bytes instanceof Uint8Array) { + bytes = prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding); + } else { + bytes = prepend ? padding.concat(bytes) : bytes.concat(padding); + } + } + + return bytes; +} \ No newline at end of file diff --git a/src/lib/mtproto/mtproto.worker.ts b/src/lib/mtproto/mtproto.worker.ts index 8b1bd9a9..6a811765 100644 --- a/src/lib/mtproto/mtproto.worker.ts +++ b/src/lib/mtproto/mtproto.worker.ts @@ -1,6 +1,5 @@ // just to include -import {secureRandom} from '../polyfill'; -secureRandom; +import '../polyfill'; import apiManager from "./apiManager"; import AppStorage from '../storage'; diff --git a/src/lib/mtproto/networker.ts b/src/lib/mtproto/networker.ts index 3aa1f908..5a81110e 100644 --- a/src/lib/mtproto/networker.ts +++ b/src/lib/mtproto/networker.ts @@ -1,7 +1,5 @@ -import {isObject} from '../bin_utils'; -import {convertToUint8Array, - bufferConcat, nextRandomInt, bytesToHex, - bytesCmp, bigStringInt} from '../bin_utils'; +import {isObject} from './bin_utils'; +import { bigStringInt} from './bin_utils'; import {TLDeserialization, TLSerialization} from './tl_utils'; import CryptoWorker from '../crypto/cryptoworker'; import AppStorage from '../storage'; @@ -13,6 +11,8 @@ import { Modes, App } from './mtproto_config'; import { InvokeApiOptions } from '../../types'; import { longToBytes } from '../crypto/crypto_utils'; import MTTransport from './transports/transport'; +import { convertToUint8Array, bufferConcat, bytesCmp, bytesToHex } from '../../helpers/bytes'; +import { nextRandomInt } from '../../helpers/random'; /// #if MTPROTO_HTTP_UPLOAD // @ts-ignore diff --git a/src/lib/mtproto/referenceDatabase.ts b/src/lib/mtproto/referenceDatabase.ts index 7eb1b6a0..60c9bf13 100644 --- a/src/lib/mtproto/referenceDatabase.ts +++ b/src/lib/mtproto/referenceDatabase.ts @@ -2,7 +2,7 @@ import appMessagesManager from "../appManagers/appMessagesManager"; import { Photo } from "../../layer"; import { deepEqual } from "../utils"; import { MOUNT_CLASS_TO } from "./mtproto_config"; -import { bytesToHex } from "../bin_utils"; +import { bytesToHex } from "../../helpers/bytes"; export type ReferenceContext = ReferenceContext.referenceContextProfilePhoto | ReferenceContext.referenceContextMessage; export namespace ReferenceContext { diff --git a/src/lib/mtproto/rsaKeysManager.ts b/src/lib/mtproto/rsaKeysManager.ts index ff80f13a..5500027e 100644 --- a/src/lib/mtproto/rsaKeysManager.ts +++ b/src/lib/mtproto/rsaKeysManager.ts @@ -1,6 +1,7 @@ import { TLSerialization } from "./tl_utils"; -import { bytesFromHex, bigStringInt, bytesToHex, bytesFromArrayBuffer } from "../bin_utils"; +import { bigStringInt } from "./bin_utils"; import CryptoWorker from '../crypto/cryptoworker'; +import { bytesFromArrayBuffer, bytesFromHex, bytesToHex } from "../../helpers/bytes"; export class RSAKeysManager { diff --git a/src/lib/mtproto/timeManager.ts b/src/lib/mtproto/timeManager.ts index 8a9a45aa..3a8915ba 100644 --- a/src/lib/mtproto/timeManager.ts +++ b/src/lib/mtproto/timeManager.ts @@ -1,5 +1,6 @@ import AppStorage from '../storage'; -import { nextRandomInt, longFromInts } from '../bin_utils'; +import { longFromInts } from './bin_utils'; +import { nextRandomInt } from '../../helpers/random'; export class TimeManager { private lastMessageID = [0, 0]; diff --git a/src/lib/mtproto/tl_utils.ts b/src/lib/mtproto/tl_utils.ts index dd3eb1ed..e28fb014 100644 --- a/src/lib/mtproto/tl_utils.ts +++ b/src/lib/mtproto/tl_utils.ts @@ -1,4 +1,5 @@ -import { bigint, bigStringInt, bytesToHex, isObject } from '../bin_utils'; +import { bytesToHex } from '../../helpers/bytes'; +import { bigint, bigStringInt, isObject } from './bin_utils'; /// #if MTPROTO_WORKER // @ts-ignore import { gzipUncompress } from '../crypto/crypto_utils'; diff --git a/src/lib/mtproto/transports/http.ts b/src/lib/mtproto/transports/http.ts index 06306379..602c0062 100644 --- a/src/lib/mtproto/transports/http.ts +++ b/src/lib/mtproto/transports/http.ts @@ -1,5 +1,5 @@ +import { bytesFromArrayBuffer } from '../../../helpers/bytes'; import MTTransport from './transport'; -import { bytesFromArrayBuffer } from '../../bin_utils'; export default class HTTP extends MTTransport { constructor(dcID: number, url: string) { diff --git a/src/lib/mtproto/transports/obfuscation.ts b/src/lib/mtproto/transports/obfuscation.ts index 94b61af9..d2338ceb 100644 --- a/src/lib/mtproto/transports/obfuscation.ts +++ b/src/lib/mtproto/transports/obfuscation.ts @@ -1,6 +1,6 @@ //import aesjs from 'aes-js'; import { CTR } from "@cryptography/aes"; -import { bytesFromWordss } from "../../bin_utils"; +import { bytesFromWordss } from "../../../helpers/bytes"; import { Codec } from "./codec"; /* diff --git a/src/lib/mtproto/transports/padded.ts b/src/lib/mtproto/transports/padded.ts index 718e0e12..d44dc20d 100644 --- a/src/lib/mtproto/transports/padded.ts +++ b/src/lib/mtproto/transports/padded.ts @@ -1,4 +1,4 @@ -import { nextRandomInt } from "../../bin_utils"; +import { nextRandomInt } from "../../../helpers/random"; import { IntermediatePacketCodec } from "./intermediate"; /* Data packets are aligned to 4bytes. This codec adds random bytes of size from 0 to 3 bytes, which are ignored by decoder. */ diff --git a/src/lib/polyfill.ts b/src/lib/polyfill.ts index 4136d9bc..c65dcc8b 100644 --- a/src/lib/polyfill.ts +++ b/src/lib/polyfill.ts @@ -1,8 +1,9 @@ -import { bytesToHex, bytesFromHex, bufferConcats } from "./bin_utils"; // @ts-ignore -import {SecureRandom} from 'jsbn'; +//import {SecureRandom} from 'jsbn'; +import { bytesToHex, bytesFromHex, bufferConcats } from '../helpers/bytes'; +import { nextRandomInt } from '../helpers/random'; -export const secureRandom = new SecureRandom(); +//export const secureRandom = new SecureRandom(); Object.defineProperty(Uint8Array.prototype, 'hex', { get: function(): string { @@ -17,7 +18,10 @@ Object.defineProperty(Uint8Array.prototype, 'hex', { }); Uint8Array.prototype.randomize = function() { - secureRandom.nextBytes(this); + //secureRandom.nextBytes(this); + for(let i = 0; i < this.length; ++i) { + this[i] = nextRandomInt(255); + } return this; }; diff --git a/src/pages/pageSignQR.ts b/src/pages/pageSignQR.ts index 2c165474..fc2bd40f 100644 --- a/src/pages/pageSignQR.ts +++ b/src/pages/pageSignQR.ts @@ -5,9 +5,9 @@ import pageIm from './pageIm'; import pagePassword from './pagePassword'; import pageSignIn from './pageSignIn'; import { App } from '../lib/mtproto/mtproto_config'; -import { bytesToBase64, bytesCmp } from '../lib/bin_utils'; import serverTimeManager from '../lib/mtproto/serverTimeManager'; import { AuthAuthorization, AuthLoginToken } from '../layer'; +import { bytesCmp, bytesToBase64 } from '../helpers/bytes'; let onFirstMount = async() => { const pageElement = page.pageEl; diff --git a/src/tests/crypto_methods.test.ts b/src/tests/crypto_methods.test.ts index ebce2a04..92b28d31 100644 --- a/src/tests/crypto_methods.test.ts +++ b/src/tests/crypto_methods.test.ts @@ -1,5 +1,5 @@ +import { bytesFromArrayBuffer, bytesFromHex } from '../helpers/bytes'; import CryptoWorker from '../lib/crypto/cryptoworker'; -import { bytesFromHex, bytesFromArrayBuffer } from '../lib/bin_utils'; test('factorize', () => { for(let i = 0; i < 10; ++i) {