diff --git a/CHANGELOG.md b/CHANGELOG.md index aa6b76751..c80389505 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ ## Current Develop Branch +## 8.0.1 Thu Jul 02 2020 +- [#8874](https://github.com/MetaMask/metamask-extension/pull/8874): Fx overflow behaviour of add token list +- [#8885](https://github.com/MetaMask/metamask-extension/pull/8885): Show `origin` in connect flow rather than site name +- [#8883](https://github.com/MetaMask/metamask-extension/pull/8883): Allow setting a custom nonce of zero +- [#8889](https://github.com/MetaMask/metamask-extension/pull/8889): Fix language code format mismatch +- [#8891](https://github.com/MetaMask/metamask-extension/pull/8891): Prevent showing connected accounts without origin +- [#8893](https://github.com/MetaMask/metamask-extension/pull/8893): Prevent manually connecting to extension UI +- [#8895](https://github.com/MetaMask/metamask-extension/pull/8895): Allow localized messages to not use substitutions +- [#8897](https://github.com/MetaMask/metamask-extension/pull/8897): Update eth-keyring-controller to fix erasure of imported/hardware account names +- [#8896](https://github.com/MetaMask/metamask-extension/pull/8896): Include relative time polyfill locale data +- [#8898](https://github.com/MetaMask/metamask-extension/pull/8898): Replace percentage opacity value + ## 8.0.0 Mon Jun 23 2020 - [#7004](https://github.com/MetaMask/metamask-extension/pull/7004): Add permission system - [#7261](https://github.com/MetaMask/metamask-extension/pull/7261): Search accounts by name diff --git a/app/manifest/_base.json b/app/manifest/_base.json index 83ad55d90..1d567a273 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "8.0.0", + "version": "8.0.1", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 43e13b77a..344f9a972 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -443,14 +443,14 @@ export default class TransactionController extends EventEmitter { const txMeta = this.txStateManager.getTx(txId) const fromAddress = txMeta.txParams.from // wait for a nonce - let { customNonceValue = null } = txMeta + let { customNonceValue } = txMeta customNonceValue = Number(customNonceValue) nonceLock = await this.nonceTracker.getNonceLock(fromAddress) // add nonce to txParams // if txMeta has lastGasPrice then it is a retry at same nonce with higher // gas price transaction and their for the nonce should not be calculated const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce - const customOrNonce = customNonceValue || nonce + const customOrNonce = (customNonceValue === 0) ? customNonceValue : customNonceValue || nonce txMeta.txParams.nonce = ethUtil.addHexPrefix(customOrNonce.toString(16)) // add nonce debugging information to txMeta diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 5e8cc8e66..822ea73a4 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -83,10 +83,15 @@ async function queryCurrentActiveTab (windowType) { extension.tabs.query({ active: true, currentWindow: true }, (tabs) => { const [activeTab] = tabs - const { title, url } = activeTab + const { id, title, url } = activeTab const { origin, protocol } = url ? new URL(url) : {} - resolve({ title, origin, protocol, url }) + if (!origin || origin === 'null') { + resolve({}) + return + } + + resolve({ id, title, origin, protocol, url }) }) }) } diff --git a/development/build/static.js b/development/build/static.js index de206d1f1..62dbeaa62 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -3,6 +3,8 @@ const path = require('path') const watch = require('gulp-watch') const glob = require('fast-glob') +const locales = require('../../app/_locales/index.json') + const { createTask, composeSeries } = require('./task') module.exports = createStaticAssetTasks @@ -45,6 +47,20 @@ const copyTargets = [ }, ] +const languageTags = new Set() +for (const locale of locales) { + const { code } = locale + const tag = code.split('_')[0] + languageTags.add(tag) +} + +for (const tag of languageTags) { + copyTargets.push({ + src: `./node_modules/@formatjs/intl-relativetimeformat/dist/locale-data/${tag}.json`, + dest: `intl/${tag}/relative-time-format-data.json`, + }) +} + const copyTargetsDev = [ ...copyTargets, { diff --git a/package.json b/package.json index 6e73f61c2..48bf624c7 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "eth-json-rpc-filters": "^4.1.1", "eth-json-rpc-infura": "^4.0.2", "eth-json-rpc-middleware": "^5.0.1", - "eth-keyring-controller": "^6.0.0", + "eth-keyring-controller": "^6.0.1", "eth-method-registry": "^1.2.0", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", @@ -189,7 +189,7 @@ "@babel/register": "^7.5.5", "@metamask/eslint-config": "^1.1.0", "@metamask/forwarder": "^1.1.0", - "@metamask/test-dapp": "^2.1.1", + "@metamask/test-dapp": "^2.2.0", "@sentry/cli": "^1.49.0", "@storybook/addon-actions": "^5.3.14", "@storybook/addon-backgrounds": "^5.3.14", diff --git a/ui/app/components/app/menu-bar/menu-bar.js b/ui/app/components/app/menu-bar/menu-bar.js index 99bc50afa..282307f59 100644 --- a/ui/app/components/app/menu-bar/menu-bar.js +++ b/ui/app/components/app/menu-bar/menu-bar.js @@ -26,7 +26,7 @@ export default function MenuBar () { const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false) const origin = useSelector(getOriginOfCurrentTab) - const showStatus = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP && origin !== extension.runtime.id + const showStatus = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP && origin && origin !== extension.runtime.id return (
diff --git a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js index 268c973bf..feb6eaa9a 100644 --- a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js +++ b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js @@ -7,7 +7,13 @@ import CheckBox from '../../../ui/check-box' export default class PermissionPageContainerContent extends PureComponent { static propTypes = { - domainMetadata: PropTypes.object.isRequired, + domainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), selectedPermissions: PropTypes.object.isRequired, onPermissionToggle: PropTypes.func.isRequired, selectedIdentities: PropTypes.array, @@ -145,6 +151,7 @@ export default class PermissionPageContainerContent extends PureComponent { ? t('allowExternalExtensionTo', [domainMetadata.extensionId]) : t('allowThisSiteTo') } + siteOrigin={domainMetadata.origin} />
{ this.renderRequestedPermissions() } diff --git a/ui/app/components/app/permission-page-container/permission-page-container.component.js b/ui/app/components/app/permission-page-container/permission-page-container.component.js index 3020b82b5..0779f2226 100644 --- a/ui/app/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/app/components/app/permission-page-container/permission-page-container.component.js @@ -14,7 +14,13 @@ export default class PermissionPageContainer extends Component { allIdentitiesSelected: PropTypes.bool, request: PropTypes.object, requestMetadata: PropTypes.object, - targetDomainMetadata: PropTypes.object.isRequired, + targetDomainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } static defaultProps = { diff --git a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js index e32f8a0b1..c1bc5d775 100644 --- a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js +++ b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js @@ -5,25 +5,25 @@ import SiteIcon from '../../ui/site-icon' export default class PermissionsConnectHeader extends Component { static propTypes = { icon: PropTypes.string, - iconName: PropTypes.string, + iconName: PropTypes.string.isRequired, + siteOrigin: PropTypes.string.isRequired, headerTitle: PropTypes.node, headerText: PropTypes.string, } static defaultProps = { icon: null, - iconName: '', headerTitle: '', headerText: '', } renderHeaderIcon () { - const { icon, iconName } = this.props + const { icon, iconName, siteOrigin } = this.props return (
-
{iconName}
+
{siteOrigin}
) } diff --git a/ui/app/components/ui/page-container/index.scss b/ui/app/components/ui/page-container/index.scss index 21f6ca0c5..98bbcd9d1 100644 --- a/ui/app/components/ui/page-container/index.scss +++ b/ui/app/components/ui/page-container/index.scss @@ -46,6 +46,7 @@ flex: 1; display: flex; flex-direction: column; + min-height: 0; } &__footer { diff --git a/ui/app/components/ui/popover/index.scss b/ui/app/components/ui/popover/index.scss index 1742c7754..a34f99e50 100644 --- a/ui/app/components/ui/popover/index.scss +++ b/ui/app/components/ui/popover/index.scss @@ -73,7 +73,7 @@ width: 100%; height: 100%; background: black; - opacity: 20%; + opacity: .2; } &-content { diff --git a/ui/app/helpers/utils/i18n-helper.js b/ui/app/helpers/utils/i18n-helper.js index 496bd4524..01a369229 100644 --- a/ui/app/helpers/utils/i18n-helper.js +++ b/ui/app/helpers/utils/i18n-helper.js @@ -48,15 +48,17 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => { // perform substitutions if (hasSubstitutions) { const parts = phrase.split(/(\$\d)/g) - const partsToReplace = phrase.match(/(\$\d)/g) - - if (partsToReplace.length > substitutions.length) { - throw new Error(`Insufficient number of substitutions for message: '${phrase}'`) - } const substitutedParts = parts.map((part) => { const subMatch = part.match(/\$(\d)/) - return subMatch ? substitutions[Number(subMatch[1]) - 1] : part + if (!subMatch) { + return part + } + const substituteIndex = Number(subMatch[1]) - 1 + if (substitutions[substituteIndex]) { + return substitutions[substituteIndex] + } + throw new Error(`Insufficient number of substitutions for message: '${phrase}'`) }) phrase = hasReactSubstitutions @@ -77,3 +79,21 @@ export async function fetchLocale (localeCode) { } } +const relativeTimeFormatLocaleData = new Set() + +export async function loadRelativeTimeFormatLocaleData (localeCode) { + const languageTag = localeCode.split('_')[0] + if ( + Intl.RelativeTimeFormat && + typeof Intl.RelativeTimeFormat.__addLocaleData === 'function' && + !relativeTimeFormatLocaleData.has(languageTag) + ) { + const localeData = await fetchRelativeTimeFormatData(languageTag) + Intl.RelativeTimeFormat.__addLocaleData(localeData) + } +} + +async function fetchRelativeTimeFormatData (languageTag) { + const response = await window.fetch(`./intl/${languageTag}/relative-time-format-data.json`) + return await response.json() +} diff --git a/ui/app/hooks/useTransactionTimeRemaining.js b/ui/app/hooks/useTransactionTimeRemaining.js index c1d5ddd25..1f959c82f 100644 --- a/ui/app/hooks/useTransactionTimeRemaining.js +++ b/ui/app/hooks/useTransactionTimeRemaining.js @@ -50,7 +50,7 @@ export function useTransactionTimeRemaining ( const featureFlags = useSelector(getFeatureFlags) const transactionTimeFeatureActive = featureFlags?.transactionTime - const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style: 'narrow' }) + const rtf = new Intl.RelativeTimeFormat(locale.replace('_', '-'), { numeric: 'auto', style: 'narrow' }) // Memoize this value so it can be used as a dependency in the effect below const initialTimeEstimate = useMemo(() => { diff --git a/ui/app/pages/permissions-connect/choose-account/choose-account.component.js b/ui/app/pages/permissions-connect/choose-account/choose-account.component.js index 720fd0bb0..606b2ecc9 100644 --- a/ui/app/pages/permissions-connect/choose-account/choose-account.component.js +++ b/ui/app/pages/permissions-connect/choose-account/choose-account.component.js @@ -25,7 +25,13 @@ export default class ChooseAccount extends Component { cancelPermissionsRequest: PropTypes.func.isRequired, permissionsRequestId: PropTypes.string.isRequired, selectedAccountAddresses: PropTypes.object.isRequired, - targetDomainMetadata: PropTypes.object, + targetDomainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } state = { @@ -197,6 +203,7 @@ export default class ChooseAccount extends Component { ? t('selectAccounts') : t('connectAccountOrCreate') } + siteOrigin={targetDomainMetadata.origin} /> {this.renderAccountsListHeader()} {this.renderAccountsList()} diff --git a/ui/app/pages/permissions-connect/permissions-connect.component.js b/ui/app/pages/permissions-connect/permissions-connect.component.js index 068d846dd..4119e04a6 100644 --- a/ui/app/pages/permissions-connect/permissions-connect.component.js +++ b/ui/app/pages/permissions-connect/permissions-connect.component.js @@ -31,7 +31,13 @@ export default class PermissionConnect extends Component { connectPath: PropTypes.string.isRequired, confirmPermissionPath: PropTypes.string.isRequired, page: PropTypes.string.isRequired, - targetDomainMetadata: PropTypes.object, + targetDomainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } static defaultProps = { @@ -95,7 +101,7 @@ export default class PermissionConnect extends Component { if ( permissionsRequest && - savedMetadata.name !== targetDomainMetadata?.name + savedMetadata.origin !== targetDomainMetadata?.origin ) { return { targetDomainMetadata } } diff --git a/ui/app/pages/permissions-connect/permissions-connect.container.js b/ui/app/pages/permissions-connect/permissions-connect.container.js index 31a727cb5..30a76ec55 100644 --- a/ui/app/pages/permissions-connect/permissions-connect.container.js +++ b/ui/app/pages/permissions-connect/permissions-connect.container.js @@ -43,13 +43,20 @@ const mapStateToProps = (state, ownProps) => { const nativeCurrency = getNativeCurrency(state) const domainMetadata = getDomainMetadata(state) - const targetDomainMetadata = origin - ? domainMetadata[origin] || { - origin, - name: (new URL(origin)).hostname, - icon: null, + + let targetDomainMetadata = null + if (origin) { + if (domainMetadata[origin]) { + targetDomainMetadata = { ...domainMetadata[origin], origin } + } else { + const targetUrl = new URL(origin) + targetDomainMetadata = { + host: targetUrl.host, + name: targetUrl.hostname, + origin, + } } - : null + } const accountsWithLabels = getAccountsWithLabels(state) diff --git a/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js b/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js index 3795f348c..ac39de104 100644 --- a/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js +++ b/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js @@ -33,5 +33,11 @@ export default function PermissionsRedirect ({ domainMetadata }) { } PermissionsRedirect.propTypes = { - domainMetadata: PropTypes.object.isRequired, + domainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index f139d71a0..dd9188687 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -4,7 +4,7 @@ import getBuyEthUrl from '../../../app/scripts/lib/buy-eth-url' import { checksumAddress } from '../helpers/utils/util' import { calcTokenBalance, estimateGas } from '../pages/send/send.utils' import ethUtil from 'ethereumjs-util' -import { fetchLocale } from '../helpers/utils/i18n-helper' +import { fetchLocale, loadRelativeTimeFormatLocaleData } from '../helpers/utils/i18n-helper' import { getMethodDataAsync } from '../helpers/utils/transactions.util' import { fetchSymbolAndDecimals } from '../helpers/utils/token-util' import switchDirection from '../helpers/utils/switch-direction' @@ -1191,8 +1191,8 @@ export function showAccountDetail (address) { const activeTabOrigin = state.activeTab.origin const selectedAddress = getSelectedAddress(state) const permittedAccountsForCurrentTab = getPermittedAccountsForCurrentTab(state) - const currentTabIsConnectedToPreviousAddress = permittedAccountsForCurrentTab.includes(selectedAddress) - const currentTabIsConnectedToNextAddress = permittedAccountsForCurrentTab.includes(address) + const currentTabIsConnectedToPreviousAddress = Boolean(activeTabOrigin) && permittedAccountsForCurrentTab.includes(selectedAddress) + const currentTabIsConnectedToNextAddress = Boolean(activeTabOrigin) && permittedAccountsForCurrentTab.includes(address) const switchingToUnconnectedAddress = currentTabIsConnectedToPreviousAddress && !currentTabIsConnectedToNextAddress try { @@ -2012,8 +2012,9 @@ export function setIpfsGateway (val) { } export function updateCurrentLocale (key) { - return (dispatch) => { + return async (dispatch) => { dispatch(showLoadingIndication()) + await loadRelativeTimeFormatLocaleData(key) return fetchLocale(key) .then((localeMessages) => { log.debug(`background.setCurrentLocale`) diff --git a/ui/index.js b/ui/index.js index 8f868f317..44f5fd500 100644 --- a/ui/index.js +++ b/ui/index.js @@ -10,7 +10,7 @@ import txHelper from './lib/tx-helper' import { getEnvironmentType } from '../app/scripts/lib/util' import { ALERT_TYPES } from '../app/scripts/controllers/alert' import { ENVIRONMENT_TYPE_POPUP } from '../app/scripts/lib/enums' -import { fetchLocale } from './app/helpers/utils/i18n-helper' +import { fetchLocale, loadRelativeTimeFormatLocaleData } from './app/helpers/utils/i18n-helper' import switchDirection from './app/helpers/utils/switch-direction' import { getPermittedAccountsForCurrentTab, getSelectedAddress } from './app/selectors' import { ALERT_STATE } from './app/ducks/alerts/unconnected-account' @@ -48,6 +48,11 @@ async function startApp (metamaskState, backgroundConnection, opts) { : {} const enLocaleMessages = await fetchLocale('en') + await loadRelativeTimeFormatLocaleData('en') + if (metamaskState.currentLocale) { + await loadRelativeTimeFormatLocaleData(metamaskState.currentLocale) + } + if (metamaskState.textDirection === 'rtl') { await switchDirection('rtl') } diff --git a/yarn.lock b/yarn.lock index bf3cbe901..3220fb053 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1711,10 +1711,10 @@ pump "^3.0.0" safe-event-emitter "^1.0.1" -"@metamask/test-dapp@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@metamask/test-dapp/-/test-dapp-2.1.1.tgz#c3b79f93c8a698b0904171c5143d0bca1307653a" - integrity sha512-ed0Ma9TLc+wkQYJK5TWslphp58JSi4Rer84LK2RxW1p4aS2LsGKS30pKMFUegj+g9g//7tyh+uFE87pXu4vPkA== +"@metamask/test-dapp@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@metamask/test-dapp/-/test-dapp-2.2.0.tgz#e48ea589db7ab028ea222ae47ee814c4687e02c6" + integrity sha512-KX8ZhR/yLBO6yzx/9/BDxHdrTV6nNoOb8LvpUGm8GiLu6jOXETKZj0qfgvL5quWnQ/LRJMEXeuOZWjtXgcVofg== "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" @@ -10215,10 +10215,10 @@ eth-keyring-controller@^5.3.0, eth-keyring-controller@^5.6.1: loglevel "^1.5.0" obs-store "^4.0.3" -eth-keyring-controller@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/eth-keyring-controller/-/eth-keyring-controller-6.0.0.tgz#4629c7b9f08e9c2f24ecfa0a296fc40ea0fa98af" - integrity sha512-+tdXXwTklX0KX50YwlSriTU/6Xc0Ury0jmcp1mMcJfKSBFSKyWCmPmrhdkMxE9LRd4lbt4qx9LS5wZ3Ia05cLg== +eth-keyring-controller@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eth-keyring-controller/-/eth-keyring-controller-6.0.1.tgz#6a4cdd5802b0587320c711be6c1752b2a88221aa" + integrity sha512-60j71F1HgLcvwzg7U5R45bA/kgQSUlmiZrsUIIhW4qS7QOYqJn0OQ64enf0ZaxMMPVVcKSfCDersYJiqm/yrlw== dependencies: bip39 "^2.4.0" bluebird "^3.5.0"