mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-28 23:06:37 +01:00
Attempt ENS resolution on any valid domain name (#8059)
ENS currently supports a variety of tlds in addition to `.eth`, and more will be supported in the future. Rather than hard-code a list of supported ENS tlds, all valid domain names will now be interpreted as potential ENS addresses in our address input component. Closes #7978
This commit is contained in:
parent
5156191ba7
commit
5b030bfdc3
@ -103,6 +103,64 @@ describe('util', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('isValidDomainName', function () {
|
||||||
|
it('should return true when given a valid domain name', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('foo.bar'), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true when given a valid subdomain', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('foo.foo.bar'), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true when given a single-character domain', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('f.bar'), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true when given a unicode TLD', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('台灣.中国'), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a domain with unacceptable ASCII characters', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('$.bar'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a TLD that starts with a dash', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('foo.-bar'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a TLD that ends with a dash', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('foo.bar-'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a domain name with a chunk that starts with a dash', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('-foo.bar'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a domain name with a chunk that ends with a dash', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('foo-.bar'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a bare TLD', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('bar'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a domain that starts with a period', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('.bar'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a subdomain that starts with a period', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('.foo.bar'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a domain that ends with a period', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('bar.'), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false when given a 1-character TLD', function () {
|
||||||
|
assert.strictEqual(util.isValidDomainName('foo.b'), false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('#numericBalance', function () {
|
describe('#numericBalance', function () {
|
||||||
it('should return a BN 0 if given nothing', function () {
|
it('should return a BN 0 if given nothing', function () {
|
||||||
var result = util.numericBalance()
|
var result = util.numericBalance()
|
||||||
|
@ -2,6 +2,7 @@ const abi = require('human-standard-token-abi')
|
|||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
|
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
|
import punycode from 'punycode'
|
||||||
|
|
||||||
const MIN_GAS_PRICE_GWEI_BN = new ethUtil.BN(1)
|
const MIN_GAS_PRICE_GWEI_BN = new ethUtil.BN(1)
|
||||||
const GWEI_FACTOR = new ethUtil.BN(1e9)
|
const GWEI_FACTOR = new ethUtil.BN(1e9)
|
||||||
@ -36,7 +37,7 @@ module.exports = {
|
|||||||
miniAddressSummary: miniAddressSummary,
|
miniAddressSummary: miniAddressSummary,
|
||||||
isAllOneCase: isAllOneCase,
|
isAllOneCase: isAllOneCase,
|
||||||
isValidAddress: isValidAddress,
|
isValidAddress: isValidAddress,
|
||||||
isValidENSAddress,
|
isValidDomainName,
|
||||||
numericBalance: numericBalance,
|
numericBalance: numericBalance,
|
||||||
parseBalance: parseBalance,
|
parseBalance: parseBalance,
|
||||||
formatBalance: formatBalance,
|
formatBalance: formatBalance,
|
||||||
@ -99,8 +100,14 @@ function isValidAddress (address) {
|
|||||||
return (isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed)
|
return (isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidENSAddress (address) {
|
function isValidDomainName (address) {
|
||||||
return address.match(/^.{3,}\.(eth|test|xyz)$/)
|
const match = punycode.toASCII(address)
|
||||||
|
.toLowerCase()
|
||||||
|
// Checks that the domain consists of at least one valid domain pieces separated by periods, followed by a tld
|
||||||
|
// Each piece of domain name has only the characters a-z, 0-9, and a hyphen (but not at the start or end of chunk)
|
||||||
|
// A chunk has minimum length of 1, but minimum tld is set to 2 for now (no 1-character tlds exist yet)
|
||||||
|
.match(/^(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+[a-z0-9][-a-z0-9]*[a-z0-9]$/)
|
||||||
|
return match !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInvalidChecksumAddress (address) {
|
function isInvalidChecksumAddress (address) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import c from 'classnames'
|
import c from 'classnames'
|
||||||
import { isValidENSAddress, isValidAddress, isValidAddressHead } from '../../../../helpers/utils/util'
|
import { isValidDomainName, isValidAddress, isValidAddressHead } from '../../../../helpers/utils/util'
|
||||||
import {ellipsify} from '../../send.utils'
|
import { ellipsify } from '../../send.utils'
|
||||||
|
|
||||||
import debounce from 'debounce'
|
import debounce from 'debounce'
|
||||||
import copyToClipboard from 'copy-to-clipboard/index'
|
import copyToClipboard from 'copy-to-clipboard/index'
|
||||||
@ -91,7 +91,7 @@ export default class EnsInput extends Component {
|
|||||||
this.props.updateEnsResolution(address)
|
this.props.updateEnsResolution(address)
|
||||||
})
|
})
|
||||||
.catch((reason) => {
|
.catch((reason) => {
|
||||||
if (isValidENSAddress(recipient) && reason.message === 'ENS name not defined.') {
|
if (isValidDomainName(recipient) && reason.message === 'ENS name not defined.') {
|
||||||
this.props.updateEnsResolutionError(this.context.t('ensNotFoundOnCurrentNetwork'))
|
this.props.updateEnsResolutionError(this.context.t('ensNotFoundOnCurrentNetwork'))
|
||||||
} else {
|
} else {
|
||||||
log.error(reason)
|
log.error(reason)
|
||||||
@ -124,7 +124,7 @@ export default class EnsInput extends Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValidENSAddress(input)) {
|
if (isValidDomainName(input)) {
|
||||||
this.lookupEnsName(input)
|
this.lookupEnsName(input)
|
||||||
} else if (onValidAddressTyped && isValidAddress(input)) {
|
} else if (onValidAddressTyped && isValidAddress(input)) {
|
||||||
onValidAddressTyped(input)
|
onValidAddressTyped(input)
|
||||||
|
@ -55,7 +55,7 @@ import {
|
|||||||
calcGasTotal,
|
calcGasTotal,
|
||||||
} from './send.utils.js'
|
} from './send.utils.js'
|
||||||
import {
|
import {
|
||||||
isValidENSAddress,
|
isValidDomainName,
|
||||||
} from '../../helpers/utils/util'
|
} from '../../helpers/utils/util'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -126,8 +126,8 @@ function mapDispatchToProps (dispatch) {
|
|||||||
updateSendEnsResolution: (ensResolution) => dispatch(updateSendEnsResolution(ensResolution)),
|
updateSendEnsResolution: (ensResolution) => dispatch(updateSendEnsResolution(ensResolution)),
|
||||||
updateSendEnsResolutionError: (message) => dispatch(updateSendEnsResolutionError(message)),
|
updateSendEnsResolutionError: (message) => dispatch(updateSendEnsResolutionError(message)),
|
||||||
updateToNicknameIfNecessary: (to, toNickname, addressBook) => {
|
updateToNicknameIfNecessary: (to, toNickname, addressBook) => {
|
||||||
if (isValidENSAddress(toNickname)) {
|
if (isValidDomainName(toNickname)) {
|
||||||
const addressBookEntry = addressBook.find(({ address}) => to === address) || {}
|
const addressBookEntry = addressBook.find(({ address }) => to === address) || {}
|
||||||
if (!addressBookEntry.name !== toNickname) {
|
if (!addressBookEntry.name !== toNickname) {
|
||||||
dispatch(updateSendTo(to, addressBookEntry.name || ''))
|
dispatch(updateSendTo(to, addressBookEntry.name || ''))
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ import PropTypes from 'prop-types'
|
|||||||
import Identicon from '../../../../components/ui/identicon'
|
import Identicon from '../../../../components/ui/identicon'
|
||||||
import TextField from '../../../../components/ui/text-field'
|
import TextField from '../../../../components/ui/text-field'
|
||||||
import { CONTACT_LIST_ROUTE } from '../../../../helpers/constants/routes'
|
import { CONTACT_LIST_ROUTE } from '../../../../helpers/constants/routes'
|
||||||
import { isValidAddress, isValidENSAddress } from '../../../../helpers/utils/util'
|
import { isValidAddress, isValidDomainName } from '../../../../helpers/utils/util'
|
||||||
import EnsInput from '../../../../pages/send/send-content/add-recipient/ens-input'
|
import EnsInput from '../../../send/send-content/add-recipient/ens-input'
|
||||||
import PageContainerFooter from '../../../../components/ui/page-container/page-container-footer'
|
import PageContainerFooter from '../../../../components/ui/page-container/page-container-footer'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export default class AddContact extends PureComponent {
|
|||||||
|
|
||||||
validate = address => {
|
validate = address => {
|
||||||
const valid = isValidAddress(address)
|
const valid = isValidAddress(address)
|
||||||
const validEnsAddress = isValidENSAddress(address)
|
const validEnsAddress = isValidDomainName(address)
|
||||||
if (valid || validEnsAddress || address === '') {
|
if (valid || validEnsAddress || address === '') {
|
||||||
this.setState({ error: '', ethAddress: address })
|
this.setState({ error: '', ethAddress: address })
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user