Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

fix: username validation when registering a new delegate #1218

Merged
merged 4 commits into from May 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
81 changes: 81 additions & 0 deletions __tests__/unit/services/wallet.spec.js
Expand Up @@ -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' }]
})
})
})
})
Expand Up @@ -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)
}
}
}
Expand Down
Expand Up @@ -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: {
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/locales/en-US.js
Expand Up @@ -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',
Expand Down
21 changes: 17 additions & 4 deletions 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'

Expand Down Expand Up @@ -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
}
}

/**
Expand Down