diff --git a/package-lock.json b/package-lock.json index 5569c8b3..a2090541 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1312,6 +1312,12 @@ "minimist": "^1.2.0" } }, + "@cryptography/aes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@cryptography/aes/-/aes-0.1.1.tgz", + "integrity": "sha512-PcYz4FDGblO6tM2kSC+VzhhK62vml6k6/YAkiWtyPvrgJVfnDRoHGDtKn5UiaRRUrvUTTocBpvc2rRgTCqxjsg==", + "dev": true + }, "@cryptography/sha1": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@cryptography/sha1/-/sha1-0.1.0.tgz", diff --git a/package.json b/package.json index 56feba86..cf1d3028 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "webpack-dev-server --open --config webpack.dev.js", "start-production": "webpack-dev-server --open --config webpack.prod.js", - "serve-serve": "webpack-serve --compress --port 9001 --host localhost --no-watch --static ./public --config webpack.prod.js", + "serve": "node server.js", "build": "webpack --config webpack.prod.js", "test": "jest --config=jest.config.js", "profile": "webpack --profile --json > stats.json --config webpack.prod.js" @@ -21,6 +21,7 @@ "@babel/core": "^7.9.0", "@babel/preset-env": "^7.9.5", "@babel/preset-typescript": "^7.9.0", + "@cryptography/aes": "^0.1.1", "@cryptography/sha1": "^0.1.0", "@cryptography/sha256": "^0.2.0", "@types/aes-js": "^3.1.1", diff --git a/src/components/emoticonsDropdown.ts b/src/components/emoticonsDropdown.ts index e27b8dc0..7e5e5c5b 100644 --- a/src/components/emoticonsDropdown.ts +++ b/src/components/emoticonsDropdown.ts @@ -71,9 +71,9 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, if(menuScroll) { if(i < heights.length - 4) { - menuScroll.container.scrollLeft = (i - 3) * 50; + menuScroll.container.scrollLeft = (i - 3) * 47; } else { - menuScroll.container.scrollLeft = i * 50; + menuScroll.container.scrollLeft = i * 47; } } @@ -85,7 +85,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, }; { - let categories = ["Smileys & Emotion", "Animals & Nature", "Food & Drink", "Travel & Places", "Activities", "Objects", "Symbols", "Flags", "Skin Tones"]; + let categories = ["Smileys & Emotion", "Animals & Nature", "Food & Drink", "Travel & Places", "Activities", "Objects", /* "Symbols", */"Flags", "Skin Tones"]; let divs: { [category: string]: HTMLDivElement } = {}; @@ -100,12 +100,16 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, let details = Config.Emoji.emoji[unified]; let category = details[keyCategory]; + if(category == 'Symbols') category = 'Objects'; + details.unified = unified; if(!sorted[category]) sorted[category] = []; sorted[category][details.sort_order] = details; } + //console.log('emoticons sorted:', sorted); + Object.keys(sorted).forEach(c => sorted[c].sort()); categories.pop(); @@ -143,20 +147,29 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, } //console.timeEnd('emojiParse'); + let contentEmojiDiv = document.getElementById('content-emoji') as HTMLDivElement; let heights: number[] = [0]; - let contentEmojiDiv = document.getElementById('content-emoji') as HTMLDivElement; - categories.forEach(category => { + let prevCategoryIndex = 1; + let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement; + let emojiScroll = new Scrollable(contentEmojiDiv, 'y', 500, 'EMOJI', null); + emojiScroll.container.addEventListener('scroll', (e) => { + prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container); + }); + //emojiScroll.setVirtualContainer(emojiScroll.container); + + categories.map(category => { let div = divs[category]; if(!div) { console.error('no div by category:', category); } - contentEmojiDiv.append(div); + emojiScroll.append(div); + return div; + }).forEach(div => { + //console.log('emoji heights push: ', (heights[heights.length - 1] || 0) + div.scrollHeight, div, div.scrollHeight); heights.push((heights[heights.length - 1] || 0) + div.scrollHeight); - - //console.log(div, div.scrollHeight); }); contentEmojiDiv.addEventListener('click', function(e) { @@ -184,14 +197,6 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, btnSend.classList.remove('tgico-microphone2'); }); - let prevCategoryIndex = 1; - let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement; - let emojiScroll = new Scrollable(contentEmojiDiv, 'y', 500, 'EMOJI', contentEmojiDiv); - emojiScroll.container.addEventListener('scroll', (e) => { - prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container); - }); - //emojiScroll.setVirtualContainer(emojiScroll.container); - emoticonsMenuOnClick(menu, heights, emojiScroll); } @@ -273,13 +278,15 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, heightRAF = window.requestAnimationFrame(() => { heightRAF = 0; + let paddingTop = parseInt(window.getComputedStyle(stickersScroll.container).getPropertyValue('padding-top')) || 0; + heights.length = 0; let concated = stickersScroll.hiddenElements.up.concat(stickersScroll.visibleElements, stickersScroll.hiddenElements.down); concated.forEach((el, i) => { - heights[i] = (heights[i - 1] || 0) + el.height; + heights[i] = (heights[i - 1] || 0) + el.height + (i == 0 ? paddingTop : 0); }); - console.log('stickers concated', concated, heights); + //console.log('stickers concated', concated, heights); }); /* Array.from(stickersDiv.children).forEach((div, i) => { @@ -343,12 +350,13 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, //stickersScroll.append(categoryDiv); let stickerSet = await appStickersManager.getStickerSet(set); + + //console.log('got stickerSet', stickerSet, li); if(stickerSet.set.thumb) { - let thumb = stickerSet.set.thumb; - appStickersManager.getStickerSetThumb(stickerSet.set).then((blob) => { - if(thumb.w == 1 && thumb.h == 1) { // means animated + //console.log('setting thumb', stickerSet, blob); + if(stickerSet.set.pFlags.animated) { // means animated const reader = new FileReader(); reader.addEventListener('loadend', async(e) => { diff --git a/src/components/pageSignIn.ts b/src/components/pageSignIn.ts index b094b31a..7494237b 100644 --- a/src/components/pageSignIn.ts +++ b/src/components/pageSignIn.ts @@ -38,7 +38,7 @@ export default () => { installed = true; //const countries: Country[] = _countries.default.filter(c => c.emoji); - const countries: Country[] = Config.Countries.filter(c => c.emoji); + const countries: Country[] = Config.Countries.filter(c => c.emoji).sort((a, b) => a.name.localeCompare(b.name)); let lastCountrySelected = ''; @@ -174,9 +174,9 @@ export default () => { } if(country && (this.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) { - btnNext.style.display = ''; + btnNext.style.visibility = ''; } else { - btnNext.style.display = 'none'; + btnNext.style.visibility = 'hidden'; } }); diff --git a/src/components/scrollable.ts b/src/components/scrollable.ts index d84e9061..e64e5491 100644 --- a/src/components/scrollable.ts +++ b/src/components/scrollable.ts @@ -104,6 +104,10 @@ export default class Scrollable { constructor(public el: HTMLElement, axis: 'y' | 'x' = 'y', public splitOffset = 300, logPrefix = '', public appendTo = el, public onScrollOffset = splitOffset) { this.container = document.createElement('div'); this.container.classList.add('scrollable'); + + if(!appendTo) { + this.appendTo = this.container; + } this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : '')); @@ -413,7 +417,7 @@ export default class Scrollable { let appendTo = this.splitUp || this.appendTo; clearTimeout(this.disableHoverTimeout); - if(this.el != this.appendTo) { + if(this.el != this.appendTo && this.appendTo != this.container) { if(!appendTo.classList.contains('disable-hover')) { appendTo.classList.add('disable-hover'); } diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index e90c1752..8636ebaa 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -543,7 +543,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: ( if(doc.thumbs && !div.firstElementChild && (!doc.downloaded || stickerType == 2)) { let thumb = doc.thumbs[0]; - console.log('wrap sticker', thumb, div); + //console.log('wrap sticker', thumb, div); if(thumb.bytes) { apiFileManager.saveSmallFile(thumb.location, thumb.bytes); diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index 4018c687..dad67732 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -1336,7 +1336,7 @@ export class AppImManager { this.log('messageMediaDocument', doc, bubble); - if(doc.sticker && doc.size <= 1e6) { + if(doc.sticker/* && doc.size <= 1e6 */) { bubble.classList.add('sticker'); if(doc.animated) { diff --git a/src/lib/appManagers/appSidebarLeft.ts b/src/lib/appManagers/appSidebarLeft.ts index a3dbce94..b6db478f 100644 --- a/src/lib/appManagers/appSidebarLeft.ts +++ b/src/lib/appManagers/appSidebarLeft.ts @@ -8,6 +8,7 @@ import appMessagesIDsManager from "./appMessagesIDsManager"; import appImManager from "./appImManager"; import appUsersManager from "./appUsersManager"; import { appPeersManager } from "../services"; +import apiManager from "../mtproto/apiManager"; let testScroll = false; @@ -50,6 +51,7 @@ class AppSidebarLeft { private menuEl = this.toolsBtn.querySelector('.btn-menu'); private savedBtn = this.menuEl.querySelector('.menu-saved'); private archivedBtn = this.menuEl.querySelector('.menu-archive'); + private logOutBtn = this.menuEl.querySelector('.menu-logout'); public archivedCount = this.archivedBtn.querySelector('.archived-count') as HTMLSpanElement; private listsContainer: HTMLDivElement = null; @@ -130,6 +132,10 @@ class AppSidebarLeft { //this.toolsBtn.classList.remove('tgico-menu', 'btn-menu-toggle'); //this.toolsBtn.classList.add('tgico-back'); }); + + this.logOutBtn.addEventListener('click', (e) => { + apiManager.logOut(); + }); if(testScroll) { for(let i = 0; i < 1000; ++i) { diff --git a/src/lib/appManagers/appStickersManager.ts b/src/lib/appManagers/appStickersManager.ts index 57114285..54e1f115 100644 --- a/src/lib/appManagers/appStickersManager.ts +++ b/src/lib/appManagers/appStickersManager.ts @@ -2,6 +2,7 @@ import AppStorage from '../storage'; import { MTDocument } from '../../components/wrappers'; import apiManager from '../mtproto/apiManager'; import apiFileManager from '../mtproto/apiFileManager'; +import appDocsManager from './appDocsManager'; export type MTStickerSet = { _: 'stickerSet', @@ -27,6 +28,9 @@ export type MTStickerSet = { h: number, size: number }, + pFlags: { + animated?: boolean + } thumb_dc_id?: number, count: number, hash: number @@ -52,12 +56,23 @@ class appStickersManager { [stickerSetID: string]: MTStickerSetFull }>('stickerSets').then((sets) => { if(sets) { + for(let id in sets) { + let set = sets[id]; + set.documents.forEach(doc => { + delete doc.downloaded; + delete doc.url; + + this.saveSticker(doc); + }); + } + this.stickerSets = sets; } }); } public saveSticker(doc: MTDocument) { + if(this.documents[doc.id]) return this.documents[doc.id]; /* Object.keys(doc).forEach(key => { if(doc[key] instanceof Uint8Array) { doc[key] = Array.from(doc[key]); @@ -66,7 +81,10 @@ class appStickersManager { doc.file_reference = Array.from(doc.file_reference); + appDocsManager.saveDoc(doc); this.documents[doc.id] = doc; + + return doc; } public getSticker(fileID: string) { diff --git a/src/lib/bin_utils.ts b/src/lib/bin_utils.ts index 6fb9c573..ba66c92c 100644 --- a/src/lib/bin_utils.ts +++ b/src/lib/bin_utils.ts @@ -282,7 +282,7 @@ export function longToInts(sLong: string) { return [divRem[0].intValue(), divRem[1].intValue()]; } -export function bytesFromWords(wordArray: any) { +export function bytesFromWords(wordArray: {words: number[] | Uint8Array | Uint32Array, sigBytes: number}) { var words = wordArray.words; var sigBytes = wordArray.sigBytes; var bytes = []; @@ -294,6 +294,30 @@ export function bytesFromWords(wordArray: any) { return bytes; } +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 longToBytes(sLong: string) { return bytesFromWords({words: longToInts(sLong), sigBytes: 8}).reverse(); } diff --git a/src/lib/crypto/crypto.js b/src/lib/crypto/crypto.js deleted file mode 100644 index 472ace38..00000000 --- a/src/lib/crypto/crypto.js +++ /dev/null @@ -1,2184 +0,0 @@ -/* -CryptoJS v3.1.2 -code.google.com/p/crypto-js -(c) 2009-2013 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -/** - * CryptoJS core components. - */ - -console.log('CryptoJS included!'); - -var CryptoJS /* = this.CryptoJS = globalThis.CryptoJS */ = CryptoJS || (function (Math, undefined) { - /** - * CryptoJS namespace. - */ - var C = {}; - - /** - * Library namespace. - */ - var C_lib = C.lib = {}; - - /** - * Base object for prototypal inheritance. - */ - var Base = C_lib.Base = (function () { - function F() {} - - return { - /** - * Creates a new object that inherits from this object. - * - * @param {Object} overrides Properties to copy into the new object. - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * field: 'value', - * - * method: function () { - * } - * }); - */ - extend: function (overrides) { - // Spawn - F.prototype = this; - var subtype = new F(); - - // Augment - if (overrides) { - subtype.mixIn(overrides); - } - - // Create default initializer - if (!subtype.hasOwnProperty('init')) { - subtype.init = function () { - subtype.$super.init.apply(this, arguments); - }; - } - - // Initializer's prototype is the subtype object - subtype.init.prototype = subtype; - - // Reference supertype - subtype.$super = this; - - return subtype; - }, - - /** - * Extends this object and runs the init method. - * Arguments to create() will be passed to init(). - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var instance = MyType.create(); - */ - create: function () { - var instance = this.extend(); - instance.init.apply(instance, arguments); - - return instance; - }, - - /** - * Initializes a newly created object. - * Override this method to add some logic when your objects are created. - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * init: function () { - * // ... - * } - * }); - */ - init: function () { - }, - - /** - * Copies properties into this object. - * - * @param {Object} properties The properties to mix in. - * - * @example - * - * MyType.mixIn({ - * field: 'value' - * }); - */ - mixIn: function (properties) { - for (var propertyName in properties) { - if (properties.hasOwnProperty(propertyName)) { - this[propertyName] = properties[propertyName]; - } - } - - // IE won't copy toString using the loop above - if (properties.hasOwnProperty('toString')) { - this.toString = properties.toString; - } - }, - - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = instance.clone(); - */ - clone: function () { - return this.init.prototype.extend(this); - } - }; - }()); - - /** - * An array of 32-bit words. - * - * @property {Array} words The array of 32-bit words. - * @property {number} sigBytes The number of significant bytes in this word array. - */ - var WordArray = C_lib.WordArray = Base.extend({ - /** - * Initializes a newly created word array. - * - * @param {Array} words (Optional) An array of 32-bit words. - * @param {number} sigBytes (Optional) The number of significant bytes in the words. - * - * @example - * - * var wordArray = CryptoJS.lib.WordArray.create(); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); - */ - init: function (words, sigBytes) { - words = this.words = words || []; - - if (sigBytes != undefined) { - this.sigBytes = sigBytes; - } else { - this.sigBytes = words.length * 4; - } - }, - - /** - * Converts this word array to a string. - * - * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex - * - * @return {string} The stringified word array. - * - * @example - * - * var string = wordArray + ''; - * var string = wordArray.toString(); - * var string = wordArray.toString(CryptoJS.enc.Utf8); - */ - toString: function (encoder) { - return (encoder || Hex).stringify(this); - }, - - /** - * Concatenates a word array to this word array. - * - * @param {WordArray} wordArray The word array to append. - * - * @return {WordArray} This word array. - * - * @example - * - * wordArray1.concat(wordArray2); - */ - concat: function (wordArray) { - // Shortcuts - var thisWords = this.words; - var thatWords = wordArray.words; - var thisSigBytes = this.sigBytes; - var thatSigBytes = wordArray.sigBytes; - - // Clamp excess bits - this.clamp(); - - // Concat - if (thisSigBytes % 4) { - // Copy one byte at a time - for (var i = 0; i < thatSigBytes; i++) { - var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); - } - } else if (thatWords.length > 0xffff) { - // Copy one word at a time - for (var i = 0; i < thatSigBytes; i += 4) { - thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; - } - } else { - // Copy all words at once - // thisWords.push.apply(thisWords, thatWords); - - // HOTFIX from: https://code.google.com/p/crypto-js/issues/detail?id=90 - for (var i = 0; i < thatWords.length; i++) { - thisWords.push(thatWords[i]); - } - } - this.sigBytes += thatSigBytes; - - // Chainable - return this; - }, - - /** - * Removes insignificant bits. - * - * @example - * - * wordArray.clamp(); - */ - clamp: function () { - // Shortcuts - var words = this.words; - var sigBytes = this.sigBytes; - - // Clamp - words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); - words.length = Math.ceil(sigBytes / 4); - }, - - /** - * Creates a copy of this word array. - * - * @return {WordArray} The clone. - * - * @example - * - * var clone = wordArray.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone.words = this.words.slice(0); - - return clone; - }, - - /** - * Creates a word array filled with random bytes. - * - * @param {number} nBytes The number of random bytes to generate. - * - * @return {WordArray} The random word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.lib.WordArray.random(16); - */ - random: function (nBytes) { - var words = []; - for (var i = 0; i < nBytes; i += 4) { - words.push((Math.random() * 0x100000000) | 0); - } - - return new WordArray.init(words, nBytes); - } - }); - - /** - * Encoder namespace. - */ - var C_enc = C.enc = {}; - - /** - * Hex encoding strategy. - */ - var Hex = C_enc.Hex = { - /** - * Converts a word array to a hex string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The hex string. - * - * @static - * - * @example - * - * var hexString = CryptoJS.enc.Hex.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var hexChars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - hexChars.push((bite >>> 4).toString(16)); - hexChars.push((bite & 0x0f).toString(16)); - } - - return hexChars.join(''); - }, - - /** - * Converts a hex string to a word array. - * - * @param {string} hexStr The hex string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Hex.parse(hexString); - */ - parse: function (hexStr) { - // Shortcut - var hexStrLength = hexStr.length; - - // Convert - var words = []; - for (var i = 0; i < hexStrLength; i += 2) { - words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); - } - - return new WordArray.init(words, hexStrLength / 2); - } - }; - - /** - * Latin1 encoding strategy. - */ - var Latin1 = C_enc.Latin1 = { - /** - * Converts a word array to a Latin1 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The Latin1 string. - * - * @static - * - * @example - * - * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var latin1Chars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - latin1Chars.push(String.fromCharCode(bite)); - } - - return latin1Chars.join(''); - }, - - /** - * Converts a Latin1 string to a word array. - * - * @param {string} latin1Str The Latin1 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); - */ - parse: function (latin1Str) { - // Shortcut - var latin1StrLength = latin1Str.length; - - // Convert - var words = []; - for (var i = 0; i < latin1StrLength; i++) { - words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); - } - - return new WordArray.init(words, latin1StrLength); - } - }; - - /** - * UTF-8 encoding strategy. - */ - var Utf8 = C_enc.Utf8 = { - /** - * Converts a word array to a UTF-8 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The UTF-8 string. - * - * @static - * - * @example - * - * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); - */ - stringify: function (wordArray) { - try { - return decodeURIComponent(escape(Latin1.stringify(wordArray))); - } catch (e) { - throw new Error('Malformed UTF-8 data'); - } - }, - - /** - * Converts a UTF-8 string to a word array. - * - * @param {string} utf8Str The UTF-8 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); - */ - parse: function (utf8Str) { - return Latin1.parse(unescape(encodeURIComponent(utf8Str))); - } - }; - - /** - * Abstract buffered block algorithm template. - * - * The property blockSize must be implemented in a concrete subtype. - * - * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 - */ - var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ - /** - * Resets this block algorithm's data buffer to its initial state. - * - * @example - * - * bufferedBlockAlgorithm.reset(); - */ - reset: function () { - // Initial values - this._data = new WordArray.init(); - this._nDataBytes = 0; - }, - - /** - * Adds new data to this block algorithm's buffer. - * - * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. - * - * @example - * - * bufferedBlockAlgorithm._append('data'); - * bufferedBlockAlgorithm._append(wordArray); - */ - _append: function (data) { - // Convert string to WordArray, else assume WordArray already - if (typeof data == 'string') { - data = Utf8.parse(data); - } - - // Append - this._data.concat(data); - this._nDataBytes += data.sigBytes; - }, - - /** - * Processes available data blocks. - * - * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. - * - * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. - * - * @return {WordArray} The processed data. - * - * @example - * - * var processedData = bufferedBlockAlgorithm._process(); - * var processedData = bufferedBlockAlgorithm._process(!!'flush'); - */ - _process: function (doFlush) { - // Shortcuts - var data = this._data; - var dataWords = data.words; - var dataSigBytes = data.sigBytes; - var blockSize = this.blockSize; - var blockSizeBytes = blockSize * 4; - - // Count blocks ready - var nBlocksReady = dataSigBytes / blockSizeBytes; - if (doFlush) { - // Round up to include partial blocks - nBlocksReady = Math.ceil(nBlocksReady); - } else { - // Round down to include only full blocks, - // less the number of blocks that must remain in the buffer - nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); - } - - // Count words ready - var nWordsReady = nBlocksReady * blockSize; - - // Count bytes ready - var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); - - // Process blocks - if (nWordsReady) { - for (var offset = 0; offset < nWordsReady; offset += blockSize) { - // Perform concrete-algorithm logic - this._doProcessBlock(dataWords, offset); - } - - // Remove processed words - var processedWords = dataWords.splice(0, nWordsReady); - data.sigBytes -= nBytesReady; - } - - // Return processed words - return new WordArray.init(processedWords, nBytesReady); - }, - - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = bufferedBlockAlgorithm.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone._data = this._data.clone(); - - return clone; - }, - - _minBufferSize: 0 - }); - - /** - * Abstract hasher template. - * - * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) - */ - var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ - /** - * Configuration options. - */ - cfg: Base.extend(), - - /** - * Initializes a newly created hasher. - * - * @param {Object} cfg (Optional) The configuration options to use for this hash computation. - * - * @example - * - * var hasher = CryptoJS.algo.SHA256.create(); - */ - init: function (cfg) { - // Apply config defaults - this.cfg = this.cfg.extend(cfg); - - // Set initial values - this.reset(); - }, - - /** - * Resets this hasher to its initial state. - * - * @example - * - * hasher.reset(); - */ - reset: function () { - // Reset data buffer - BufferedBlockAlgorithm.reset.call(this); - - // Perform concrete-hasher logic - this._doReset(); - }, - - /** - * Updates this hasher with a message. - * - * @param {WordArray|string} messageUpdate The message to append. - * - * @return {Hasher} This hasher. - * - * @example - * - * hasher.update('message'); - * hasher.update(wordArray); - */ - update: function (messageUpdate) { - // Append - this._append(messageUpdate); - - // Update the hash - this._process(); - - // Chainable - return this; - }, - - /** - * Finalizes the hash computation. - * Note that the finalize operation is effectively a destructive, read-once operation. - * - * @param {WordArray|string} messageUpdate (Optional) A final message update. - * - * @return {WordArray} The hash. - * - * @example - * - * var hash = hasher.finalize(); - * var hash = hasher.finalize('message'); - * var hash = hasher.finalize(wordArray); - */ - finalize: function (messageUpdate) { - // Final message update - if (messageUpdate) { - this._append(messageUpdate); - } - - // Perform concrete-hasher logic - var hash = this._doFinalize(); - - return hash; - }, - - blockSize: 512/32, - - /** - * Creates a shortcut function to a hasher's object interface. - * - * @param {Hasher} hasher The hasher to create a helper for. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); - */ - _createHelper: function (hasher) { - return function (message, cfg) { - return new hasher.init(cfg).finalize(message); - }; - }, - - /** - * Creates a shortcut function to the HMAC's object interface. - * - * @param {Hasher} hasher The hasher to use in this HMAC helper. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); - */ - _createHmacHelper: function (hasher) { - return function (message, key) { - return new C_algo.HMAC.init(hasher, key).finalize(message); - }; - } - }); - - /** - * Algorithm namespace. - */ - var C_algo = C.algo = {}; - - - - - // X-64 - // Shortcuts - var C_lib = C.lib; - var Base = C_lib.Base; - var X32WordArray = C_lib.WordArray; - - /** - * x64 namespace. - */ - var C_x64 = C.x64 = {}; - - /** - * A 64-bit word. - */ - var X64Word = C_x64.Word = Base.extend({ - /** - * Initializes a newly created 64-bit word. - * - * @param {number} high The high 32 bits. - * @param {number} low The low 32 bits. - * - * @example - * - * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); - */ - init: function (high, low) { - this.high = high; - this.low = low; - } - - /** - * Bitwise NOTs this word. - * - * @return {X64Word} A new x64-Word object after negating. - * - * @example - * - * var negated = x64Word.not(); - */ - // not: function () { - // var high = ~this.high; - // var low = ~this.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise ANDs this word with the passed word. - * - * @param {X64Word} word The x64-Word to AND with this word. - * - * @return {X64Word} A new x64-Word object after ANDing. - * - * @example - * - * var anded = x64Word.and(anotherX64Word); - */ - // and: function (word) { - // var high = this.high & word.high; - // var low = this.low & word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise ORs this word with the passed word. - * - * @param {X64Word} word The x64-Word to OR with this word. - * - * @return {X64Word} A new x64-Word object after ORing. - * - * @example - * - * var ored = x64Word.or(anotherX64Word); - */ - // or: function (word) { - // var high = this.high | word.high; - // var low = this.low | word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise XORs this word with the passed word. - * - * @param {X64Word} word The x64-Word to XOR with this word. - * - * @return {X64Word} A new x64-Word object after XORing. - * - * @example - * - * var xored = x64Word.xor(anotherX64Word); - */ - // xor: function (word) { - // var high = this.high ^ word.high; - // var low = this.low ^ word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Shifts this word n bits to the left. - * - * @param {number} n The number of bits to shift. - * - * @return {X64Word} A new x64-Word object after shifting. - * - * @example - * - * var shifted = x64Word.shiftL(25); - */ - // shiftL: function (n) { - // if (n < 32) { - // var high = (this.high << n) | (this.low >>> (32 - n)); - // var low = this.low << n; - // } else { - // var high = this.low << (n - 32); - // var low = 0; - // } - - // return X64Word.create(high, low); - // }, - - /** - * Shifts this word n bits to the right. - * - * @param {number} n The number of bits to shift. - * - * @return {X64Word} A new x64-Word object after shifting. - * - * @example - * - * var shifted = x64Word.shiftR(7); - */ - // shiftR: function (n) { - // if (n < 32) { - // var low = (this.low >>> n) | (this.high << (32 - n)); - // var high = this.high >>> n; - // } else { - // var low = this.high >>> (n - 32); - // var high = 0; - // } - - // return X64Word.create(high, low); - // }, - - /** - * Rotates this word n bits to the left. - * - * @param {number} n The number of bits to rotate. - * - * @return {X64Word} A new x64-Word object after rotating. - * - * @example - * - * var rotated = x64Word.rotL(25); - */ - // rotL: function (n) { - // return this.shiftL(n).or(this.shiftR(64 - n)); - // }, - - /** - * Rotates this word n bits to the right. - * - * @param {number} n The number of bits to rotate. - * - * @return {X64Word} A new x64-Word object after rotating. - * - * @example - * - * var rotated = x64Word.rotR(7); - */ - // rotR: function (n) { - // return this.shiftR(n).or(this.shiftL(64 - n)); - // }, - - /** - * Adds this word with the passed word. - * - * @param {X64Word} word The x64-Word to add with this word. - * - * @return {X64Word} A new x64-Word object after adding. - * - * @example - * - * var added = x64Word.add(anotherX64Word); - */ - // add: function (word) { - // var low = (this.low + word.low) | 0; - // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; - // var high = (this.high + word.high + carry) | 0; - - // return X64Word.create(high, low); - // } - }); - - /** - * An array of 64-bit words. - * - * @property {Array} words The array of CryptoJS.x64.Word objects. - * @property {number} sigBytes The number of significant bytes in this word array. - */ - var X64WordArray = C_x64.WordArray = Base.extend({ - /** - * Initializes a newly created word array. - * - * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. - * @param {number} sigBytes (Optional) The number of significant bytes in the words. - * - * @example - * - * var wordArray = CryptoJS.x64.WordArray.create(); - * - * var wordArray = CryptoJS.x64.WordArray.create([ - * CryptoJS.x64.Word.create(0x00010203, 0x04050607), - * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) - * ]); - * - * var wordArray = CryptoJS.x64.WordArray.create([ - * CryptoJS.x64.Word.create(0x00010203, 0x04050607), - * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) - * ], 10); - */ - init: function (words, sigBytes) { - words = this.words = words || []; - - if (sigBytes != undefined) { - this.sigBytes = sigBytes; - } else { - this.sigBytes = words.length * 8; - } - }, - - /** - * Converts this 64-bit word array to a 32-bit word array. - * - * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. - * - * @example - * - * var x32WordArray = x64WordArray.toX32(); - */ - toX32: function () { - // Shortcuts - var x64Words = this.words; - var x64WordsLength = x64Words.length; - - // Convert - var x32Words = []; - for (var i = 0; i < x64WordsLength; i++) { - var x64Word = x64Words[i]; - x32Words.push(x64Word.high); - x32Words.push(x64Word.low); - } - - return X32WordArray.create(x32Words, this.sigBytes); - }, - - /** - * Creates a copy of this word array. - * - * @return {X64WordArray} The clone. - * - * @example - * - * var clone = x64WordArray.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - - // Clone "words" array - var words = clone.words = this.words.slice(0); - - // Clone each X64Word object - var wordsLength = words.length; - for (var i = 0; i < wordsLength; i++) { - words[i] = words[i].clone(); - } - - return clone; - } - }); - - - // CIPHER - - // Shortcuts - var C_lib = C.lib; - var Base = C_lib.Base; - var WordArray = C_lib.WordArray; - var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; - var C_enc = C.enc; - var Utf8 = C_enc.Utf8; - var Base64 = C_enc.Base64; - var C_algo = C.algo; - var EvpKDF = C_algo.EvpKDF; - - /** - * Abstract base cipher template. - * - * @property {number} keySize This cipher's key size. Default: 4 (128 bits) - * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) - * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. - * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. - */ - var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ - /** - * Configuration options. - * - * @property {WordArray} iv The IV to use for this operation. - */ - cfg: Base.extend(), - - /** - * Creates this cipher in encryption mode. - * - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {Cipher} A cipher instance. - * - * @static - * - * @example - * - * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); - */ - createEncryptor: function (key, cfg) { - return this.create(this._ENC_XFORM_MODE, key, cfg); - }, - - /** - * Creates this cipher in decryption mode. - * - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {Cipher} A cipher instance. - * - * @static - * - * @example - * - * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); - */ - createDecryptor: function (key, cfg) { - return this.create(this._DEC_XFORM_MODE, key, cfg); - }, - - /** - * Initializes a newly created cipher. - * - * @param {number} xformMode Either the encryption or decryption transormation mode constant. - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @example - * - * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); - */ - init: function (xformMode, key, cfg) { - // Apply config defaults - this.cfg = this.cfg.extend(cfg); - - // Store transform mode and key - this._xformMode = xformMode; - this._key = key; - - // Set initial values - this.reset(); - }, - - /** - * Resets this cipher to its initial state. - * - * @example - * - * cipher.reset(); - */ - reset: function () { - // Reset data buffer - BufferedBlockAlgorithm.reset.call(this); - - // Perform concrete-cipher logic - this._doReset(); - }, - - /** - * Adds data to be encrypted or decrypted. - * - * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. - * - * @return {WordArray} The data after processing. - * - * @example - * - * var encrypted = cipher.process('data'); - * var encrypted = cipher.process(wordArray); - */ - process: function (dataUpdate) { - // Append - this._append(dataUpdate); - - // Process available blocks - return this._process(); - }, - - /** - * Finalizes the encryption or decryption process. - * Note that the finalize operation is effectively a destructive, read-once operation. - * - * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. - * - * @return {WordArray} The data after final processing. - * - * @example - * - * var encrypted = cipher.finalize(); - * var encrypted = cipher.finalize('data'); - * var encrypted = cipher.finalize(wordArray); - */ - finalize: function (dataUpdate) { - // Final data update - if (dataUpdate) { - this._append(dataUpdate); - } - - // Perform concrete-cipher logic - var finalProcessedData = this._doFinalize(); - - return finalProcessedData; - }, - - keySize: 128/32, - - ivSize: 128/32, - - _ENC_XFORM_MODE: 1, - - _DEC_XFORM_MODE: 2, - - /** - * Creates shortcut functions to a cipher's object interface. - * - * @param {Cipher} cipher The cipher to create a helper for. - * - * @return {Object} An object with encrypt and decrypt shortcut functions. - * - * @static - * - * @example - * - * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); - */ - _createHelper: (function () { - function selectCipherStrategy(key) { - if (typeof key == 'string') { - return PasswordBasedCipher; - } else { - return SerializableCipher; - } - } - - return function (cipher) { - return { - encrypt: function (message, key, cfg) { - return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); - }, - - decrypt: function (ciphertext, key, cfg) { - return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); - } - }; - }; - }()) - }); - - /** - * Abstract base stream cipher template. - * - * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) - */ - var StreamCipher = C_lib.StreamCipher = Cipher.extend({ - _doFinalize: function () { - // Process partial blocks - var finalProcessedBlocks = this._process(!!'flush'); - - return finalProcessedBlocks; - }, - - blockSize: 1 - }); - - /** - * Mode namespace. - */ - var C_mode = C.mode = {}; - - /** - * Abstract base block cipher mode template. - */ - var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ - /** - * Creates this mode for encryption. - * - * @param {Cipher} cipher A block cipher instance. - * @param {Array} iv The IV words. - * - * @static - * - * @example - * - * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); - */ - createEncryptor: function (cipher, iv) { - return this.Encryptor.create(cipher, iv); - }, - - /** - * Creates this mode for decryption. - * - * @param {Cipher} cipher A block cipher instance. - * @param {Array} iv The IV words. - * - * @static - * - * @example - * - * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); - */ - createDecryptor: function (cipher, iv) { - return this.Decryptor.create(cipher, iv); - }, - - /** - * Initializes a newly created mode. - * - * @param {Cipher} cipher A block cipher instance. - * @param {Array} iv The IV words. - * - * @example - * - * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); - */ - init: function (cipher, iv) { - this._cipher = cipher; - this._iv = iv; - } - }); - - /** - * Cipher Block Chaining mode. - */ - var CBC = C_mode.CBC = (function () { - /** - * Abstract base CBC mode. - */ - var CBC = BlockCipherMode.extend(); - - /** - * CBC encryptor. - */ - CBC.Encryptor = CBC.extend({ - /** - * Processes the data block at offset. - * - * @param {Array} words The data words to operate on. - * @param {number} offset The offset where the block starts. - * - * @example - * - * mode.processBlock(data.words, offset); - */ - processBlock: function (words, offset) { - // Shortcuts - var cipher = this._cipher; - var blockSize = cipher.blockSize; - - // XOR and encrypt - xorBlock.call(this, words, offset, blockSize); - cipher.encryptBlock(words, offset); - - // Remember this block to use with next block - this._prevBlock = words.slice(offset, offset + blockSize); - } - }); - - /** - * CBC decryptor. - */ - CBC.Decryptor = CBC.extend({ - /** - * Processes the data block at offset. - * - * @param {Array} words The data words to operate on. - * @param {number} offset The offset where the block starts. - * - * @example - * - * mode.processBlock(data.words, offset); - */ - processBlock: function (words, offset) { - // Shortcuts - var cipher = this._cipher; - var blockSize = cipher.blockSize; - - // Remember this block to use with next block - var thisBlock = words.slice(offset, offset + blockSize); - - // Decrypt and XOR - cipher.decryptBlock(words, offset); - xorBlock.call(this, words, offset, blockSize); - - // This block becomes the previous block - this._prevBlock = thisBlock; - } - }); - - function xorBlock(words, offset, blockSize) { - // Shortcut - var iv = this._iv; - - // Choose mixing block - if (iv) { - var block = iv; - - // Remove IV for subsequent blocks - this._iv = undefined; - } else { - var block = this._prevBlock; - } - - // XOR blocks - for (var i = 0; i < blockSize; i++) { - words[offset + i] ^= block[i]; - } - } - - return CBC; - }()); - - - /** - * Infinite Garble Extension mode. - */ - var IGE = C_mode.IGE = (function () { - /** - * Abstract base IGE mode. - */ - var IGE = BlockCipherMode.extend(); - - /** - * IGE encryptor. - */ - IGE.Encryptor = IGE.extend({ - /** - * Processes the data block at offset. - * - * @param {Array} words The data words to operate on. - * @param {number} offset The offset where the block starts. - * - * @example - * - * mode.processBlock(data.words, offset); - */ - processBlock: function (words, offset) { - // Shortcuts - var cipher = this._cipher; - var blockSize = cipher.blockSize; - - if (this._ivp === undefined) { - this._ivp = this._iv.slice(0, blockSize); - this._iv2p = this._iv.slice(blockSize, blockSize + blockSize); - } - - - // Remember this block to use with next block - var nextIv2p = words.slice(offset, offset + blockSize); - - // XOR with previous ciphertext - xorBlock(words, this._ivp, offset, blockSize); - - // Block cipher - cipher.encryptBlock(words, offset); - - // XOR with previous plaintext - xorBlock(words, this._iv2p, offset, blockSize); - - this._ivp = words.slice(offset, offset + blockSize); - this._iv2p = nextIv2p; - } - }); - - /** - * IGE decryptor. - */ - IGE.Decryptor = IGE.extend({ - /** - * Processes the data block at offset. - * - * @param {Array} words The data words to operate on. - * @param {number} offset The offset where the block starts. - * - * @example - * - * mode.processBlock(data.words, offset); - */ - processBlock: function (words, offset) { - // Shortcuts - var cipher = this._cipher; - var blockSize = cipher.blockSize; - - if (this._ivp === undefined) { - this._ivp = this._iv.slice(0, blockSize); - this._iv2p = this._iv.slice(blockSize, 2 * blockSize); - } - - // Remember this block to use with next block - var nextIvp = words.slice(offset, offset + blockSize); - - // XOR with previous ciphertext - xorBlock(words, this._iv2p, offset, blockSize); - - // Block cipher - cipher.decryptBlock(words, offset); - - // XOR with previous plaintext - xorBlock(words, this._ivp, offset, blockSize); - - this._ivp = nextIvp; - this._iv2p = words.slice(offset, offset + blockSize); - } - }); - - function xorBlock(words, block, offset, blockSize) { - for (var i = 0; i < blockSize; i++) { - words[offset + i] ^= block[i]; - } - } - - return IGE; - }()); - - /** - * Padding namespace. - */ - var C_pad = C.pad = {}; - - /** - * PKCS #5/7 padding strategy. - */ - var Pkcs7 = C_pad.Pkcs7 = { - /** - * Pads data using the algorithm defined in PKCS #5/7. - * - * @param {WordArray} data The data to pad. - * @param {number} blockSize The multiple that the data should be padded to. - * - * @static - * - * @example - * - * CryptoJS.pad.Pkcs7.pad(wordArray, 4); - */ - pad: function (data, blockSize) { - // Shortcut - var blockSizeBytes = blockSize * 4; - - // Count padding bytes - var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; - - // Create padding word - var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; - - // Create padding - var paddingWords = []; - for (var i = 0; i < nPaddingBytes; i += 4) { - paddingWords.push(paddingWord); - } - var padding = WordArray.create(paddingWords, nPaddingBytes); - - // Add padding - data.concat(padding); - }, - - /** - * Unpads data that had been padded using the algorithm defined in PKCS #5/7. - * - * @param {WordArray} data The data to unpad. - * - * @static - * - * @example - * - * CryptoJS.pad.Pkcs7.unpad(wordArray); - */ - unpad: function (data) { - // Get number of padding bytes from last byte - var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; - - // Remove padding - data.sigBytes -= nPaddingBytes; - } - }; - - var NoPadding = C_pad.NoPadding = { - pad: function () { - }, - - unpad: function () { - } - }; - - - /** - * Abstract base block cipher template. - * - * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) - */ - var BlockCipher = C_lib.BlockCipher = Cipher.extend({ - /** - * Configuration options. - * - * @property {Mode} mode The block mode to use. Default: CBC - * @property {Padding} padding The padding strategy to use. Default: Pkcs7 - */ - cfg: Cipher.cfg.extend({ - mode: CBC, - padding: Pkcs7 - }), - - reset: function () { - // Reset cipher - Cipher.reset.call(this); - - // Shortcuts - var cfg = this.cfg; - var iv = cfg.iv; - var mode = cfg.mode; - - // Reset block mode - if (this._xformMode == this._ENC_XFORM_MODE) { - var modeCreator = mode.createEncryptor; - } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { - var modeCreator = mode.createDecryptor; - - // Keep at least one block in the buffer for unpadding - this._minBufferSize = 1; - } - this._mode = modeCreator.call(mode, this, iv && iv.words); - }, - - _doProcessBlock: function (words, offset) { - this._mode.processBlock(words, offset); - }, - - _doFinalize: function () { - // Shortcut - var padding = this.cfg.padding; - - // Finalize - if (this._xformMode == this._ENC_XFORM_MODE) { - // Pad data - padding.pad(this._data, this.blockSize); - - // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); - } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { - // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); - - // Unpad data - padding.unpad(finalProcessedBlocks); - } - - return finalProcessedBlocks; - }, - - blockSize: 128/32 - }); - - /** - * A collection of cipher parameters. - * - * @property {WordArray} ciphertext The raw ciphertext. - * @property {WordArray} key The key to this ciphertext. - * @property {WordArray} iv The IV used in the ciphering operation. - * @property {WordArray} salt The salt used with a key derivation function. - * @property {Cipher} algorithm The cipher algorithm. - * @property {Mode} mode The block mode used in the ciphering operation. - * @property {Padding} padding The padding scheme used in the ciphering operation. - * @property {number} blockSize The block size of the cipher. - * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. - */ - var CipherParams = C_lib.CipherParams = Base.extend({ - /** - * Initializes a newly created cipher params object. - * - * @param {Object} cipherParams An object with any of the possible cipher parameters. - * - * @example - * - * var cipherParams = CryptoJS.lib.CipherParams.create({ - * ciphertext: ciphertextWordArray, - * key: keyWordArray, - * iv: ivWordArray, - * salt: saltWordArray, - * algorithm: CryptoJS.algo.AES, - * mode: CryptoJS.mode.CBC, - * padding: CryptoJS.pad.PKCS7, - * blockSize: 4, - * formatter: CryptoJS.format.OpenSSL - * }); - */ - init: function (cipherParams) { - this.mixIn(cipherParams); - }, - - /** - * Converts this cipher params object to a string. - * - * @param {Format} formatter (Optional) The formatting strategy to use. - * - * @return {string} The stringified cipher params. - * - * @throws Error If neither the formatter nor the default formatter is set. - * - * @example - * - * var string = cipherParams + ''; - * var string = cipherParams.toString(); - * var string = cipherParams.toString(CryptoJS.format.OpenSSL); - */ - toString: function (formatter) { - return (formatter || this.formatter).stringify(this); - } - }); - - /** - * Format namespace. - */ - var C_format = C.format = {}; - - /** - * OpenSSL formatting strategy. - */ - var OpenSSLFormatter = C_format.OpenSSL = { - /** - * Converts a cipher params object to an OpenSSL-compatible string. - * - * @param {CipherParams} cipherParams The cipher params object. - * - * @return {string} The OpenSSL-compatible string. - * - * @static - * - * @example - * - * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); - */ - stringify: function (cipherParams) { - // Shortcuts - var ciphertext = cipherParams.ciphertext; - var salt = cipherParams.salt; - - // Format - if (salt) { - var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); - } else { - var wordArray = ciphertext; - } - - return wordArray.toString(Base64); - }, - - /** - * Converts an OpenSSL-compatible string to a cipher params object. - * - * @param {string} openSSLStr The OpenSSL-compatible string. - * - * @return {CipherParams} The cipher params object. - * - * @static - * - * @example - * - * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); - */ - parse: function (openSSLStr) { - // Parse base64 - var ciphertext = Base64.parse(openSSLStr); - - // Shortcut - var ciphertextWords = ciphertext.words; - - // Test for salt - if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { - // Extract salt - var salt = WordArray.create(ciphertextWords.slice(2, 4)); - - // Remove salt from ciphertext - ciphertextWords.splice(0, 4); - ciphertext.sigBytes -= 16; - } - - return CipherParams.create({ ciphertext: ciphertext, salt: salt }); - } - }; - - /** - * A cipher wrapper that returns ciphertext as a serializable cipher params object. - */ - var SerializableCipher = C_lib.SerializableCipher = Base.extend({ - /** - * Configuration options. - * - * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL - */ - cfg: Base.extend({ - format: OpenSSLFormatter - }), - - /** - * Encrypts a message. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {WordArray|string} message The message to encrypt. - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {CipherParams} A cipher params object. - * - * @static - * - * @example - * - * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); - * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); - * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); - */ - encrypt: function (cipher, message, key, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); - - // Encrypt - var encryptor = cipher.createEncryptor(key, cfg); - var ciphertext = encryptor.finalize(message); - - // Shortcut - var cipherCfg = encryptor.cfg; - - // Create and return serializable cipher params - return CipherParams.create({ - ciphertext: ciphertext, - key: key, - iv: cipherCfg.iv, - algorithm: cipher, - mode: cipherCfg.mode, - padding: cipherCfg.padding, - blockSize: cipher.blockSize, - formatter: cfg.format - }); - }, - - /** - * Decrypts serialized ciphertext. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {CipherParams|string} ciphertext The ciphertext to decrypt. - * @param {WordArray} key The key. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {WordArray} The plaintext. - * - * @static - * - * @example - * - * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); - * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); - */ - decrypt: function (cipher, ciphertext, key, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); - - // Convert string to CipherParams - ciphertext = this._parse(ciphertext, cfg.format); - - // Decrypt - var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); - - return plaintext; - }, - - /** - * Converts serialized ciphertext to CipherParams, - * else assumed CipherParams already and returns ciphertext unchanged. - * - * @param {CipherParams|string} ciphertext The ciphertext. - * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. - * - * @return {CipherParams} The unserialized ciphertext. - * - * @static - * - * @example - * - * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); - */ - _parse: function (ciphertext, format) { - if (typeof ciphertext == 'string') { - return format.parse(ciphertext, this); - } else { - return ciphertext; - } - } - }); - - /** - * Key derivation function namespace. - */ - var C_kdf = C.kdf = {}; - - /** - * OpenSSL key derivation function. - */ - var OpenSSLKdf = C_kdf.OpenSSL = { - /** - * Derives a key and IV from a password. - * - * @param {string} password The password to derive from. - * @param {number} keySize The size in words of the key to generate. - * @param {number} ivSize The size in words of the IV to generate. - * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. - * - * @return {CipherParams} A cipher params object with the key, IV, and salt. - * - * @static - * - * @example - * - * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); - * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); - */ - execute: function (password, keySize, ivSize, salt) { - // Generate random salt - if (!salt) { - salt = WordArray.random(64/8); - } - - // Derive key and IV - var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); - - // Separate key and IV - var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); - key.sigBytes = keySize * 4; - - // Return params - return CipherParams.create({ key: key, iv: iv, salt: salt }); - } - }; - - /** - * A serializable cipher wrapper that derives the key from a password, - * and returns ciphertext as a serializable cipher params object. - */ - var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ - /** - * Configuration options. - * - * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL - */ - cfg: SerializableCipher.cfg.extend({ - kdf: OpenSSLKdf - }), - - /** - * Encrypts a message using a password. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {WordArray|string} message The message to encrypt. - * @param {string} password The password. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {CipherParams} A cipher params object. - * - * @static - * - * @example - * - * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); - * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); - */ - encrypt: function (cipher, message, password, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); - - // Derive key and other params - var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); - - // Add IV to config - cfg.iv = derivedParams.iv; - - // Encrypt - var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); - - // Mix in derived params - ciphertext.mixIn(derivedParams); - - return ciphertext; - }, - - /** - * Decrypts serialized ciphertext using a password. - * - * @param {Cipher} cipher The cipher algorithm to use. - * @param {CipherParams|string} ciphertext The ciphertext to decrypt. - * @param {string} password The password. - * @param {Object} cfg (Optional) The configuration options to use for this operation. - * - * @return {WordArray} The plaintext. - * - * @static - * - * @example - * - * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); - * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); - */ - decrypt: function (cipher, ciphertext, password, cfg) { - // Apply config defaults - cfg = this.cfg.extend(cfg); - - // Convert string to CipherParams - ciphertext = this._parse(ciphertext, cfg.format); - - // Derive key and other params - var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); - - // Add IV to config - cfg.iv = derivedParams.iv; - - // Decrypt - var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); - - return plaintext; - } - }); - - - - - - // AES - // Shortcuts - var C_lib = C.lib; - var BlockCipher = C_lib.BlockCipher; - var C_algo = C.algo; - - // Lookup tables - var SBOX = []; - var INV_SBOX = []; - var SUB_MIX_0 = []; - var SUB_MIX_1 = []; - var SUB_MIX_2 = []; - var SUB_MIX_3 = []; - var INV_SUB_MIX_0 = []; - var INV_SUB_MIX_1 = []; - var INV_SUB_MIX_2 = []; - var INV_SUB_MIX_3 = []; - - // Compute lookup tables - (function () { - // Compute double table - var d = []; - for (var i = 0; i < 256; i++) { - if (i < 128) { - d[i] = i << 1; - } else { - d[i] = (i << 1) ^ 0x11b; - } - } - - // Walk GF(2^8) - var x = 0; - var xi = 0; - for (var i = 0; i < 256; i++) { - // Compute sbox - var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); - sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; - SBOX[x] = sx; - INV_SBOX[sx] = x; - - // Compute multiplication - var x2 = d[x]; - var x4 = d[x2]; - var x8 = d[x4]; - - // Compute sub bytes, mix columns tables - var t = (d[sx] * 0x101) ^ (sx * 0x1010100); - SUB_MIX_0[x] = (t << 24) | (t >>> 8); - SUB_MIX_1[x] = (t << 16) | (t >>> 16); - SUB_MIX_2[x] = (t << 8) | (t >>> 24); - SUB_MIX_3[x] = t; - - // Compute inv sub bytes, inv mix columns tables - var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); - INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); - INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); - INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); - INV_SUB_MIX_3[sx] = t; - - // Compute next counter - if (!x) { - x = xi = 1; - } else { - x = x2 ^ d[d[d[x8 ^ x2]]]; - xi ^= d[d[xi]]; - } - } - }()); - - // Precomputed Rcon lookup - var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; - - /** - * AES block cipher algorithm. - */ - var AES = C_algo.AES = BlockCipher.extend({ - _doReset: function () { - // Shortcuts - var key = this._key; - var keyWords = key.words; - var keySize = key.sigBytes / 4; - - // Compute number of rounds - var nRounds = this._nRounds = keySize + 6 - - // Compute number of key schedule rows - var ksRows = (nRounds + 1) * 4; - - // Compute key schedule - var keySchedule = this._keySchedule = []; - for (var ksRow = 0; ksRow < ksRows; ksRow++) { - if (ksRow < keySize) { - keySchedule[ksRow] = keyWords[ksRow]; - } else { - var t = keySchedule[ksRow - 1]; - - if (!(ksRow % keySize)) { - // Rot word - t = (t << 8) | (t >>> 24); - - // Sub word - t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; - - // Mix Rcon - t ^= RCON[(ksRow / keySize) | 0] << 24; - } else if (keySize > 6 && ksRow % keySize == 4) { - // Sub word - t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; - } - - keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; - } - } - - // Compute inv key schedule - var invKeySchedule = this._invKeySchedule = []; - for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) { - var ksRow = ksRows - invKsRow; - - if (invKsRow % 4) { - var t = keySchedule[ksRow]; - } else { - var t = keySchedule[ksRow - 4]; - } - - if (invKsRow < 4 || ksRow <= 4) { - invKeySchedule[invKsRow] = t; - } else { - invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ - INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; - } - } - }, - - encryptBlock: function (M, offset) { - this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); - }, - - decryptBlock: function (M, offset) { - // Swap 2nd and 4th rows - var t = M[offset + 1]; - M[offset + 1] = M[offset + 3]; - M[offset + 3] = t; - - this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); - - // Inv swap 2nd and 4th rows - var t = M[offset + 1]; - M[offset + 1] = M[offset + 3]; - M[offset + 3] = t; - }, - - _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { - // Shortcut - var nRounds = this._nRounds; - - // Get input, add round key - var s0 = M[offset] ^ keySchedule[0]; - var s1 = M[offset + 1] ^ keySchedule[1]; - var s2 = M[offset + 2] ^ keySchedule[2]; - var s3 = M[offset + 3] ^ keySchedule[3]; - - // Key schedule row counter - var ksRow = 4; - - // Rounds - for (var round = 1; round < nRounds; round++) { - // Shift rows, sub bytes, mix columns, add round key - var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; - var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; - var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; - var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; - - // Update state - s0 = t0; - s1 = t1; - s2 = t2; - s3 = t3; - } - - // Shift rows, sub bytes, add round key - var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; - var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; - var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; - var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; - - // Set output - M[offset] = t0; - M[offset + 1] = t1; - M[offset + 2] = t2; - M[offset + 3] = t3; - }, - - keySize: 256/32 - }); - - /** - * Shortcut functions to the cipher's object interface. - * - * @example - * - * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); - * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); - */ - C.AES = BlockCipher._createHelper(AES); - - return C; -}(Math)); - -module.exports = CryptoJS; diff --git a/src/lib/crypto/crypto_utils.ts b/src/lib/crypto/crypto_utils.ts index 80aad7f9..955d9991 100644 --- a/src/lib/crypto/crypto_utils.ts +++ b/src/lib/crypto/crypto_utils.ts @@ -1,5 +1,6 @@ import sha1 from '@cryptography/sha1'; import sha256 from '@cryptography/sha256'; +import {IGE} from '@cryptography/aes'; import {str2bigInt, bpe, equalsInt, greater, copy_, eGCD_, add_, rightShift_, sub_, copyInt_, isZero, @@ -9,43 +10,13 @@ import {str2bigInt, bpe, equalsInt, greater, // @ts-ignore import {BigInteger} from 'jsbn'; -import CryptoJS from './crypto.js'; -import { addPadding, bytesToHex, bytesFromHex, nextRandomInt, bytesFromBigInt, dT, bytesFromWords } from '../bin_utils'; +import { addPadding, bytesToHex, bytesFromHex, nextRandomInt, bytesFromBigInt, dT, bytesFromWords, bytesToWordss, bytesFromWordss } from '../bin_utils'; export function bytesFromLeemonBigInt(bigInt: BigInteger) { var str = bigInt2str(bigInt, 16); return bytesFromHex(str); } -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 bytesToWords(bytes: any) { - if(bytes instanceof ArrayBuffer) { - bytes = new Uint8Array(bytes); - } - var len = bytes.length; - var words: any = []; - var i; - for(i = 0; i < len; i++) { - words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8); - } - - return new CryptoJS.lib.WordArray.init(words, len); -} - export function sha1HashSync(bytes: number[] | ArrayBuffer | Uint8Array) { //console.trace(dT(), 'SHA-1 hash start', bytes); @@ -68,54 +39,35 @@ export function sha256HashSync(bytes: Uint8Array | ArrayBuffer) { let words = bytesToWordss(bytes); let hash = sha256(words); - // bytesFromWords below - var o = []; - for(var i = 0; i < hash.length * 4; i++) { - o.push((hash[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff); - } - //console.log(dT(), 'SHA-256 hash finish'); - return o; + return bytesFromWordss(hash); } -export function aesEncryptSync(bytes: any, keyBytes: any, ivBytes: any) { - // console.log(dT(), 'AES encrypt start', len/*, bytesToHex(keyBytes), bytesToHex(ivBytes)*/) +export function aesEncryptSync(bytes: ArrayBuffer, keyBytes: ArrayBuffer, ivBytes: ArrayBuffer) { + //console.log(dT(), 'AES encrypt start', bytes, keyBytes, ivBytes); // console.log('aes before padding bytes:', bytesToHex(bytes)); bytes = addPadding(bytes); // console.log('aes after padding bytes:', bytesToHex(bytes)); - let mode = CryptoJS.mode.IGE; + const cipher = new IGE(bytesToWordss(keyBytes), bytesToWordss(ivBytes)); + const encryptedBytes = cipher.encrypt(bytesToWordss(bytes)); + //console.log(dT(), 'AES encrypt finish'); - let encryptedWords = CryptoJS.AES.encrypt(bytesToWords(bytes), bytesToWords(keyBytes), { - iv: bytesToWords(ivBytes), - padding: CryptoJS.pad.NoPadding, - mode//: CryptoJS.mode.IGE - }).ciphertext; - - let encryptedBytes = bytesFromWords(encryptedWords); - // console.log(dT(), 'AES encrypt finish') - - return encryptedBytes; + return bytesFromWordss(encryptedBytes); } -export function aesDecryptSync(encryptedBytes: any, keyBytes: any, ivBytes: any) { +export function aesDecryptSync(bytes: Uint8Array, keyBytes: Uint8Array, ivBytes: Uint8Array) { + //console.log(dT(), 'AES decrypt start', bytes, keyBytes, ivBytes); - let mode = CryptoJS.mode.IGE; - // console.log(dT(), 'AES decrypt start', encryptedBytes.length) - var decryptedWords = CryptoJS.AES.decrypt({ciphertext: bytesToWords(encryptedBytes)}, bytesToWords(keyBytes), { - iv: bytesToWords(ivBytes), - padding: CryptoJS.pad.NoPadding, - mode//: CryptoJS.mode.IGE - }); + const cipher = new IGE(bytesToWordss(keyBytes), bytesToWordss(ivBytes)); + const decryptedBytes = cipher.decrypt(bytesToWordss(bytes)); - var bytes = bytesFromWords(decryptedWords); - // console.log(dT(), 'AES decrypt finish') + //console.log(dT(), 'AES decrypt finish'); - return bytes; + return bytesFromWordss(decryptedBytes); } - export function rsaEncrypt(publicKey: {modulus: string, exponent: string}, bytes: any): number[] { console.log(dT(), 'RSA encrypt start', publicKey, bytes); diff --git a/src/lib/crypto/cryptoworker.ts b/src/lib/crypto/cryptoworker.ts index 88b5973c..98be5054 100644 --- a/src/lib/crypto/cryptoworker.ts +++ b/src/lib/crypto/cryptoworker.ts @@ -88,36 +88,26 @@ class CryptoWorker { } public sha1Hash(bytes: number[] | ArrayBuffer | Uint8Array): Promise { - //if(this.webWorker) { - return this.performTaskWorker('sha1-hash', bytes); - //} + return this.performTaskWorker('sha1-hash', bytes); } public sha256Hash(bytes: any) { - //if(this.webWorker) { - return this.performTaskWorker('sha256-hash', bytes); - //} + return this.performTaskWorker('sha256-hash', bytes); } public pbkdf2(buffer: Uint8Array, salt: Uint8Array, iterations: number) { - //if(this.webWorker) { - return this.performTaskWorker('pbkdf2', buffer, salt, iterations); - //} + return this.performTaskWorker('pbkdf2', buffer, salt, iterations); } public aesEncrypt(bytes: any, keyBytes: any, ivBytes: any) { - //if(this.webWorker) { - return this.performTaskWorker('aes-encrypt', convertToArrayBuffer(bytes), - convertToArrayBuffer(keyBytes), convertToArrayBuffer(ivBytes)); - //} + return this.performTaskWorker('aes-encrypt', convertToArrayBuffer(bytes), + convertToArrayBuffer(keyBytes), convertToArrayBuffer(ivBytes)); } public aesDecrypt(encryptedBytes: any, keyBytes: any, ivBytes: any): Promise { - //if(this.webWorker) { - return this.performTaskWorker('aes-decrypt', - encryptedBytes, keyBytes, ivBytes) - .then(bytes => convertToArrayBuffer(bytes)); - //} + return this.performTaskWorker('aes-decrypt', + encryptedBytes, keyBytes, ivBytes) + .then(bytes => convertToArrayBuffer(bytes)); } public rsaEncrypt(publicKey: {modulus: string, exponent: string}, bytes: any): Promise { @@ -127,21 +117,15 @@ class CryptoWorker { public factorize(bytes: any) { bytes = convertToByteArray(bytes); - //if(this.webWorker) { - return this.performTaskWorker<[number[], number[], number]>('factorize', bytes); - //} + return this.performTaskWorker<[number[], number[], number]>('factorize', bytes); } public modPow(x: any, y: any, m: any) { - //if(this.webWorker) { - return this.performTaskWorker('mod-pow', x, y, m); - //} + return this.performTaskWorker('mod-pow', x, y, m); } public gzipUncompress(bytes: ArrayBuffer, toString?: boolean) { - //if(this.webWorker) { - return this.performTaskWorker('unzip', bytes, toString); - //} + return this.performTaskWorker('unzip', bytes, toString); } } diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index 84cf4070..67952d0f 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -78,14 +78,16 @@ export class ApiManager { AppStorage.remove('dc', 'user_auth', 'stickerSets'); this.baseDcID = 0; this.telegramMeNotify(false); - return this.mtpClearStorage(); + this.mtpClearStorage(); }, (error) => { storageKeys.push('dc', 'user_auth', 'stickerSets'); AppStorage.remove(storageKeys); this.baseDcID = 0; error.handled = true; this.telegramMeNotify(false); - return this.mtpClearStorage(); + this.mtpClearStorage(); + }).then(() => { + location.pathname = '/'; }); } @@ -224,17 +226,7 @@ export class ApiManager { setTimeout(() => { if(!error.handled) { if(error.code == 401) { - // @ts-ignore WARNING! - this.logOut().finally(() => { - if(location.protocol == 'http:' && - !Config.Modes.http && - Config.App.domains.indexOf(location.hostname) != -1) { - location.href = location.href.replace(/^http:/, 'https:'); - } else { - location.hash = '/login'; - // AppRuntimeManager.reload(); // WARNING - } - }) + this.logOut(); } else { // ErrorService.show({error: error}); // WARNING } diff --git a/src/lib/mtproto/transports/abridged.ts b/src/lib/mtproto/transports/abridged.ts index a11057de..70776bb1 100644 --- a/src/lib/mtproto/transports/abridged.ts +++ b/src/lib/mtproto/transports/abridged.ts @@ -1,6 +1,7 @@ -import { bytesFromHex, addPadding } from "../../bin_utils"; +//import { bytesFromHex, addPadding } from "../../bin_utils"; +import { Codec } from "./codec"; -class AbridgedPacketCodec { +class AbridgedPacketCodec implements Codec { public tag = 0xef; public obfuscateTag = new Uint8Array([this.tag, this.tag, this.tag, this.tag]); @@ -9,12 +10,14 @@ class AbridgedPacketCodec { let header: Uint8Array; if(len < 127) { header = new Uint8Array([len]); - } else { - header = new Uint8Array([0x7f, ...addPadding(bytesFromHex(len.toString(16)).reverse(), 3, true)/* .reverse() */]); + } else { // Length: payload length, divided by four, and encoded as 3 length bytes (little endian) + //header = new Uint8Array([0x7f, ...addPadding(bytesFromHex(len.toString(16)).reverse(), 3, true)/* .reverse() */]); + header = new Uint8Array([0x7f, len & 0xFF, (len >> 8) & 0xFF, (len >> 16) & 0xFF]); //console.log('got nobody cause im braindead', header, len); } - return new Uint8Array([...header, ...data]); + return header.concat(data); + //return new Uint8Array([...header, ...data]); } public readPacket(data: Uint8Array) { diff --git a/src/lib/mtproto/transports/codec.ts b/src/lib/mtproto/transports/codec.ts index 9a817bcf..13fc0141 100644 --- a/src/lib/mtproto/transports/codec.ts +++ b/src/lib/mtproto/transports/codec.ts @@ -1,6 +1,6 @@ export interface Codec { - tag?: number; - obfuscateTag?: Uint8Array; + tag: number; + obfuscateTag: Uint8Array; encodePacket: (data: Uint8Array) => Uint8Array; readPacket: (data: Uint8Array) => Uint8Array; diff --git a/src/lib/mtproto/transports/intermediate.ts b/src/lib/mtproto/transports/intermediate.ts new file mode 100644 index 00000000..a4252295 --- /dev/null +++ b/src/lib/mtproto/transports/intermediate.ts @@ -0,0 +1,49 @@ +import { nextRandomInt } from "../../bin_utils"; +import { Codec } from "./codec"; + +class IntermediatePacketCodec implements Codec { + public tag = 0xee; + public obfuscateTag = new Uint8Array([this.tag, this.tag, this.tag, this.tag]); + + public encodePacket(data: Uint8Array) { + let len = data.byteLength; + let header = new Uint8Array(new Uint32Array([len]).buffer); + + return header.concat(data); + } + + public readPacket(data: Uint8Array) { + let length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + + return data.slice(4, 4 + length); + } +} + +/* Data packets are aligned to 4bytes. This codec adds random bytes of size + from 0 to 3 bytes, which are ignored by decoder. */ +class PaddedIntermediatePacketCodec extends IntermediatePacketCodec { + public tag = 0xdd; + public obfuscateTag = new Uint8Array([this.tag, this.tag, this.tag, this.tag]); + + public encodePacket(data: Uint8Array) { + let padding = new Uint8Array(nextRandomInt(3)).randomize(); + let len = data.byteLength + padding.byteLength; + + let header = new Uint8Array(new Uint32Array([len]).buffer); + console.log('encodePacket', padding, len, data, header); + + return header.concat(data, padding); + } + + public readPacket(data: Uint8Array) { + let padLength = data.byteLength % 4; + if(padLength > 0) { + return data.slice(4, -padLength); + } + + return data.slice(4); + } +} + +export default new IntermediatePacketCodec(); +//export default new PaddedIntermediatePacketCodec(); diff --git a/src/lib/mtproto/transports/websocket.ts b/src/lib/mtproto/transports/websocket.ts index 3e57a15d..b1f8f731 100644 --- a/src/lib/mtproto/transports/websocket.ts +++ b/src/lib/mtproto/transports/websocket.ts @@ -1,15 +1,25 @@ import MTTransport from './transport'; -import aesjs from 'aes-js'; -import abridgetPacketCodec from './abridged'; +//import aesjs from 'aes-js'; +import {CTR} from '@cryptography/aes'; +//import abridgetPacketCodec from './abridged'; +import intermediatePacketCodec from './intermediate'; import {MTPNetworker} from '../networker'; import { logger } from '../../polyfill'; +import { bytesFromWordss } from '../../bin_utils'; +import { Codec } from './codec'; +/* +@cryptography/aes не работает с массивами которые не кратны 4, поэтому использую intermediate а не abridged +*/ export class Obfuscation { - public enc: aesjs.ModeOfOperation.ModeOfOperationCTR; - public dec: aesjs.ModeOfOperation.ModeOfOperationCTR; + /* public enc: aesjs.ModeOfOperation.ModeOfOperationCTR; + public dec: aesjs.ModeOfOperation.ModeOfOperationCTR; */ - public init() { + public encNew: CTR; + public decNew: CTR; + + public init(codec: Codec) { const initPayload = new Uint8Array(64); initPayload.randomize(); @@ -22,6 +32,7 @@ export class Obfuscation { val != 0x20544547 && val != 0x4954504f && val != 0xeeeeeeee && + val != 0xdddddddd && val2 != 0x00000000) { //initPayload[56] = initPayload[57] = initPayload[58] = initPayload[59] = transport; break; @@ -38,10 +49,13 @@ export class Obfuscation { let decKey = reversedPayload.slice(8, 40); let decIv = reversedPayload.slice(40, 56); - this.enc = new aesjs.ModeOfOperation.ctr(encKey, new aesjs.Counter(encIv as any)); - this.dec = new aesjs.ModeOfOperation.ctr(decKey, new aesjs.Counter(decIv as any)); + /* this.enc = new aesjs.ModeOfOperation.ctr(encKey, new aesjs.Counter(encIv as any)); + this.dec = new aesjs.ModeOfOperation.ctr(decKey, new aesjs.Counter(decIv as any)); */ + + this.encNew = new CTR(encKey, encIv); + this.decNew = new CTR(decKey, decIv); - initPayload.set(abridgetPacketCodec.obfuscateTag, 56); + initPayload.set(intermediatePacketCodec.obfuscateTag, 56); const encrypted = this.encode(initPayload); initPayload.set(encrypted.slice(56, 64), 56); @@ -49,12 +63,47 @@ export class Obfuscation { return initPayload; } + /* public encode(payload: Uint8Array) { + let res = this.enc.encrypt(payload); + + try { + let arr = this.encNew.encrypt(payload); + //let resNew = bytesFromWords({words: arr, sigBytes: arr.length}); + let resNew = new Uint8Array(bytesFromWordss(arr)); + console.log('Obfuscation: encode comparison:', res, arr, resNew, res.hex == resNew.hex); + } catch(err) { + console.error('Obfuscation: error:', err); + } + + return res; + } + + public decode(payload: Uint8Array) { + let res = this.dec.encrypt(payload); + + try { + let arr = this.decNew.decrypt(payload); + //let resNew = bytesFromWords({words: arr, sigBytes: arr.length}); + let resNew = new Uint8Array(bytesFromWordss(arr)); + console.log('Obfuscation: decode comparison:', res, arr, resNew, res.hex == resNew.hex); + } catch(err) { + console.error('Obfuscation: error:', err); + } + + return res; + } */ public encode(payload: Uint8Array) { - return this.enc.encrypt(payload); + let res = this.encNew.encrypt(payload); + let bytes = new Uint8Array(bytesFromWordss(res)); + + return bytes; } - public decode(data: Uint8Array) { - return this.dec.encrypt(data); + public decode(payload: Uint8Array) { + let res = this.decNew.decrypt(payload); + let bytes = new Uint8Array(bytesFromWordss(res)); + + return bytes; } } @@ -75,6 +124,8 @@ export default class Socket extends MTTransport { debug = false; + codec = intermediatePacketCodec; + constructor(dcID: number, url: string) { super(dcID, url); @@ -103,7 +154,7 @@ export default class Socket extends MTTransport { handleOpen = () => { this.log('opened'); - this.ws.send(this.obfuscation.init()); + this.ws.send(this.obfuscation.init(this.codec)); this.connected = true; this.releasePending(); @@ -126,7 +177,7 @@ export default class Socket extends MTTransport { this.debug && this.log('<-', 'handleMessage', event); let data = this.obfuscation.decode(new Uint8Array(event.data)); - data = abridgetPacketCodec.readPacket(data); + data = this.codec.readPacket(data); if(this.networker) { // authenticated! //this.pending = this.pending.filter(p => p.body); // clear pending @@ -175,7 +226,7 @@ export default class Socket extends MTTransport { let pending = this.pending[i]; let {body} = pending; if(body) { - let toEncode = abridgetPacketCodec.encodePacket(body); + let toEncode = this.codec.encodePacket(body); //console.log('send before obf:', /* body.hex, nonce.hex, */ toEncode.hex); let enc = this.obfuscation.encode(toEncode); diff --git a/src/lib/polyfill.ts b/src/lib/polyfill.ts index 712a20fd..88bd2c7f 100644 --- a/src/lib/polyfill.ts +++ b/src/lib/polyfill.ts @@ -80,6 +80,10 @@ Uint8Array.prototype.concat = function(...args: Array(callback: (value: T, index?: number, array?: Array) => void) { let length = this.length; for(var i = length - 1; i >= 0; --i) { @@ -108,7 +112,8 @@ declare global { interface Uint8Array { hex: string; randomize: () => Uint8Array, - concat: (...args: Array) => Uint8Array + concat: (...args: Array) => Uint8Array, + toString: () => string } interface Array { diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index b0582e8e..988e86be 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -1,3 +1,5 @@ +$chat-max-width: 696px; + .chat-container { display: flex; // padding: 200px; @@ -57,7 +59,7 @@ display: flex; align-items: center; box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); - padding: .5rem 1rem; + padding: .5rem 17px; flex: 0 0 auto; /* Forces side columns to stay same width */ min-height: 60px; max-height: 60px; @@ -71,8 +73,9 @@ } .content { - padding-left: 1rem; flex: 1; + padding-left: 17px; + line-height: 1.6; } .person { @@ -93,7 +96,7 @@ .bottom { font-size: 14px; line-height: 18px; - color: $placeholder-color; + color: #707579; .online { color: $darkblue; @@ -220,7 +223,7 @@ .bubble { padding-top: 5px; display: grid; - grid-template-columns: 1fr 700px 1fr; + grid-template-columns: 1fr $chat-max-width 1fr; grid-row-gap: 0px; &:before, &:after { @@ -1069,9 +1072,9 @@ display: flex; align-items: center; width: 100%; - max-width: 700px; + max-width: $chat-max-width; padding-top: .35rem; - padding-bottom: 1rem; + padding-bottom: 21px; justify-content: space-between; flex: 0 0 auto; /* Forces side columns to stay same width */ position: relative; @@ -1080,8 +1083,8 @@ background: none; border: none; width: 100%; - padding: .5rem .5rem; - font-size: .95rem; + font-size: 16px; + padding: 10px 9px; /* height: 100%; */ max-height: 30rem; overflow-y: none; @@ -1093,7 +1096,7 @@ [contenteditable=true]:empty:before { content: attr(data-placeholder); - color: #9e9e9e; + color: #a2acb4; display: block; /* For Firefox By Ariel Flesler */ } @@ -1101,8 +1104,8 @@ flex: 0 0 auto; font-size: 1.5rem; line-height: 1.5rem; - height: 3.25rem; - width: 3.25rem; + height: 54px; + width: 54px; color: #9e9e9e; background-color: #fff; align-self: flex-end; @@ -1130,7 +1133,7 @@ margin-right: 9px; padding: 4.5px .5rem; /* padding: 3px .5rem 6px .5rem; */ - min-height: 3.25rem; + min-height: 54px; max-height: 30rem; caret-color: $button-primary-background; flex: 1; @@ -1204,11 +1207,13 @@ .btn-icon { display: block; - color: $placeholder-color; - font-size: 1.5rem; - line-height: 1.5rem; transition: .2s color; flex: 0 0 auto; + + font-size: 24px; + line-height: 24px; + padding: 10px 7px 9px 7.5px; + color: #8d969c; &.active { color: $blue; diff --git a/src/scss/partials/_chatlist.scss b/src/scss/partials/_chatlist.scss index fc5dcc12..67e9b400 100644 --- a/src/scss/partials/_chatlist.scss +++ b/src/scss/partials/_chatlist.scss @@ -2,18 +2,19 @@ .input-search { position: relative; width: 100%; - margin-left: 1rem; + margin-left: 22px; input { background-color: rgba(112, 117, 121, .08); border: 2px solid transparent; - height: 3rem; + height: 44px; border-radius: 22px; box-sizing: border-box; - padding: 0 1.5rem 0 3rem; + padding: 0px 1.5rem 0 40px; -webkit-transition: all .15s ease-out; transition: all .15s ease-out; width: 100%; + font-size: 16px; &:focus { background-color: rgba(112, 117, 121, 0); @@ -28,15 +29,19 @@ .tgico { position: absolute; - left: 1rem; + left: 12px; top: 50%; transform: translateY(-50%); text-align: center; - font-size: 1.65rem; + font-size: 24px; color: $color-gray; opacity: .6; -webkit-transition: all .15s ease-out; transition: all .15s ease-out; + + &:before { + vertical-align: middle; + } } } @@ -69,8 +74,8 @@ flex-direction: row; position: relative; cursor: pointer; - padding: 8px 8.5px; - margin: 0 8.5px 0 8px; + padding: 7px 8.5px; + margin: 0px 8px 2px 7px; overflow: hidden; &:hover { @@ -84,7 +89,7 @@ .pinned-delimiter { display: flex; - padding: 8px 0 4px; + padding: 6px 0 6px; span { margin: 0; @@ -111,7 +116,9 @@ /* span:not(.tgico-pinnedchat):not(.emoji):last-child { */ .user-title + span { /* font-size: .9rem; */ - font-size: .8rem; + //font-size: .8rem; + font-size: .75rem; + padding: 2px 0px 0px 0px; } .user-last-message + span:not(.tgico-pinnedchat) { @@ -143,7 +150,7 @@ overflow: hidden; color: $color-gray; flex: 1 1 auto; - padding-right: 6.5px; + padding-right: 3.5px; padding-left: 10px; } @@ -209,6 +216,7 @@ color: #fff; border-radius: 12px; margin-top: 1.5px; + margin-right: -2px; } .unread, .unread-muted { diff --git a/src/scss/partials/_emojiDropdown.scss b/src/scss/partials/_emojiDropdown.scss index 12ea4fe0..0bc430a2 100644 --- a/src/scss/partials/_emojiDropdown.scss +++ b/src/scss/partials/_emojiDropdown.scss @@ -8,7 +8,7 @@ height: 420px; background: #fff; box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, 0.14); - border-radius: 12px; + border-radius: 10px; z-index: 2; /* display: none; */ display: flex; @@ -25,7 +25,14 @@ } > .menu-horizontal { - padding: 0 3rem; + padding: 0px 58px 0px 58px; + font-weight: 500; + margin-top: 2px; + + > li.active:after { + left: 29px; + right: 28px; + } } .emoji-container { @@ -34,6 +41,10 @@ overflow: hidden; height: 100%; } + + .btn-icon { + color: #8d969c; + } .tabs-container { /* width: 300%; */ @@ -42,19 +53,27 @@ .emoji-category { font-size: 2.25rem; line-height: 2.25rem; - margin-top: 1px; + padding-top: 1px; + + display: grid; + grid-column-gap: 2.44px; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; + + &:first-child { + padding-top: 5px; + } > * { margin: 0; - padding: 5px 5px; + padding: 4px 4px; line-height: inherit; border-radius: 8px; cursor: pointer; user-select: none; -webkit-user-select: none; - width: 44px; - height: 44px; + width: 42px; + height: 42px; .emoji { width: 100%; @@ -72,7 +91,7 @@ } */ } - .emoji-category, .sticker-category { + .sticker-category { display: flex; align-items: center; justify-content: space-between; @@ -104,6 +123,7 @@ padding: 1px 2.5px; justify-content: center; border-radius: 12px; + padding: 0; &:hover { background-color: rgba(112, 117, 121, 0.08); @@ -129,7 +149,7 @@ > div:first-of-type { flex: 1; padding: 0; - padding-top: 10px; + //padding-top: 10px; } } @@ -146,9 +166,9 @@ .emoji-padding, .stickers-padding { .menu-horizontal { - height: 50px; + height: 47px; border-bottom: none; - padding: 0; + padding: 2px 2px 2px 2px; width: 100%; li { @@ -168,9 +188,11 @@ } } - /* #content-stickers { - padding: 0; - } */ + #content-stickers { + .scrollable { + padding: 15px 5px 0; + } + } .emoji-padding, .stickers-padding { .menu-horizontal > li { diff --git a/src/scss/partials/_sidebar.scss b/src/scss/partials/_sidebar.scss index 757da4ea..4e9431da 100644 --- a/src/scss/partials/_sidebar.scss +++ b/src/scss/partials/_sidebar.scss @@ -15,7 +15,7 @@ display: flex; align-items: center; justify-content: space-between; - padding: .5rem 1.25rem; + padding: 7.5px 20px 7.5px 15px; min-height: 60px; .sidebar-title { diff --git a/src/scss/style.scss b/src/scss/style.scss index da45de98..d935cbeb 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -48,7 +48,7 @@ html, body { } html { - font-size: 15px; + font-size: $text-size; } a { @@ -83,8 +83,8 @@ h1, h2, h3, h4, h5, h6 { } h4 { - font-size: 2.28rem; - margin: 1.52rem 0 .912rem 0; + font-size: 2rem; + margin: 1.5rem 0 1rem 0; line-height: 110%; } @@ -94,7 +94,6 @@ input { .subtitle { /* font-weight: 500; */ - font-size: 1rem; color: $placeholder-color; line-height: 1.25; } @@ -103,7 +102,8 @@ input { .page-authCode .input-wrapper, .page-signUp .input-wrapper, .page-password .input-wrapper { - margin-top: 3rem; + /* margin-top: 3rem; */ + margin-top: 50px; } .page-authCode { @@ -281,7 +281,7 @@ input { &[class*=" tgico-"] { line-height: 52px; - font-size: 1.5rem; + font-size: 28px; } path { @@ -496,6 +496,14 @@ input { } } +.page-sign { + .auth-image { + width: 160px; + height: 160px; + margin-bottom: 45px; + } +} + .page-signUp { .auth-image { border-radius: 50%; @@ -524,7 +532,7 @@ input { } .input-wrapper { - width: 350px; + width: 360px; margin: 0 auto; } @@ -536,7 +544,7 @@ input { content: " "; top: 50%; bottom: 0; - right: 15px; + right: 21px; cursor: pointer; height: 0; @@ -546,12 +554,12 @@ input { border-radius: 1px; border-width: 0 2px 2px 0; display: inline-block; - padding: 4px; + padding: 5px; vertical-align: middle; z-index: 2; - margin-top: -7px; + margin-top: -9px; transform: rotate(45deg); -webkit-transform: rotate(45deg); transition: .2s all; @@ -560,13 +568,12 @@ input { label { position: absolute; color: $placeholder-color; - left: 12.5px; + left: 1rem; right: auto; z-index: 2; top: 50%; transform: translateY(-50%); background-color: #fff; - font-size: 0.85rem; transition: .2s all, .1s opacity; display: inline-block; cursor: text; @@ -574,12 +581,11 @@ input { input { border: 1px solid #DADCE0; - border-radius: $border-radius; - padding: 0 12.5px; + border-radius: $border-radius-big; + padding: 0 1rem; box-sizing: border-box; - font-size: 0.85rem; width: 100%; - height: 45px; + height: 54px; transition: .2s border-color; position: relative; z-index: 1; @@ -587,8 +593,8 @@ input { &:focus { border-color: $button-primary-background; - border-width: 1.5px; - padding: 0 12px; + border-width: 2px; + padding: 0 calc(1rem - 1px); } &:disabled { @@ -606,7 +612,7 @@ input { } &:focus ~ .arrow-down { - margin-top: -2px; + margin-top: -4px; transform: rotate(225deg); -webkit-transform: rotate(225deg); border-color: $button-primary-background; @@ -617,21 +623,21 @@ input { } &:focus + label, &:valid + label, &:disabled + label { - top: -8.5px; + top: -.5rem; transform: none; padding: 0 5px; - left: 7.5px; - font-size: 0.85rem!important; + left: .75rem; + font-size: 0.75rem!important; opacity: 1; } } } .checkbox-field { - margin: 1rem 0; + margin: 1.25rem 0; display: block; text-align: left; - padding: 0 1rem; + padding: 0 19px; /* font-weight: 500; */ position: relative; } @@ -646,12 +652,11 @@ input { & + span { position: relative; - padding-left: 35px; + padding-left: calc(18px + 2.25rem); cursor: pointer; display: inline-block; height: 25px; line-height: 25px; - font-size: 1rem; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; @@ -718,7 +723,7 @@ input { } .input-wrapper > * ~ * { - margin-top: 1.2rem; + margin-top: 1.5rem; } .select-wrapper { @@ -726,7 +731,7 @@ input { /* height: auto; */ position: absolute; width: 100%; - top: calc(100% + 10px); + top: calc(100% + .5rem); left: 0; overflow: hidden; background-color: #fff; @@ -737,15 +742,15 @@ input { flex-wrap: wrap; ul { - margin: 10px 0; + margin: .5rem 0; } li { /* display: flex; */ align-items: center; - padding: 0 12.5px; + padding: 0 1rem; justify-content: space-between; - height: 50px; + height: 3.5rem; cursor: pointer; font-weight: 500; @@ -850,8 +855,7 @@ input:focus, button:focus { border-radius: $border-radius; width: 100%; text-align: center; - font-size: 0.85rem; - height: 45px; + height: 54px; border: none; font-weight: 500; cursor: pointer; @@ -1385,7 +1389,7 @@ div.scrollable::-webkit-scrollbar-thumb { text-align: center; flex: 1; user-select: none; - font-size: 16px; + font-size: 1rem; &.active { position: relative;