From 93c9466a52a7282a242167643e39ef15091a75fc Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 30 Apr 2019 10:43:58 +0200 Subject: [PATCH 1/4] limit passphrase length to 50 bytes --- .../modals/passphrase/Passphrase/index.js | 34 +++++++++++++------ .../passphrase/Passphrase/index.messages.js | 4 +++ src/utils/__tests__/formatUtils.test.js | 10 ++++++ src/utils/formatUtils.js | 11 ++++++ 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/components/modals/passphrase/Passphrase/index.js b/src/components/modals/passphrase/Passphrase/index.js index e0ef1989..7ce59e9e 100644 --- a/src/components/modals/passphrase/Passphrase/index.js +++ b/src/components/modals/passphrase/Passphrase/index.js @@ -2,6 +2,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; +import { byteLength } from 'utils/formatUtils'; import { FormattedMessage } from 'react-intl'; import { Button, Input, Checkbox, P, H5, colors } from 'trezor-ui-components'; import { FONT_SIZE } from 'config/variables'; @@ -24,6 +25,7 @@ type State = { passphraseCheckInputValue: string, doPassphraseInputsMatch: boolean, isPassphraseHidden: boolean, + byteLength: number, }; const Wrapper = styled.div` @@ -91,6 +93,7 @@ class Passphrase extends PureComponent { passphraseCheckInputValue: '', doPassphraseInputsMatch: true, isPassphraseHidden: true, + byteLength: 0, }; } @@ -117,6 +120,9 @@ class Passphrase extends PureComponent { let doPassphraseInputsMatch = false; if (inputName === 'passphraseInputValue') { + this.setState({ + byteLength: byteLength(inputValue), + }); // If passphrase is not hidden the second input should get filled automatically // and should be disabled if (this.state.isPassphraseHidden) { @@ -181,13 +187,28 @@ class Passphrase extends PureComponent { handleKeyPress(event: KeyboardEvent) { if (event.key === 'Enter') { event.preventDefault(); - if (this.state.doPassphraseInputsMatch) { + if (this.state.doPassphraseInputsMatch && this.state.byteLength < 50) { this.submitPassphrase(); } } } render() { + let error = null; + if (this.state.byteLength > 50) { + error = ( + + + + ); + } else if (!this.state.doPassphraseInputsMatch) { + error = ( + + + + ); + } + return (
@@ -236,11 +257,7 @@ class Passphrase extends PureComponent { /> )} - {!this.state.doPassphraseInputsMatch && ( - - - - )} + {error} { - diff --git a/src/components/modals/passphrase/Passphrase/index.messages.js b/src/components/modals/passphrase/Passphrase/index.messages.js index 1c059114..a6813822 100644 --- a/src/components/modals/passphrase/Passphrase/index.messages.js +++ b/src/components/modals/passphrase/Passphrase/index.messages.js @@ -24,6 +24,10 @@ const definedMessages: Messages = defineMessages({ id: 'TR_PASSPHRASES_DO_NOT_MATCH', defaultMessage: 'Passphrases do not match!', }, + TR_PASSPHRASES_IS_TOO_LONG: { + id: 'TR_PASSPHRASES_IS_TOO_LONG', + defaultMessage: 'Passphrase is too long!', + }, TR_SHOW_PASSPHRASE: { id: 'TR_SHOW_PASSPHRASE', defaultMessage: 'Show passphrase', diff --git a/src/utils/__tests__/formatUtils.test.js b/src/utils/__tests__/formatUtils.test.js index 4d57d0d1..67defb4a 100644 --- a/src/utils/__tests__/formatUtils.test.js +++ b/src/utils/__tests__/formatUtils.test.js @@ -21,4 +21,14 @@ describe('format utils', () => { expect(utils.fromDecimalAmount('a', 'a')).toBe('0'); expect(utils.fromDecimalAmount('a', '1')).toBe('0'); }); + + describe('byteLength', () => { + it('should return correct byte length for strings with special ASCII characters', () => { + expect(utils.byteLength('testString')).toEqual(10); + expect(utils.byteLength('~!@#$%^&*()_+{}|:?><')).toEqual(20); + expect(utils.byteLength('😀')).toEqual(4); + expect(utils.byteLength('ä')).toEqual(2); + expect(utils.byteLength('áľščť')).toEqual(10); + }); + }); }); diff --git a/src/utils/formatUtils.js b/src/utils/formatUtils.js index 4cea3e00..392ef109 100644 --- a/src/utils/formatUtils.js +++ b/src/utils/formatUtils.js @@ -27,3 +27,14 @@ export const fromDecimalAmount = (amount: string | number, decimals: number): st return '0'; } }; + +export const byteLength = (text: string): number => { + // returns length of the text in bytes, 0 in case of error. + try { + // regexp is handling cases when encodeURI returns '%uXXXX' or %XX%XX + return encodeURI(text).split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./).length - 1; + } catch (error) { + console.error(error); + return 0; + } +}; From b155406f4721cb0026313ed70b912f34468b15f9 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 30 Apr 2019 10:45:59 +0200 Subject: [PATCH 2/4] fix condition --- src/components/modals/passphrase/Passphrase/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/modals/passphrase/Passphrase/index.js b/src/components/modals/passphrase/Passphrase/index.js index 7ce59e9e..26ed5e3d 100644 --- a/src/components/modals/passphrase/Passphrase/index.js +++ b/src/components/modals/passphrase/Passphrase/index.js @@ -187,7 +187,7 @@ class Passphrase extends PureComponent { handleKeyPress(event: KeyboardEvent) { if (event.key === 'Enter') { event.preventDefault(); - if (this.state.doPassphraseInputsMatch && this.state.byteLength < 50) { + if (this.state.doPassphraseInputsMatch && this.state.byteLength <= 50) { this.submitPassphrase(); } } From c38a0b8630e7be2416118c1048b468817b2fee26 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Tue, 30 Apr 2019 10:46:49 +0200 Subject: [PATCH 3/4] fix message id --- src/components/modals/passphrase/Passphrase/index.js | 2 +- src/components/modals/passphrase/Passphrase/index.messages.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/modals/passphrase/Passphrase/index.js b/src/components/modals/passphrase/Passphrase/index.js index 26ed5e3d..4377ce47 100644 --- a/src/components/modals/passphrase/Passphrase/index.js +++ b/src/components/modals/passphrase/Passphrase/index.js @@ -198,7 +198,7 @@ class Passphrase extends PureComponent { if (this.state.byteLength > 50) { error = ( - + ); } else if (!this.state.doPassphraseInputsMatch) { diff --git a/src/components/modals/passphrase/Passphrase/index.messages.js b/src/components/modals/passphrase/Passphrase/index.messages.js index a6813822..073e68dc 100644 --- a/src/components/modals/passphrase/Passphrase/index.messages.js +++ b/src/components/modals/passphrase/Passphrase/index.messages.js @@ -24,8 +24,8 @@ const definedMessages: Messages = defineMessages({ id: 'TR_PASSPHRASES_DO_NOT_MATCH', defaultMessage: 'Passphrases do not match!', }, - TR_PASSPHRASES_IS_TOO_LONG: { - id: 'TR_PASSPHRASES_IS_TOO_LONG', + TR_PASSPHRASE_IS_TOO_LONG: { + id: 'TR_PASSPHRASE_IS_TOO_LONG', defaultMessage: 'Passphrase is too long!', }, TR_SHOW_PASSPHRASE: { From 0c2724be3e6f1246c50368fbc1663db90d5df429 Mon Sep 17 00:00:00 2001 From: slowbackspace Date: Thu, 2 May 2019 10:17:42 +0200 Subject: [PATCH 4/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3ed0cac..77c7312a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ __changed__ - static (without animation) active tab indicator - input validation - mandatory leading 0 for float numbers - regexps refactored to functions, added unit tests +- limit passphrase length to 50 bytes __removed__ - Text "already used" from token select in case of already added tokens