1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-28 23:06:37 +01:00

Merge pull request #8054 from MetaMask/Version-v7.7.5

Version v7.7.5 RC
This commit is contained in:
Thomas Huang 2020-02-18 11:19:31 -08:00 committed by GitHub
commit 2285a5077d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 182 additions and 59 deletions

View File

@ -2,6 +2,12 @@
## Current Develop Branch
## 7.7.5 Fri Feb 14 2020
- [#8053](https://github.com/MetaMask/metamask-extension/pull/8053): Inline the source text not the binary encoding for inpage script
- [#8049](https://github.com/MetaMask/metamask-extension/pull/8049): Add warning to watchAsset API when editing a known token
- [#8051](https://github.com/MetaMask/metamask-extension/pull/8051): Update Wyre ETH purchase url
- [#8059](https://github.com/MetaMask/metamask-extension/pull/8059): Attempt ENS resolution on any valid domain name
## 7.7.4 Wed Jan 29 2020
- [#7918](https://github.com/MetaMask/metamask-extension/pull/7918): Update data on Approve screen after updating custom spend limit
- [#7919](https://github.com/MetaMask/metamask-extension/pull/7919): Allow editing max spend limit

View File

@ -715,6 +715,12 @@
"knownAddressRecipient": {
"message": "Known contract address."
},
"knownTokenWarning": {
"message": "This action will edit tokens that are already listed in your wallet, which can be used to phish you. Only approve if you are certain that you mean to change what these tokens represent."
},
"reusedTokenNameWarning": {
"message": "A token here reuses a symbol from another token you watch, this can be confusing or deceptive."
},
"invalidAddressRecipientNotEthNetwork": {
"message": "Not ETH network, set to lowercase"
},

View File

@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
"version": "7.7.4",
"version": "7.7.5",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "__MSG_appDescription__",

View File

@ -9,7 +9,7 @@ const ObjectMultiplex = require('obj-multiplex')
const extension = require('extensionizer')
const PortStream = require('extension-port-stream')
const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString()
const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js'), 'utf8')
const inpageSuffix = '//# sourceURL=' + extension.runtime.getURL('inpage.js') + '\n'
const inpageBundle = inpageContent + inpageSuffix

View File

@ -17,7 +17,7 @@ function getBuyEthUrl ({ network, amount, address, service }) {
switch (service) {
case 'wyre':
return `https://dash.sendwyre.com/sign-up`
return `https://pay.sendwyre.com/?dest=ethereum:${address}&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`
case 'coinswitch':
return `https://metamask.coinswitch.co/?address=${address}&to=eth`
case 'coinbase':

View File

@ -20,7 +20,7 @@ describe('buy-eth-url', function () {
it('returns coinbase url with amount and address for network 1', function () {
const wyreUrl = getBuyEthUrl(mainnet)
assert.equal(wyreUrl, 'https://dash.sendwyre.com/sign-up')
assert.equal(wyreUrl, 'https://pay.sendwyre.com/?dest=ethereum:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card')
})

View File

@ -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 () {
it('should return a BN 0 if given nothing', function () {
var result = util.numericBalance()

View File

@ -2,6 +2,7 @@ const abi = require('human-standard-token-abi')
const ethUtil = require('ethereumjs-util')
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
import { DateTime } from 'luxon'
import punycode from 'punycode'
const MIN_GAS_PRICE_GWEI_BN = new ethUtil.BN(1)
const GWEI_FACTOR = new ethUtil.BN(1e9)
@ -36,7 +37,7 @@ module.exports = {
miniAddressSummary: miniAddressSummary,
isAllOneCase: isAllOneCase,
isValidAddress: isValidAddress,
isValidENSAddress,
isValidDomainName,
numericBalance: numericBalance,
parseBalance: parseBalance,
formatBalance: formatBalance,
@ -99,8 +100,14 @@ function isValidAddress (address) {
return (isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed)
}
function isValidENSAddress (address) {
return address.match(/^.{3,}\.(eth|test|xyz)$/)
function isValidDomainName (address) {
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) {

View File

@ -16,6 +16,7 @@ export default class ConfirmAddSuggestedToken extends Component {
addToken: PropTypes.func,
pendingTokens: PropTypes.object,
removeSuggestedTokens: PropTypes.func,
tokens: PropTypes.array,
}
componentDidMount () {
@ -33,9 +34,11 @@ export default class ConfirmAddSuggestedToken extends Component {
}
render () {
const { addToken, pendingTokens, removeSuggestedTokens, history } = this.props
const { addToken, pendingTokens, tokens, removeSuggestedTokens, history } = this.props
const pendingTokenKey = Object.keys(pendingTokens)[0]
const pendingToken = pendingTokens[pendingTokenKey]
const hasTokenDuplicates = this.checkTokenDuplicates(pendingTokens, tokens)
const reusesName = this.checkNameReuse(pendingTokens, tokens)
return (
<div className="page-container">
@ -46,6 +49,20 @@ export default class ConfirmAddSuggestedToken extends Component {
<div className="page-container__subtitle">
{ this.context.t('likeToAddTokens') }
</div>
{ hasTokenDuplicates ?
(
<div className="warning">
{ this.context.t('knownTokenWarning') }
</div>
) : null
}
{ reusesName ?
(
<div className="warning">
{ this.context.t('reusedTokenNameWarning') }
</div>
) : null
}
</div>
<div className="page-container__content">
<div className="confirm-add-token">
@ -119,4 +136,32 @@ export default class ConfirmAddSuggestedToken extends Component {
</div>
)
}
checkTokenDuplicates (pendingTokens, tokens) {
const pending = Object.keys(pendingTokens)
const existing = tokens.map(token => token.address)
const dupes = pending.filter((proposed) => {
return existing.includes(proposed)
})
return dupes.length > 0
}
/**
* Returns true if any pendingTokens both:
* - Share a symbol with an existing `tokens` member.
* - Does not share an address with that same `tokens` member.
* This should be flagged as possibly deceptive or confusing.
*/
checkNameReuse (pendingTokens, tokens) {
const duplicates = Object.keys(pendingTokens)
.map((addr) => pendingTokens[addr])
.filter((token) => {
const dupes = tokens.filter(old => old.symbol === token.symbol)
.filter(old => old.address !== token.address)
return dupes.length > 0
})
return duplicates.length > 0
}
}

View File

@ -8,11 +8,12 @@ const extend = require('xtend')
const { addToken, removeSuggestedTokens } = require('../../store/actions')
const mapStateToProps = ({ metamask }) => {
const { pendingTokens, suggestedTokens } = metamask
const { pendingTokens, suggestedTokens, tokens } = metamask
const params = extend(pendingTokens, suggestedTokens)
return {
pendingTokens: params,
tokens,
}
}

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
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 debounce from 'debounce'
@ -91,7 +91,7 @@ export default class EnsInput extends Component {
this.props.updateEnsResolution(address)
})
.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'))
} else {
log.error(reason)
@ -124,7 +124,7 @@ export default class EnsInput extends Component {
return
}
if (isValidENSAddress(input)) {
if (isValidDomainName(input)) {
this.lookupEnsName(input)
} else if (onValidAddressTyped && isValidAddress(input)) {
onValidAddressTyped(input)

View File

@ -55,7 +55,7 @@ import {
calcGasTotal,
} from './send.utils.js'
import {
isValidENSAddress,
isValidDomainName,
} from '../../helpers/utils/util'
import {
@ -126,7 +126,7 @@ function mapDispatchToProps (dispatch) {
updateSendEnsResolution: (ensResolution) => dispatch(updateSendEnsResolution(ensResolution)),
updateSendEnsResolutionError: (message) => dispatch(updateSendEnsResolutionError(message)),
updateToNicknameIfNecessary: (to, toNickname, addressBook) => {
if (isValidENSAddress(toNickname)) {
if (isValidDomainName(toNickname)) {
const addressBookEntry = addressBook.find(({ address }) => to === address) || {}
if (!addressBookEntry.name !== toNickname) {
dispatch(updateSendTo(to, addressBookEntry.name || ''))

View File

@ -3,8 +3,8 @@ import PropTypes from 'prop-types'
import Identicon from '../../../../components/ui/identicon'
import TextField from '../../../../components/ui/text-field'
import { CONTACT_LIST_ROUTE } from '../../../../helpers/constants/routes'
import { isValidAddress, isValidENSAddress } from '../../../../helpers/utils/util'
import EnsInput from '../../../../pages/send/send-content/add-recipient/ens-input'
import { isValidAddress, isValidDomainName } from '../../../../helpers/utils/util'
import EnsInput from '../../../send/send-content/add-recipient/ens-input'
import PageContainerFooter from '../../../../components/ui/page-container/page-container-footer'
import debounce from 'lodash.debounce'
@ -51,7 +51,7 @@ export default class AddContact extends PureComponent {
validate = address => {
const valid = isValidAddress(address)
const validEnsAddress = isValidENSAddress(address)
const validEnsAddress = isValidDomainName(address)
if (valid || validEnsAddress || address === '') {
this.setState({ error: '', ethAddress: address })
} else {

View File

@ -1670,25 +1670,25 @@
normalize-path "^2.0.1"
through2 "^2.0.3"
"@hapi/accept@3.x.x":
version "3.2.2"
resolved "https://registry.yarnpkg.com/@hapi/accept/-/accept-3.2.2.tgz#3a033af67be8196c23f8f51aa8756687b972c7cb"
integrity sha512-UtXlTT59srtMr7ZRBzK2CvyWqFwlf78hPt9jEXqkwfbwiwRH1PRv/qkS8lgr5ZyoG6kfpU3xTgt2X91Yfe/6Yg==
"@hapi/accept@^3.2.4":
version "3.2.4"
resolved "https://registry.yarnpkg.com/@hapi/accept/-/accept-3.2.4.tgz#687510529493fe1d7d47954c31aff360d9364bd1"
integrity sha512-soThGB+QMgfxlh0Vzhzlf3ZOEOPk5biEwcOXhkF0Eedqx8VnhGiggL9UYHrIsOb1rUg3Be3K8kp0iDL2wbVSOQ==
dependencies:
"@hapi/boom" "7.x.x"
"@hapi/hoek" "6.x.x"
"@hapi/hoek" "8.x.x"
"@hapi/address@2.x.x":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a"
integrity sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==
"@hapi/ammo@3.x.x", "@hapi/ammo@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@hapi/ammo/-/ammo-3.1.0.tgz#a3281ecb68bf7af2ffa6d0f7656536a7d23700ed"
integrity sha512-iFQBEfm3WwWy8JdPQ8l6qXVLPtzmjITVfaxwl6dfoP8kKv6i2Uk43Ax+ShkNfOVyfEnNggqL2IyZTY3DaaRGNg==
"@hapi/ammo@3.x.x", "@hapi/ammo@^3.1.0", "@hapi/ammo@^3.1.2":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@hapi/ammo/-/ammo-3.1.2.tgz#a9edf5d48d99b75fdcd7ab3dabf9059942a06961"
integrity sha512-ej9OtFmiZv1qr45g1bxEZNGyaR4jRpyMxU6VhbxjaYThymvOwsyIsUKMZnP5Qw2tfYFuwqCJuIBHGpeIbdX9gQ==
dependencies:
"@hapi/hoek" "6.x.x"
"@hapi/hoek" "8.x.x"
"@hapi/b64@4.x.x":
version "4.2.0"
@ -1717,13 +1717,13 @@
resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a"
integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==
"@hapi/call@5.x.x":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@hapi/call/-/call-5.1.0.tgz#91e4c434318003173d96d211d90d35736a33945e"
integrity sha512-CiVEXjD/jiIHBqufBW3pdedshEMjRmHtff7m1puot8j4MUmuKRbLlh0DB8fv6QqH/7/55pH1qgFj300r0WpyMw==
"@hapi/call@^5.1.3":
version "5.1.3"
resolved "https://registry.yarnpkg.com/@hapi/call/-/call-5.1.3.tgz#217af45e3bc3d38b03aa5c9edfe1be939eee3741"
integrity sha512-5DfWpMk7qZiYhvBhM5oUiT4GQ/O8a2rFR121/PdwA/eZ2C1EsuD547ZggMKAR5bZ+FtxOf0fdM20zzcXzq2mZA==
dependencies:
"@hapi/boom" "7.x.x"
"@hapi/hoek" "6.x.x"
"@hapi/hoek" "8.x.x"
"@hapi/catbox-memory@4.x.x":
version "4.1.0"
@ -1743,10 +1743,10 @@
"@hapi/joi" "15.x.x"
"@hapi/podium" "3.x.x"
"@hapi/content@4.x.x", "@hapi/content@^4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@hapi/content/-/content-4.1.0.tgz#5265516949ca081e85a43e97c1058ff53fc69714"
integrity sha512-hv2Czsl49hnWDEfRZOFow/BmYbKyfEknmk3k83gOp6moFn5ceHB4xVcna8OwsGfy8dxO81lhpPy+JgQEaU4SWw==
"@hapi/content@^4.1.0", "@hapi/content@^4.1.1":
version "4.1.1"
resolved "https://registry.yarnpkg.com/@hapi/content/-/content-4.1.1.tgz#179673d1e2b7eb36c564d8f9605d019bd2252cbf"
integrity sha512-3TWvmwpVPxFSF3KBjKZ8yDqIKKZZIm7VurDSweYpXYENZrJH3C1hd1+qEQW9wQaUaI76pPBLGrXl6I3B7i3ipA==
dependencies:
"@hapi/boom" "7.x.x"
@ -1763,26 +1763,26 @@
integrity sha512-Bsfp/+1Gyf70eGtnIgmScvrH8sSypO3TcK3Zf0QdHnzn/ACnAkI6KLtGACmNRPEzzIy+W7aJX5E+1fc9GwIABQ==
"@hapi/hapi@^18.3.1":
version "18.3.1"
resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-18.3.1.tgz#936d1e24551b11486eabd6a4974bea4ec2127669"
integrity sha512-gBiU9isWWezrg0ucX95Ph6AY6fUKZub3FxKapaleoFBJDOUcxTYiQR6Lha2zvHalIFoTl3K04O3Yr/5pD17QkQ==
version "18.4.1"
resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-18.4.1.tgz#023fbc131074b1cb2cd7f6766d65f4b0e92df788"
integrity sha512-9HjVGa0Z4Qv9jk9AVoUdJMQLA+KuZ+liKWyEEkVBx3e3H1F0JM6aGbPkY9jRfwsITBWGBU2iXazn65SFKSi/tg==
dependencies:
"@hapi/accept" "3.x.x"
"@hapi/ammo" "3.x.x"
"@hapi/accept" "^3.2.4"
"@hapi/ammo" "^3.1.2"
"@hapi/boom" "7.x.x"
"@hapi/bounce" "1.x.x"
"@hapi/call" "5.x.x"
"@hapi/call" "^5.1.3"
"@hapi/catbox" "10.x.x"
"@hapi/catbox-memory" "4.x.x"
"@hapi/heavy" "6.x.x"
"@hapi/hoek" "6.x.x"
"@hapi/hoek" "8.x.x"
"@hapi/joi" "15.x.x"
"@hapi/mimos" "4.x.x"
"@hapi/podium" "3.x.x"
"@hapi/shot" "4.x.x"
"@hapi/somever" "2.x.x"
"@hapi/statehood" "6.x.x"
"@hapi/subtext" "6.x.x"
"@hapi/subtext" "^6.1.3"
"@hapi/teamwork" "3.x.x"
"@hapi/topo" "3.x.x"
@ -1858,15 +1858,15 @@
"@hapi/hoek" "6.x.x"
"@hapi/vise" "3.x.x"
"@hapi/pez@4.x.x":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@hapi/pez/-/pez-4.1.0.tgz#97a88e5d19e756efbd24e5f583d59fa8db1d6cba"
integrity sha512-c+AxL8/cCj+7FB+tzJ5FhWKYP8zF7/7mA3Ft3a5y7h6YT26qzhj5d2JY27jur30KaZbrZAd4ofXXkqvE/IpJlA==
"@hapi/pez@^4.1.2":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@hapi/pez/-/pez-4.1.2.tgz#14984d0c31fed348f10c962968a21d9761f55503"
integrity sha512-8zSdJ8cZrJLFldTgwjU9Fb1JebID+aBCrCsycgqKYe0OZtM2r3Yv3aAwW5z97VsZWCROC1Vx6Mdn4rujh5Ktcg==
dependencies:
"@hapi/b64" "4.x.x"
"@hapi/boom" "7.x.x"
"@hapi/content" "4.x.x"
"@hapi/hoek" "6.x.x"
"@hapi/content" "^4.1.1"
"@hapi/hoek" "8.x.x"
"@hapi/nigel" "3.x.x"
"@hapi/podium@3.x.x":
@ -1906,17 +1906,17 @@
"@hapi/iron" "5.x.x"
"@hapi/joi" "15.x.x"
"@hapi/subtext@6.x.x":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@hapi/subtext/-/subtext-6.1.2.tgz#87754f0c25b4e2676575a3686541e5b555b0c717"
integrity sha512-G1kqD1E2QdxpvpL26WieIyo3z0qCa/sAGSa2TJI/PYPWCR9rL0rqFvhWY774xPZ4uK1PV3TIaJcx8AruAvxclg==
"@hapi/subtext@^6.1.3":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@hapi/subtext/-/subtext-6.1.3.tgz#bbd07771ae2a4e73ac360c93ed74ac641718b9c6"
integrity sha512-qWN6NbiHNzohVcJMeAlpku/vzbyH4zIpnnMPMPioQMwIxbPFKeNViDCNI6fVBbMPBiw/xB4FjqiJkRG5P9eWWg==
dependencies:
"@hapi/boom" "7.x.x"
"@hapi/bourne" "1.x.x"
"@hapi/content" "4.x.x"
"@hapi/content" "^4.1.1"
"@hapi/file" "1.x.x"
"@hapi/hoek" "8.x.x"
"@hapi/pez" "4.x.x"
"@hapi/pez" "^4.1.2"
"@hapi/wreck" "15.x.x"
"@hapi/teamwork@3.x.x":
@ -7576,7 +7576,7 @@ cross-spawn@^4:
lru-cache "^4.0.1"
which "^1.2.9"
cross-spawn@^5.0.1:
cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=