diff --git a/__tests__/unit/services/wallet.spec.js b/__tests__/unit/services/wallet.spec.js index f40e0020af..62bf960614 100644 --- a/__tests__/unit/services/wallet.spec.js +++ b/__tests__/unit/services/wallet.spec.js @@ -50,4 +50,85 @@ describe('Services > Wallet', () => { expect(WalletService.getAddress(passphrase, 30)).toEqual(address) }) }) + + describe('validateUsername', () => { + it('should work OK', () => { + const username = 'example' + expect(WalletService.validateUsername(username)).toEqual({ + passes: true, + errors: [] + }) + }) + + it('should not be empty', () => { + const username = '' + expect(WalletService.validateUsername(username)).toEqual({ + passes: false, + errors: [{ type: 'empty' }] + }) + }) + + it('should admit 20 characters at most', () => { + const username = 'asdf1234asdf1234asdf1234' + expect(WalletService.validateUsername(username)).toEqual({ + passes: false, + errors: [{ type: 'maxLength' }] + }) + }) + + it('should not admit uppercase characters', () => { + const username = 'eXamPLe' + expect(WalletService.validateUsername(username)).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + }) + + it('should admit only alphanumeric characters and some symbols', () => { + expect(WalletService.validateUsername('a!5@$&_.')).toEqual({ + passes: true, + errors: [] + }) + + expect(WalletService.validateUsername('~ll')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + + expect(WalletService.validateUsername('a#')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + + expect(WalletService.validateUsername('a%0')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + + expect(WalletService.validateUsername('(a)')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + + expect(WalletService.validateUsername('a}a{')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + + expect(WalletService.validateUsername('a[a]')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + + expect(WalletService.validateUsername('a+a')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + + expect(WalletService.validateUsername('a-a')).toEqual({ + passes: false, + errors: [{ type: 'invalidFormat' }] + }) + }) + }) }) diff --git a/src/renderer/components/Transaction/TransactionConfirm/TransactionConfirmDelegateRegistration.vue b/src/renderer/components/Transaction/TransactionConfirm/TransactionConfirmDelegateRegistration.vue index 97ba1fda0a..fbb0d2c8dd 100644 --- a/src/renderer/components/Transaction/TransactionConfirm/TransactionConfirmDelegateRegistration.vue +++ b/src/renderer/components/Transaction/TransactionConfirm/TransactionConfirmDelegateRegistration.vue @@ -32,16 +32,18 @@ export default { ListDividedItem }, + computed: { + senderLabel () { + return this.wallet_formatAddress(this.currentWallet.address) + } + }, + methods: { getUsername (transaction) { if (transaction.asset && transaction.asset.delegate) { return transaction.asset.delegate.username } return '' - }, - - senderLabel () { - return this.wallet_formatAddress(this.currentWallet.address) } } } diff --git a/src/renderer/components/Transaction/TransactionForm/TransactionFormDelegateRegistration.vue b/src/renderer/components/Transaction/TransactionForm/TransactionFormDelegateRegistration.vue index a78482fb7f..ed84a98c06 100644 --- a/src/renderer/components/Transaction/TransactionForm/TransactionFormDelegateRegistration.vue +++ b/src/renderer/components/Transaction/TransactionForm/TransactionFormDelegateRegistration.vue @@ -218,26 +218,25 @@ export default { } }, username: { - required, isValid (value) { const validation = WalletService.validateUsername(value) - if (validation && validation.passes) { - this.error = null - return validation.passes - } - if (validation.errors && validation.errors.length) { - const { type } = validation.errors[0] - if (type === 'string.max') { - this.error = this.$t('WALLET_DELEGATES.USERNAME_MAX_LENGTH_ERROR') - } else { - this.error = this.$t('WALLET_DELEGATES.USERNAME_ERROR') - } + if (validation.passes) { + this.error = null } else { - this.error = this.$t('WALLET_DELEGATES.USERNAME_ERROR') + switch (validation.errors[0].type) { + case 'empty': + this.error = this.$t('WALLET_DELEGATES.USERNAME_EMPTY_ERROR') + break + case 'maxLength': + this.error = this.$t('WALLET_DELEGATES.USERNAME_MAX_LENGTH_ERROR') + break + default: + this.error = this.$t('WALLET_DELEGATES.USERNAME_ERROR') + } } - return false + return validation.passes } }, passphrase: { diff --git a/src/renderer/i18n/locales/en-US.js b/src/renderer/i18n/locales/en-US.js index e6dd1f7a52..1e229a18d0 100644 --- a/src/renderer/i18n/locales/en-US.js +++ b/src/renderer/i18n/locales/en-US.js @@ -923,6 +923,7 @@ export default { UNVOTE: 'Unvote', VOTES: 'Votes', VOTE: 'Vote', + USERNAME_EMPTY_ERROR: 'The username must have at least 1 character', USERNAME_ERROR: 'No special characters or uppercase allowed', USERNAME_MAX_LENGTH_ERROR: 'The username must be less than or equal to 20 characters long', ALREADY_REGISTERED: 'This wallet is already registered as a delegate', diff --git a/src/renderer/services/wallet.js b/src/renderer/services/wallet.js index 61bb88d06c..13cf232457 100644 --- a/src/renderer/services/wallet.js +++ b/src/renderer/services/wallet.js @@ -1,5 +1,5 @@ import bip39 from 'bip39' -import { crypto, Message, validator } from '@arkecosystem/crypto' +import { crypto, Message } from '@arkecosystem/crypto' import { version as mainnetVersion } from '@config/networks/mainnet' import axios from 'axios' @@ -139,11 +139,24 @@ export default class WalletService { * Check that a username is valid * * @param {String} username - * @return {Object} { data: String, errors: Array, passes: Boolean, fails: Error } + * @return {Object} { errors: Array, passes: Boolean } */ static validateUsername (username) { - if (!username) return - return validator.rules.username(username) + let errors = [] + + if (username.length < 1) { + errors.push({ type: 'empty' }) + } else if (username.length > 20) { + errors.push({ type: 'maxLength' }) + // Regex from `@arkecosystem/crypto` + } else if (!username.match(/^[a-z0-9!@$&_.]+$/)) { + errors.push({ type: 'invalidFormat' }) + } + + return { + errors, + passes: errors.length === 0 + } } /**