From a76324f6d397c3e746ba501cfd858c4869cb0af7 Mon Sep 17 00:00:00 2001 From: Ellie Day Date: Sat, 23 Dec 2017 08:23:34 -0600 Subject: Add ExtensionStore and add basic store instance syncing to main controller --- app/scripts/background.js | 12 ++++++++++++ app/scripts/lib/extension-store.js | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 app/scripts/lib/extension-store.js (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index da022c490..45da2f6d0 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -4,6 +4,7 @@ const pump = require('pump') const log = require('loglevel') const extension = require('extensionizer') const LocalStorageStore = require('obs-store/lib/localStorage') +const ExtensionStore = require('./lib/extension-store') const storeTransform = require('obs-store/lib/transform') const asStream = require('obs-store/lib/asStream') const ExtensionPlatform = require('./platforms/extension') @@ -28,6 +29,7 @@ let popupIsOpen = false // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) +const extensionStore = new ExtensionStore() // initialization flow initialize().catch(log.error) @@ -45,8 +47,12 @@ async function initialize () { async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) + // fetch from extension store + const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) // read from disk let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) + // merge extension and versioned data + versionedData = { ...versionedData, ...extensionData } // migrate data versionedData = await migrator.migrateData(versionedData) // write to disk @@ -76,6 +82,7 @@ function setupController (initState) { pump( asStream(controller.store), storeTransform(versionifyData), + storeTransform(syncDataWithExtension), asStream(diskStore) ) @@ -85,6 +92,11 @@ function setupController (initState) { return versionedData } + function syncDataWithExtension(state) { + extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + return state + } + // // connect to other contexts // diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js new file mode 100644 index 000000000..a8b730a65 --- /dev/null +++ b/app/scripts/lib/extension-store.js @@ -0,0 +1,20 @@ +const extension = require('extensionizer') + +const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] + +module.exports = class ExtensionStore { + async fetch() { + return new Promise((resolve) => { + extension.storage.sync.get(KEYS_TO_SYNC, data => resolve(data)) + }) + } + async sync(state) { + const dataToSync = KEYS_TO_SYNC.reduce((result, key) => { + result[key] = state.data[key] + return result + }, {}) + return new Promise((resolve) => { + extension.storage.sync.set(dataToSync, () => resolve()) + }) + } +} -- cgit v1.2.3 From 7184db7632ef79d4bde0e643fdc1a4ee910c77fb Mon Sep 17 00:00:00 2001 From: Ellie Day Date: Tue, 2 Jan 2018 21:31:17 -0800 Subject: handle situation where storage.sync is disabled in certain versions of firefox --- app/scripts/background.js | 5 ++--- app/scripts/lib/extension-store.js | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 45da2f6d0..732f47590 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -47,11 +47,10 @@ async function initialize () { async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) - // fetch from extension store - const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) // read from disk let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) - // merge extension and versioned data + // fetch from extension store and merge in data + const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) versionedData = { ...versionedData, ...extensionData } // migrate data versionedData = await migrator.migrateData(versionedData) diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js index a8b730a65..dd0f82f36 100644 --- a/app/scripts/lib/extension-store.js +++ b/app/scripts/lib/extension-store.js @@ -1,11 +1,24 @@ const extension = require('extensionizer') const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] +const FIREFOX_SYNC_DISABLED_MESSAGE = 'Please set webextensions.storage.sync.enabled to true in about:config' + +const handleDisabledSyncAndResolve = (resolve, toResolve) => { + // Firefox 52 has sync available on extension.storage, but it is disabled by default + const lastError = extension.runtime.lastError + if (lastError && lastError.message.includes(FIREFOX_SYNC_DISABLED_MESSAGE)) { + resolve({}) + } else { + resolve(toResolve) + } +} module.exports = class ExtensionStore { async fetch() { return new Promise((resolve) => { - extension.storage.sync.get(KEYS_TO_SYNC, data => resolve(data)) + extension.storage.sync.get(KEYS_TO_SYNC, (data) => { + handleDisabledSyncAndResolve(resolve, data) + }) }) } async sync(state) { @@ -14,7 +27,9 @@ module.exports = class ExtensionStore { return result }, {}) return new Promise((resolve) => { - extension.storage.sync.set(dataToSync, () => resolve()) + extension.storage.sync.set(dataToSync, () => { + handleDisabledSyncAndResolve(resolve) + }) }) } } -- cgit v1.2.3 From 3c6a5b16ad37c83f548028d5b6fa3d0f75293ca5 Mon Sep 17 00:00:00 2001 From: Ellie Day Date: Tue, 2 Jan 2018 21:53:11 -0800 Subject: conditionally use extension store if supported or enabled --- app/scripts/background.js | 12 +++++++++--- app/scripts/lib/extension-store.js | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 732f47590..d9a2b0a6e 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -50,8 +50,12 @@ async function loadStateFromPersistence () { // read from disk let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) // fetch from extension store and merge in data - const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) - versionedData = { ...versionedData, ...extensionData } + + if (extensionStore.isSupported && extensionStore.isEnabled) { + const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + versionedData = { ...versionedData, ...extensionData } + } + // migrate data versionedData = await migrator.migrateData(versionedData) // write to disk @@ -92,7 +96,9 @@ function setupController (initState) { } function syncDataWithExtension(state) { - extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + if (extensionStore.isSupported && extensionStore.isEnabled) { + extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + } return state } diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js index dd0f82f36..67ee71f16 100644 --- a/app/scripts/lib/extension-store.js +++ b/app/scripts/lib/extension-store.js @@ -14,6 +14,10 @@ const handleDisabledSyncAndResolve = (resolve, toResolve) => { } module.exports = class ExtensionStore { + constructor() { + this.isSupported = !!(extension.storage.sync) + this.isEnabled = true // TODO: get value from user settings + } async fetch() { return new Promise((resolve) => { extension.storage.sync.get(KEYS_TO_SYNC, (data) => { -- cgit v1.2.3 From bad70eb1b328aa911a2523ccab642d7607161b4b Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Mon, 22 Jan 2018 23:48:03 -1000 Subject: first steps to i18n --- app/_locales/en/messages.json | 167 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 166 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 8c28f1c43..6967a44d2 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -6,5 +6,170 @@ "appDescription": { "message": "Ethereum Identity Management", "description": "The description of the application" - } + }, + "encryptNewDen": { + "message": "Encrypt your new DEN" + }, + "denExplainer": { + "message": "Your DEN is your password-encrypted storage within MetaMask." + }, + "importDen": { + "message": "Import Existing DEN" + }, + "createDen": { + "message": "Create" + }, + "newPassword": { + "message": "New Password (min 8 chars)" + }, + "confirmPassword": { + "message": "Confirm Password" + }, + "passwordMismatch": { + "message": "passwords don't match" + }, + "passwordShort": { + "message": "password not long enough" + }, + "myAccounts": { + "message": "My Accounts" + }, + "logout": { + "message": "Log out" + }, + "createAccount": { + "message": "Create Account" + }, + "importAccount": { + "message": "Import Account" + }, + "account": { + "message": "Account:" + }, + "infoHelp": { + "message": "Info & Help" + }, + "settings": { + "message": "Settings" + }, + "importedCaps": { + "message": "IMPORTED" + }, + "saveButton": { + "message": "SAVE" + }, + "cancelButton": { + "message": "CANCEL" + }, + "signButton": { + "message": "SIGN" + }, + "revert": { + "message": "Revert" + }, + "gasLimit": { + "message": "Gas Limit" + }, + "gasLimitCalculation": { + "message": "We calculate the suggested gas limit based on network success rates." + }, + "gasPrice": { + "message": "Gas Price (GWEI)" + }, + "gasPriceCalculation": { + "message": "We calculate the suggested gas prices based on network success rates." + }, + "customGas": { + "message": "Customize Gas" + }, + "balanceIsInsufficientGas": { + "message": "Insufficient balance for current gas total" + }, + "gasLimitTooLow": { + "message": "Gas limit must be at least 21000" + }, + "editButton": { + "message": "Edit" + }, + "looseCaps": { + "message": "LOOSE" + }, + "addToken": "Add Token", + "exportPrivateKey": "Export Private Key", + "copyAddress": "Copy Address to clipboard", + "etherscanView": "View account on Etherscan", + "qrCode": "Show QR Code", + "accDetails": "Account Details", + "networks": "Networks", + "defaultNetwork": "The default network for Ether transactions is Main Net.", + "mainnet": "Main Ethereum Network", + "unknownNetwork": "Unknown Private Network", + "rinkeby": "Rinkeby Test Network", + "kovan": "Kovan Test Network", + "ropsten": "Ropsten Test Network", + "localhost": "Localhost 8545", + "customRPC": "Custom RPC", + "hideToken": "Hide Token", + "copiedClipboard": "Copied to Clipboard", + "detailsCaps": "DETAILS", + "sendButton": "SEND", + "depositButton": "DEPOSIT", + "notStarted": "Not Started", + "noTransactions": "No Transactions", + "contractPublished": "Contract Published", + "noTransactionHistory": "No transaction history.", + "warning": "Warning", + "failed": "Failed", + "rejected": "Rejected", + "sigRequested": "Signature Requested", + "yourSigRequested": "Your signature is being requested", + "balance": "Balance:", + "retryWithMoreGas": "Retry with a higher gas price here", + "takesTooLong": "Taking too long?", + "transactionNumber": "Transaction Number", + "loadingTokens": "Loading Tokens...", + "troubleTokenBalances": "We had trouble loading your token balances. You can view them ", + "here": "here", + "message": "Message", + "signNotice": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. ", + "youSign": "You are signing:", + "conversionProgress": "Conversion in progress", + "noDeposits": "No deposits received", + "fromShapeShift": "From ShapeShift", + "invalidRequest": "Invalid Request", + "status": "Status", + "limit": "Limit", + "exchangeRate": "Exchange Rate", + "min": "Minimum", + "available": "Available", + "unavailable": "Unavailable", + "depositBTC": "Deposit your BTC to the address below:", + "deposit": "Deposit", + "receive": "Receive", + "refundAddress": "Your Refund Address", + "buyButton": "Buy", + "signMessage": "Sign Message", + "youSignCaps": "YOU ARE SIGNING", + "messageCaps": "MESSAGE", + "readMore": "Read more here.", + "cancel": "Cancel", + "sign": "Sign", + "accept": "Accept", + "attemptingConnect": "Attempting to connect to blockchain.", + "privateNetwork": "Private Network", + "invalidInput": "Invalid input.", + "noAddressForName": "No address has been set for this name.", + "clickCopy": "Click to Copy", + "copyButton": " Copy ", + "copiedButton": "Copied", + "copy": "Copy", + "copiedExclamation": "Copied!", + "continueToCoinbase": "Continue to Coinbase", + "depositEth": "Deposit Eth", + "selectService": "Select Service", + "unknownNetworkId": "Unknown network ID", + "borrowDharma": "Borrow With Dharma (Beta)", + "exportPrivateKeyWarning": "Export private keys at your own risk.", + "confirmPasswordSmall": "confirm password", + "submit": "Submit", } -- cgit v1.2.3 From 03c64ba8a646cbc5a62f2b2a8c5881bb4a4bda60 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 23 Jan 2018 15:45:33 -0800 Subject: Add unlimitedStorage option to manifest --- app/manifest.json | 1 + 1 file changed, 1 insertion(+) (limited to 'app') diff --git a/app/manifest.json b/app/manifest.json index d795a225a..13ba074e7 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -60,6 +60,7 @@ "http://localhost:8545/", "https://*.infura.io/" ], + "unlimitedStorage": true, "web_accessible_resources": [ "scripts/inpage.js" ], -- cgit v1.2.3 From 456dfdb9fdc0b7b0637d50808beb85ae33602f5b Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 23 Jan 2018 16:26:50 -0800 Subject: Modify @heyellieday's work to use storage.local to replace main storage --- app/scripts/background.js | 15 ++++++++------- app/scripts/lib/local-store.js | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 app/scripts/lib/local-store.js (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index d9a2b0a6e..9790129aa 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -4,7 +4,7 @@ const pump = require('pump') const log = require('loglevel') const extension = require('extensionizer') const LocalStorageStore = require('obs-store/lib/localStorage') -const ExtensionStore = require('./lib/extension-store') +const LocalStore = require('./lib/local-store') const storeTransform = require('obs-store/lib/transform') const asStream = require('obs-store/lib/asStream') const ExtensionPlatform = require('./platforms/extension') @@ -29,7 +29,7 @@ let popupIsOpen = false // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) -const extensionStore = new ExtensionStore() +const localStore = new LocalStore() // initialization flow initialize().catch(log.error) @@ -51,9 +51,10 @@ async function loadStateFromPersistence () { let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) // fetch from extension store and merge in data - if (extensionStore.isSupported && extensionStore.isEnabled) { - const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) - versionedData = { ...versionedData, ...extensionData } + if (localStore.isSupported) { + const localData = await localStore.get() + // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + versionedData = localData || versionedData } // migrate data @@ -96,8 +97,8 @@ function setupController (initState) { } function syncDataWithExtension(state) { - if (extensionStore.isSupported && extensionStore.isEnabled) { - extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + if (localStore.isSupported) { + localStore.set(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) } return state } diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js new file mode 100644 index 000000000..32faac96b --- /dev/null +++ b/app/scripts/lib/local-store.js @@ -0,0 +1,25 @@ +// We should not rely on local storage in an extension! +// We should use this instead! +// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local + +const extension = require('extensionizer') +const STORAGE_KEY = 'metamask-config' + +module.exports = class ExtensionStore { + constructor() { + this.isSupported = !!(extension.storage.local) + if (!this.isSupported) { + log.error('Storage local API not available.') + } + } + async get() { + return new Promise((resolve) => { + extension.storage.local.get(STORAGE_KEY, resolve) + }) + } + async set(state) { + return new Promise((resolve) => { + extension.storage.local.set(state, resolve) + }) + } +} -- cgit v1.2.3 From 99898ac77594d8fe6d4d2aa5bc3e3ba6492f4a10 Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Tue, 23 Jan 2018 22:14:47 -1000 Subject: better organization of locale file; i18n in more view files --- app/_locales/en/messages.json | 631 +++++++++++++++++++++++++++++++++--------- 1 file changed, 506 insertions(+), 125 deletions(-) (limited to 'app') diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 6967a44d2..54f266318 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1,71 +1,224 @@ { - "appName": { - "message": "MetaMask", - "description": "The name of the application" + "accept": { + "message": "Accept" + }, + "account": { + "message": "Account:" + }, + "accDetails": { + "message": "Account Details" + }, + "accountName": { + "message": "Account Name" + }, + "address": { + "message": "Address" + }, + "addToken": { + "message": "Add Token" + }, + "amountPlusGas": { + "message": "Amount + Gas" }, "appDescription": { "message": "Ethereum Identity Management", "description": "The description of the application" }, - "encryptNewDen": { - "message": "Encrypt your new DEN" + "appName": { + "message": "MetaMask", + "description": "The name of the application" }, - "denExplainer": { - "message": "Your DEN is your password-encrypted storage within MetaMask." + "attemptingConnect": { + "message": "Attempting to connect to blockchain." }, - "importDen": { - "message": "Import Existing DEN" + "available": { + "message": "Available" }, - "createDen": { - "message": "Create" + "back": { + "message": "Back" }, - "newPassword": { - "message": "New Password (min 8 chars)" + "balance": { + "message": "Balance:" + }, + "balanceIsInsufficientGas": { + "message": "Insufficient balance for current gas total" + }, + "borrowDharma": { + "message": "Borrow With Dharma (Beta)" + }, + "buyButton": { + "message": "Buy" + }, + "buyCoinbase": { + "message": "Buy on Coinbase" + }, + "buyCoinbaseExplainer": { + "message": "Coinbase is the world’s most popular way to buy and sell bitcoin, ethereum, and litecoin." + }, + "cancel": { + "message": "Cancel" + }, + "cancelCaps": { + "message": "CANCEL" + }, + "clickCopy": { + "message": "Click to Copy" + }, + "confirm": { + "message": "Confirm" + }, + "confirmCaps": { + "message": "CONFIRM" + }, + "confirmContract": { + "message": "Confirm Contract" }, "confirmPassword": { "message": "Confirm Password" }, - "passwordMismatch": { - "message": "passwords don't match" + "confirmPasswordSmall": { + "message": "confirm password" }, - "passwordShort": { - "message": "password not long enough" + "continueToCoinbase": { + "message": "Continue to Coinbase" }, - "myAccounts": { - "message": "My Accounts" + "contractPublished": { + "message": "Contract Published" }, - "logout": { - "message": "Log out" + "conversionProgress": { + "message": "Conversion in progress" + }, + "copiedButton": { + "message": "Copied" + }, + "copiedClipboard": { + "message": "Copied to Clipboard" + }, + "copiedExclamation": { + "message": "Copied!" + }, + "copy": { + "message": "Copy" + }, + "copyAddress": { + "message": "Copy Address to clipboard" + }, + "copyButton": { + "message": " Copy " + }, + "copyPrivateKey": { + "message": "This is your private key (click to copy)" }, "createAccount": { "message": "Create Account" }, - "importAccount": { - "message": "Import Account" + "createCaps": { + "message": "CREATE" }, - "account": { - "message": "Account:" + "createDen": { + "message": "Create" }, - "infoHelp": { - "message": "Info & Help" + "customGas": { + "message": "Customize Gas" }, - "settings": { - "message": "Settings" + "customize": { + "message": "Customize" }, - "importedCaps": { - "message": "IMPORTED" + "customRPC": { + "message": "Custom RPC" }, - "saveButton": { - "message": "SAVE" + "defaultNetwork": { + "message": "The default network for Ether transactions is Main Net." }, - "cancelButton": { - "message": "CANCEL" + "denExplainer": { + "message": "Your DEN is your password-encrypted storage within MetaMask." }, - "signButton": { - "message": "SIGN" + "deposit": { + "message": "Deposit" }, - "revert": { - "message": "Revert" + "depositBTC": { + "message": "Deposit your BTC to the address below:" + }, + "depositButton": { + "message": "DEPOSIT" + }, + "depositEth": { + "message": "Deposit Eth" + }, + "depositEther": { + "message": "Deposit Ether" + }, + "depositFiat": { + "message": "Deposit with Fiat" + }, + "depositFromAccount": { + "message": "Deposit from another account" + }, + "depositShapeShift": { + "message": "Deposit with ShapeShift" + }, + "depositShapeShiftExplainer": { + "message": "If you own other cryptocurrencies, you can trade and deposit Ether directly into your MetaMask wallet. No Account Needed." + }, + "detailsCaps": { + "message": "DETAILS" + }, + "directDeposit": { + "message": "Direct Deposit" + }, + "directDepositEther": { + "message": "Directly Deposit Ether" + }, + "directDepositEtherExplainer": { + "message": "If you already have some Ether, the quickest way to get Ether in your new wallet by direct deposit." + }, + "done": { + "message": "Done" + }, + "editAccountName": { + "message": "Edit Account Name" + }, + "editCaps": { + "message": "EDIT" + }, + "encryptNewDen": { + "message": "Encrypt your new DEN" + }, + "enterPassword": { + "message": "Enter password" + }, + "etherscanView": { + "message": "View account on Etherscan" + }, + "exchangeRate": { + "message": "Exchange Rate" + }, + "exportPrivateKey": { + "message": "Export Private Key" + }, + "exportPrivateKeyLower": { + "message": "Export private key" + }, + "exportPrivateKeyWarning": { + "message": "Export private keys at your own risk." + }, + "failed": { + "message": "Failed" + }, + "fileImportFail": { + "message": "File import not working? Click here!" + }, + "from": { + "message": "From" + }, + "fromShapeShift": { + "message": "From ShapeShift" + }, + "gasFee": { + "message": "Gas Fee" + }, + "gasFeeSpecific": { + "message": "Gas fee:" }, "gasLimit": { "message": "Gas Limit" @@ -73,103 +226,331 @@ "gasLimitCalculation": { "message": "We calculate the suggested gas limit based on network success rates." }, + "gasLimitRequired": { + "message": "Gas Limit Required" + }, + "gasLimitTooLow": { + "message": "Gas limit must be at least 21000" + }, "gasPrice": { "message": "Gas Price (GWEI)" }, "gasPriceCalculation": { "message": "We calculate the suggested gas prices based on network success rates." }, - "customGas": { - "message": "Customize Gas" + "gasPriceRequired": { + "message": "Gas Price Required" }, - "balanceIsInsufficientGas": { - "message": "Insufficient balance for current gas total" + "getEther": { + "message": "Get Ether" }, - "gasLimitTooLow": { - "message": "Gas limit must be at least 21000" + "here": { + "message": "here" + }, + "hideCaps": { + "message": "HIDE" + }, + "hideToken": { + "message": "Hide Token" + }, + "hideTokenPrompt": { + "message": "Hide Token?" + }, + "howToDeposit": { + "message": "How would you like to deposit Ether?" + }, + "import": { + "message": "Import" }, - "editButton": { - "message": "Edit" + "importAccount": { + "message": "Import Account" + }, + "importAnAccount": { + "message": "Import an account" + }, + "importCaps": { + "message": "IMPORT" + }, + "importDen": { + "message": "Import Existing DEN" + }, + "importedCaps": { + "message": "IMPORTED" + }, + "infoHelp": { + "message": "Info & Help" + }, + "invalidAddress": { + "message": "Invalid address" + }, + "invalidGasParams": { + "message": "Invalid Gas Parameters" + }, + "invalidInput": { + "message": "Invalid input." + }, + "invalidRequest": { + "message": "Invalid Request" + }, + "kovan": { + "message": "Kovan Test Network" + }, + "limit": { + "message": "Limit" + }, + "loading": { + "message": "Loading..." + }, + "loadingTokens": { + "message": "Loading Tokens..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "logout": { + "message": "Log out" }, "looseCaps": { "message": "LOOSE" }, - "addToken": "Add Token", - "exportPrivateKey": "Export Private Key", - "copyAddress": "Copy Address to clipboard", - "etherscanView": "View account on Etherscan", - "qrCode": "Show QR Code", - "accDetails": "Account Details", - "networks": "Networks", - "defaultNetwork": "The default network for Ether transactions is Main Net.", - "mainnet": "Main Ethereum Network", - "unknownNetwork": "Unknown Private Network", - "rinkeby": "Rinkeby Test Network", - "kovan": "Kovan Test Network", - "ropsten": "Ropsten Test Network", - "localhost": "Localhost 8545", - "customRPC": "Custom RPC", - "hideToken": "Hide Token", - "copiedClipboard": "Copied to Clipboard", - "detailsCaps": "DETAILS", - "sendButton": "SEND", - "depositButton": "DEPOSIT", - "notStarted": "Not Started", - "noTransactions": "No Transactions", - "contractPublished": "Contract Published", - "noTransactionHistory": "No transaction history.", - "warning": "Warning", - "failed": "Failed", - "rejected": "Rejected", - "sigRequested": "Signature Requested", - "yourSigRequested": "Your signature is being requested", - "balance": "Balance:", - "retryWithMoreGas": "Retry with a higher gas price here", - "takesTooLong": "Taking too long?", - "transactionNumber": "Transaction Number", - "loadingTokens": "Loading Tokens...", - "troubleTokenBalances": "We had trouble loading your token balances. You can view them ", - "here": "here", - "message": "Message", - "signNotice": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. ", - "youSign": "You are signing:", - "conversionProgress": "Conversion in progress", - "noDeposits": "No deposits received", - "fromShapeShift": "From ShapeShift", - "invalidRequest": "Invalid Request", - "status": "Status", - "limit": "Limit", - "exchangeRate": "Exchange Rate", - "min": "Minimum", - "available": "Available", - "unavailable": "Unavailable", - "depositBTC": "Deposit your BTC to the address below:", - "deposit": "Deposit", - "receive": "Receive", - "refundAddress": "Your Refund Address", - "buyButton": "Buy", - "signMessage": "Sign Message", - "youSignCaps": "YOU ARE SIGNING", - "messageCaps": "MESSAGE", - "readMore": "Read more here.", - "cancel": "Cancel", - "sign": "Sign", - "accept": "Accept", - "attemptingConnect": "Attempting to connect to blockchain.", - "privateNetwork": "Private Network", - "invalidInput": "Invalid input.", - "noAddressForName": "No address has been set for this name.", - "clickCopy": "Click to Copy", - "copyButton": " Copy ", - "copiedButton": "Copied", - "copy": "Copy", - "copiedExclamation": "Copied!", - "continueToCoinbase": "Continue to Coinbase", - "depositEth": "Deposit Eth", - "selectService": "Select Service", - "unknownNetworkId": "Unknown network ID", - "borrowDharma": "Borrow With Dharma (Beta)", - "exportPrivateKeyWarning": "Export private keys at your own risk.", - "confirmPasswordSmall": "confirm password", - "submit": "Submit", + "mainnet": { + "message": "Main Ethereum Network" + }, + "message": { + "message": "Message" + }, + "messageCaps": { + "message": "MESSAGE" + }, + "min": { + "message": "Minimum" + }, + "myAccounts": { + "message": "My Accounts" + }, + "needEtherInWallet": { + "message": "To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet." + }, + "needImportFile": { + "message": "You must select a file to import." + }, + "needImportPassword": { + "message": "You must enter a password for the selected file." + }, + "networks": { + "message": "Networks" + }, + "newAccount": { + "message": "New Account" + }, + "newContract": { + "message": "New Contract" + }, + "newPassword": { + "message": "New Password (min 8 chars)" + }, + "newRecipient": { + "message": "New Recipient" + }, + "next": { + "message": "Next" + }, + "noAddressForName": { + "message": "No address has been set for this name." + }, + "noDeposits": { + "message": "No deposits received" + }, + "noTransactionHistory": { + "message": "No transaction history." + }, + "noTransactions": { + "message": "No Transactions" + }, + "notStarted": { + "message": "Not Started" + }, + "oldUI": { + "message": "Old UI" + }, + "oldUIMessage": { + "message": "You have returned to the old UI. You can switch back to the New UI through the option in the top right dropdown menu." + }, + "or": { + "message": "or" + }, + "passwordMismatch": { + "message": "passwords don't match" + }, + "passwordShort": { + "message": "password not long enough" + }, + "pastePrivateKey": { + "message": "Paste your private key string here:" + }, + "pasteSeed": { + "message": "Paste your seed phrase here!" + }, + "privateKeyWarning": { + "message": "Warning: Never disclose this key. Anyone with your private keys can take steal any assets held in your account." + }, + "privateNetwork": { + "message": "Private Network" + }, + "qrCode": { + "message": "Show QR Code" + }, + "readdToken": { + "message": "You can add this token back in the future by going go to “Add token” in your accounts options menu." + }, + "readMore": { + "message": "Read more here." + }, + "receive": { + "message": "Receive" + }, + "recipientAddress": { + "message": "Recipient Address" + }, + "refundAddress": { + "message": "Your Refund Address" + }, + "rejected": { + "message": "Rejected" + }, + "required": { + "message": "Required" + }, + "retryWithMoreGas": { + "message": "Retry with a higher gas price here" + }, + "revert": { + "message": "Revert" + }, + "rinkeby": { + "message": "Rinkeby Test Network" + }, + "ropsten": { + "message": "Ropsten Test Network" + }, + "sampleAccountName": { + "message": "E.g. My new account" + }, + "saveCaps": { + "message": "SAVE" + }, + "selectService": { + "message": "Select Service" + }, + "sendButton": { + "message": "SEND" + }, + "sendTokens": { + "message": "Send Tokens" + }, + "sendTokensAnywhere": { + "message": "Send Tokens to anyone with an Ethereum account" + }, + "settings": { + "message": "Settings" + }, + "shapeshiftBuy": { + "message": "Buy with Shapeshift" + }, + "showPrivateKeys": { + "message": "Show Private Keys" + }, + "sign": { + "message": "Sign" + }, + "signCaps": { + "message": "SIGN" + }, + "signMessage": { + "message": "Sign Message" + }, + "signNotice": { + "message": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. " + }, + "sigRequested": { + "message": "Signature Requested" + }, + "status": { + "message": "Status" + }, + "submit": { + "message": "Submit" + }, + "takesTooLong": { + "message": "Taking too long?" + }, + "testFaucet": { + "message": "Test Faucet" + }, + "to": { + "message": "To" + }, + "tokenBalance": { + "message": "Your Token Balance is:" + }, + "toSpecific": { + "message": "To:" + }, + "total": { + "message": "Total" + }, + "transactionMemo": { + "message": "Transaction memo (optional)" + }, + "transactionNumber": { + "message": "Transaction Number" + }, + "transfers": { + "message": "Transfers" + }, + "troubleTokenBalances": { + "message": "We had trouble loading your token balances. You can view them " + }, + "typePassword": { + "message": "Type Your Password" + }, + "uiWelcome": { + "message": "Welcome to the New UI (Beta)" + }, + "uiWelcomeMessage": { + "message": "You are now using the new Metamask UI. Take a look around, try out new features like sending tokens, and let us know if you have any issues." + }, + "unavailable": { + "message": "Unavailable" + }, + "unknown": { + "message": "Unknown" + }, + "unknownNetwork": { + "message": "Unknown Private Network" + }, + "unknownNetworkId": { + "message": "Unknown network ID" + }, + "usedByClients": { + "message": "Used by a variety of different clients" + }, + "viewAccount": { + "message": "View Account" + }, + "warning": { + "message": "Warning" + }, + "whatsThis": { + "message": "What's this?" + }, + "yourSigRequested": { + "message": "Your signature is being requested" + }, + "youSign": { + "message": "You are signing:" + }, + "youSignCaps": { + "message": "YOU ARE SIGNING" + } } -- cgit v1.2.3 From 0164030e56b1db8117a1a0bdff91987321b2cd1a Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Jan 2018 09:41:32 -0330 Subject: Handle errors when getting and setting to localStore. --- app/scripts/background.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 280c28d70..88600bf1e 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -57,7 +57,13 @@ async function loadStateFromPersistence () { // fetch from extension store and merge in data if (localStore.isSupported) { - const localData = await localStore.get() + let localData + try { + localData = await localStore.get() + } catch (err) { + log.error('error fetching state from local store:', err) + } + // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) versionedData = Object.keys(localData).length > 0 ? localData : versionedData } @@ -113,7 +119,11 @@ function setupController (initState) { function syncDataWithExtension(state) { if (localStore.isSupported) { - localStore.set(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + try { + localStore.set(state) + } catch (err) { + log.error('error setting state in local store:', err) + } } return state } -- cgit v1.2.3 From b7ae77f57a0e2bc68e9548364baa120805a1420c Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Jan 2018 09:43:20 -0330 Subject: Check that extension.storage exists before attempting to call methods on it. --- app/scripts/lib/extension-store.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js index 67ee71f16..4a970321c 100644 --- a/app/scripts/lib/extension-store.js +++ b/app/scripts/lib/extension-store.js @@ -15,12 +15,12 @@ const handleDisabledSyncAndResolve = (resolve, toResolve) => { module.exports = class ExtensionStore { constructor() { - this.isSupported = !!(extension.storage.sync) + this.isSupported = !!(extension.storage && extension.storage.sync) this.isEnabled = true // TODO: get value from user settings } async fetch() { return new Promise((resolve) => { - extension.storage.sync.get(KEYS_TO_SYNC, (data) => { + extension.storage && extension.storage.sync.get(KEYS_TO_SYNC, (data) => { handleDisabledSyncAndResolve(resolve, data) }) }) @@ -31,7 +31,7 @@ module.exports = class ExtensionStore { return result }, {}) return new Promise((resolve) => { - extension.storage.sync.set(dataToSync, () => { + extension.storage && extension.storage.sync.set(dataToSync, () => { handleDisabledSyncAndResolve(resolve) }) }) -- cgit v1.2.3 From dd80bd48babc1bfebf91ac2350491b06971b1fc1 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 11:36:15 -0800 Subject: Corrected unlimitedStorage permission --- app/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/manifest.json b/app/manifest.json index 13ba074e7..114586d0f 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -56,11 +56,11 @@ ], "permissions": [ "storage", + "unlimitedStorage", "clipboardWrite", "http://localhost:8545/", "https://*.infura.io/" ], - "unlimitedStorage": true, "web_accessible_resources": [ "scripts/inpage.js" ], -- cgit v1.2.3 From f09d72fa2aa88f0def76d228cb7d8eab29e3b092 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 11:36:42 -0800 Subject: Remove extension-store since we aren't using it yet --- app/scripts/lib/extension-store.js | 39 -------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 app/scripts/lib/extension-store.js (limited to 'app') diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js deleted file mode 100644 index 4a970321c..000000000 --- a/app/scripts/lib/extension-store.js +++ /dev/null @@ -1,39 +0,0 @@ -const extension = require('extensionizer') - -const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] -const FIREFOX_SYNC_DISABLED_MESSAGE = 'Please set webextensions.storage.sync.enabled to true in about:config' - -const handleDisabledSyncAndResolve = (resolve, toResolve) => { - // Firefox 52 has sync available on extension.storage, but it is disabled by default - const lastError = extension.runtime.lastError - if (lastError && lastError.message.includes(FIREFOX_SYNC_DISABLED_MESSAGE)) { - resolve({}) - } else { - resolve(toResolve) - } -} - -module.exports = class ExtensionStore { - constructor() { - this.isSupported = !!(extension.storage && extension.storage.sync) - this.isEnabled = true // TODO: get value from user settings - } - async fetch() { - return new Promise((resolve) => { - extension.storage && extension.storage.sync.get(KEYS_TO_SYNC, (data) => { - handleDisabledSyncAndResolve(resolve, data) - }) - }) - } - async sync(state) { - const dataToSync = KEYS_TO_SYNC.reduce((result, key) => { - result[key] = state.data[key] - return result - }, {}) - return new Promise((resolve) => { - extension.storage && extension.storage.sync.set(dataToSync, () => { - handleDisabledSyncAndResolve(resolve) - }) - }) - } -} -- cgit v1.2.3 From b281a5275983c4e2d924ba696c4885fd779d2c44 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Jan 2018 16:49:12 -0330 Subject: Remove already handled TODO comment. --- app/scripts/background.js | 1 - 1 file changed, 1 deletion(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 88600bf1e..3e04a31b3 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -64,7 +64,6 @@ async function loadStateFromPersistence () { log.error('error fetching state from local store:', err) } - // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) versionedData = Object.keys(localData).length > 0 ? localData : versionedData } -- cgit v1.2.3 From cd5eaa4393a122247295c7627a3fad3e678bea30 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 13:05:13 -0800 Subject: Remove redundant async modifiers --- app/scripts/lib/local-store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 32faac96b..9114364b6 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -12,12 +12,12 @@ module.exports = class ExtensionStore { log.error('Storage local API not available.') } } - async get() { + get() { return new Promise((resolve) => { extension.storage.local.get(STORAGE_KEY, resolve) }) } - async set(state) { + set(state) { return new Promise((resolve) => { extension.storage.local.set(state, resolve) }) -- cgit v1.2.3 From 76521cf7399c1e694a7202dcb9725ed5e1e2a0d7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 15:03:16 -0800 Subject: Fix retrieval of object --- app/scripts/lib/local-store.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 9114364b6..9e8d8db37 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -3,7 +3,6 @@ // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local const extension = require('extensionizer') -const STORAGE_KEY = 'metamask-config' module.exports = class ExtensionStore { constructor() { @@ -14,7 +13,7 @@ module.exports = class ExtensionStore { } get() { return new Promise((resolve) => { - extension.storage.local.get(STORAGE_KEY, resolve) + extension.storage.local.get(null, resolve) }) } set(state) { -- cgit v1.2.3 From 2f13790653cb20d9d967700133df6cf31ff02d14 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 15:28:15 -0800 Subject: Remove local storage writes, add log --- app/scripts/background.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 3e04a31b3..a77763c41 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -35,6 +35,7 @@ let popupIsOpen = false // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) const localStore = new LocalStore() +let versionedData // initialization flow initialize().catch(log.error) @@ -53,7 +54,7 @@ async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) // read from disk - let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) + versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) // fetch from extension store and merge in data if (localStore.isSupported) { @@ -64,13 +65,24 @@ async function loadStateFromPersistence () { log.error('error fetching state from local store:', err) } - versionedData = Object.keys(localData).length > 0 ? localData : versionedData + console.log('Comparing localdata and versionedData') + console.dir({ localData }) + + if (Object.keys(localData).length > 0) { + console.log('using the local store data') + versionedData = localData + } } // migrate data versionedData = await migrator.migrateData(versionedData) + // write to disk - diskStore.putState(versionedData) + localStore.set(versionedData) + .catch((reason) => { + log.error('Problem saving migrated data', versionedData) + }) + // return just the data return versionedData.data } @@ -107,11 +119,9 @@ function setupController (initState) { asStream(controller.store), storeTransform(versionifyData), storeTransform(syncDataWithExtension), - asStream(diskStore) ) function versionifyData (state) { - const versionedData = diskStore.getState() versionedData.data = state return versionedData } @@ -119,6 +129,7 @@ function setupController (initState) { function syncDataWithExtension(state) { if (localStore.isSupported) { try { + console.log('persisting state', state) localStore.set(state) } catch (err) { log.error('error setting state in local store:', err) -- cgit v1.2.3 From ceebc6caa4f3eab1cf6c9ec8f47dc8bd450ca4a9 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 25 Jan 2018 13:01:03 -0800 Subject: Debounce storage to avoid crashing pump --- app/scripts/background.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index a77763c41..2a8efd844 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -1,6 +1,7 @@ const urlUtil = require('url') const endOfStream = require('end-of-stream') const pump = require('pump') +const debounce = require('debounce-stream') const log = require('loglevel') const extension = require('extensionizer') const LocalStorageStore = require('obs-store/lib/localStorage') @@ -65,11 +66,7 @@ async function loadStateFromPersistence () { log.error('error fetching state from local store:', err) } - console.log('Comparing localdata and versionedData') - console.dir({ localData }) - if (Object.keys(localData).length > 0) { - console.log('using the local store data') versionedData = localData } } @@ -117,8 +114,12 @@ function setupController (initState) { // setup state persistence pump( asStream(controller.store), + debounce(200), storeTransform(versionifyData), storeTransform(syncDataWithExtension), + (error) => { + log.error('pump hit error', error) + } ) function versionifyData (state) { @@ -126,15 +127,14 @@ function setupController (initState) { return versionedData } - function syncDataWithExtension(state) { + async function syncDataWithExtension(state) { if (localStore.isSupported) { try { - console.log('persisting state', state) - localStore.set(state) + await localStore.set(state) } catch (err) { log.error('error setting state in local store:', err) } - } + } else { log.error('local store not supported') } return state } -- cgit v1.2.3 From 8ba64c657ff801425c06db166e2c9a06289047de Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 25 Jan 2018 15:38:43 -0800 Subject: Increase storage debounce value --- app/scripts/background.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 2a8efd844..07a260a4f 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -114,7 +114,7 @@ function setupController (initState) { // setup state persistence pump( asStream(controller.store), - debounce(200), + debounce(1000), storeTransform(versionifyData), storeTransform(syncDataWithExtension), (error) => { -- cgit v1.2.3 From abfa74f09a0119345165a32090d88a1d95df6c80 Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Mon, 29 Jan 2018 15:29:01 -0500 Subject: complete i18n across new UI --- app/_locales/en/messages.json | 168 +++++++++++++++++++++++++----------------- app/manifest.json | 6 +- 2 files changed, 105 insertions(+), 69 deletions(-) (limited to 'app') diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 54f266318..a0c9088cb 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3,9 +3,9 @@ "message": "Accept" }, "account": { - "message": "Account:" + "message": "Account" }, - "accDetails": { + "accountDetails": { "message": "Account Details" }, "accountName": { @@ -17,11 +17,14 @@ "addToken": { "message": "Add Token" }, + "amount": { + "message": "Amount" + }, "amountPlusGas": { "message": "Amount + Gas" }, "appDescription": { - "message": "Ethereum Identity Management", + "message": "Ethereum Browser Extension", "description": "The description of the application" }, "appName": { @@ -43,10 +46,14 @@ "balanceIsInsufficientGas": { "message": "Insufficient balance for current gas total" }, + "betweenMinAndMax": { + "message": "must be greater than or equal to $1 and less than or equal to $2.", + "description": "helper for inputting hex as decimal input" + }, "borrowDharma": { "message": "Borrow With Dharma (Beta)" }, - "buyButton": { + "buy": { "message": "Buy" }, "buyCoinbase": { @@ -58,26 +65,20 @@ "cancel": { "message": "Cancel" }, - "cancelCaps": { - "message": "CANCEL" - }, "clickCopy": { "message": "Click to Copy" }, "confirm": { "message": "Confirm" }, - "confirmCaps": { - "message": "CONFIRM" - }, "confirmContract": { "message": "Confirm Contract" }, "confirmPassword": { "message": "Confirm Password" }, - "confirmPasswordSmall": { - "message": "confirm password" + "confirmTransaction": { + "message": "Confirm Transaction" }, "continueToCoinbase": { "message": "Continue to Coinbase" @@ -109,15 +110,19 @@ "copyPrivateKey": { "message": "This is your private key (click to copy)" }, + "create": { + "message": "Create" + }, "createAccount": { "message": "Create Account" }, - "createCaps": { - "message": "CREATE" - }, "createDen": { "message": "Create" }, + "crypto": { + "message": "Crypto", + "description": "Exchange type (cryptocurrencies)" + }, "customGas": { "message": "Customize Gas" }, @@ -139,9 +144,6 @@ "depositBTC": { "message": "Deposit your BTC to the address below:" }, - "depositButton": { - "message": "DEPOSIT" - }, "depositEth": { "message": "Deposit Eth" }, @@ -160,8 +162,8 @@ "depositShapeShiftExplainer": { "message": "If you own other cryptocurrencies, you can trade and deposit Ether directly into your MetaMask wallet. No Account Needed." }, - "detailsCaps": { - "message": "DETAILS" + "details": { + "message": "Details" }, "directDeposit": { "message": "Direct Deposit" @@ -175,12 +177,12 @@ "done": { "message": "Done" }, + "edit": { + "message": "Edit" + }, "editAccountName": { "message": "Edit Account Name" }, - "editCaps": { - "message": "EDIT" - }, "encryptNewDen": { "message": "Encrypt your new DEN" }, @@ -196,17 +198,19 @@ "exportPrivateKey": { "message": "Export Private Key" }, - "exportPrivateKeyLower": { - "message": "Export private key" - }, "exportPrivateKeyWarning": { "message": "Export private keys at your own risk." }, "failed": { "message": "Failed" }, + "fiat": { + "message": "FIAT", + "description": "Exchange type" + }, "fileImportFail": { - "message": "File import not working? Click here!" + "message": "File import not working? Click here!", + "description": "Helps user import their account from a JSON file" }, "from": { "message": "From" @@ -214,12 +218,13 @@ "fromShapeShift": { "message": "From ShapeShift" }, + "gas": { + "message": "Gas", + "description": "Short indication of gas cost" + }, "gasFee": { "message": "Gas Fee" }, - "gasFeeSpecific": { - "message": "Gas fee:" - }, "gasLimit": { "message": "Gas Limit" }, @@ -244,11 +249,20 @@ "getEther": { "message": "Get Ether" }, + "getEtherFromFaucet": { + "message": "Get Ether from a faucet for the $1", + "description": "Displays network name for Ether faucet" + }, + "greaterThanMin": { + "message": "must be greater than or equal to $1.", + "description": "helper for inputting hex as decimal input" + }, "here": { - "message": "here" + "message": "here", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" }, - "hideCaps": { - "message": "HIDE" + "hide": { + "message": "Hide" }, "hideToken": { "message": "Hide Token" @@ -260,7 +274,8 @@ "message": "How would you like to deposit Ether?" }, "import": { - "message": "Import" + "message": "Import", + "description": "Button to import an account from a selected file" }, "importAccount": { "message": "Import Account" @@ -268,14 +283,12 @@ "importAnAccount": { "message": "Import an account" }, - "importCaps": { - "message": "IMPORT" - }, "importDen": { "message": "Import Existing DEN" }, - "importedCaps": { - "message": "IMPORTED" + "imported": { + "message": "Imported", + "description": "status showing that an account has been fully loaded into the keyring" }, "infoHelp": { "message": "Info & Help" @@ -292,9 +305,17 @@ "invalidRequest": { "message": "Invalid Request" }, + "jsonFile": { + "message": "JSON File", + "description": "format for importing an account" + }, "kovan": { "message": "Kovan Test Network" }, + "lessThanMax": { + "message": "must be less than or equal to $1.", + "description": "helper for inputting hex as decimal input" + }, "limit": { "message": "Limit" }, @@ -310,8 +331,8 @@ "logout": { "message": "Log out" }, - "looseCaps": { - "message": "LOOSE" + "loose": { + "message": "Loose" }, "mainnet": { "message": "Main Ethereum Network" @@ -319,9 +340,6 @@ "message": { "message": "Message" }, - "messageCaps": { - "message": "MESSAGE" - }, "min": { "message": "Minimum" }, @@ -332,10 +350,12 @@ "message": "To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet." }, "needImportFile": { - "message": "You must select a file to import." + "message": "You must select a file to import.", + "description": "User is important an account and needs to add a file to continue" }, "needImportPassword": { - "message": "You must enter a password for the selected file." + "message": "You must enter a password for the selected file.", + "description": "Password and file needed to import an account" }, "networks": { "message": "Networks" @@ -377,20 +397,28 @@ "message": "You have returned to the old UI. You can switch back to the New UI through the option in the top right dropdown menu." }, "or": { - "message": "or" + "message": "or", + "description": "choice between creating or importing a new account" }, "passwordMismatch": { - "message": "passwords don't match" + "message": "passwords don't match", + "description": "in password creation process, the two new password fields did not match" }, "passwordShort": { - "message": "password not long enough" + "message": "password not long enough", + "description": "in password creation process, the password is not long enough to be secure" }, "pastePrivateKey": { - "message": "Paste your private key string here:" + "message": "Paste your private key string here:", + "description": "For importing an account from a private key" }, "pasteSeed": { "message": "Paste your seed phrase here!" }, + "privateKey": { + "message": "Private Key", + "description": "select this type of file to use to import an account" + }, "privateKeyWarning": { "message": "Warning: Never disclose this key. Anyone with your private keys can take steal any assets held in your account." }, @@ -434,16 +462,21 @@ "message": "Ropsten Test Network" }, "sampleAccountName": { - "message": "E.g. My new account" + "message": "E.g. My new account", + "description": "Help user understand concept of adding a human-readable name to their account" + }, + "save": { + "message": "Save" }, - "saveCaps": { - "message": "SAVE" + "saveAsFile": { + "message": "Save as File", + "description": "Account export process" }, "selectService": { "message": "Select Service" }, - "sendButton": { - "message": "SEND" + "send": { + "message": "Send" }, "sendTokens": { "message": "Send Tokens" @@ -460,12 +493,12 @@ "showPrivateKeys": { "message": "Show Private Keys" }, + "showQRCode": { + "message": "Show QR Code" + }, "sign": { "message": "Sign" }, - "signCaps": { - "message": "SIGN" - }, "signMessage": { "message": "Sign Message" }, @@ -490,12 +523,13 @@ "to": { "message": "To" }, + "toETHviaShapeShift": { + "message": "$1 to ETH via ShapeShift", + "description": "system will fill in deposit type in start of message" + }, "tokenBalance": { "message": "Your Token Balance is:" }, - "toSpecific": { - "message": "To:" - }, "total": { "message": "Total" }, @@ -509,7 +543,8 @@ "message": "Transfers" }, "troubleTokenBalances": { - "message": "We had trouble loading your token balances. You can view them " + "message": "We had trouble loading your token balances. You can view them ", + "description": "Followed by a link (here) to view token balances" }, "typePassword": { "message": "Type Your Password" @@ -532,6 +567,10 @@ "unknownNetworkId": { "message": "Unknown network ID" }, + "usaOnly": { + "message": "USA only", + "description": "Using this exchange is limited to people inside the USA" + }, "usedByClients": { "message": "Used by a variety of different clients" }, @@ -548,9 +587,6 @@ "message": "Your signature is being requested" }, "youSign": { - "message": "You are signing:" - }, - "youSignCaps": { - "message": "YOU ARE SIGNING" + "message": "You are signing" } } diff --git a/app/manifest.json b/app/manifest.json index d906382e9..b52d3245d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,10 +1,10 @@ { - "name": "MetaMask", - "short_name": "Metamask", + "name": "__MSG_appName__", + "short_name": "__MSG_appName__", "version": "4.0.10", "manifest_version": 2, "author": "https://metamask.io", - "description": "Ethereum Browser Extension", + "description": "__MSG_appDescription__", "commands": { "_execute_browser_action": { "suggested_key": { -- cgit v1.2.3 From 7c2257e09c2583a4ac24a78e1b3c58a750cb798f Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 6 Mar 2018 21:25:30 -0330 Subject: Missing comma in messages.json --- app/_locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 2884392e8..f4a8fe943 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -373,7 +373,7 @@ "newAccountNumberName": { "message": "Account $1", "description": "Default name of next account to be created on create account screen" - } + }, "newContract": { "message": "New Contract" }, -- cgit v1.2.3 From ab55c184c7e40e6e46bc4da5d8438a18999a266e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 7 Mar 2018 13:50:22 -0800 Subject: Increase storage debounce to 2s --- app/scripts/background.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 464330708..cb6810173 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -126,7 +126,7 @@ function setupController (initState) { // setup state persistence pump( asStream(controller.store), - debounce(1000), + debounce(2000), storeTransform(versionifyData), storeTransform(syncDataWithExtension), (error) => { -- cgit v1.2.3 From d58e47edec80180c7dd99effc229e116c63b4f57 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 7 Mar 2018 14:23:31 -0800 Subject: Some fixes for new storage strategy - Don't persist undefined data - Write to new storage strategy without waiting for completion. - Continue writing to localStorage as fallback. --- app/scripts/background.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index cb6810173..b5f7002dc 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -93,6 +93,9 @@ async function loadStateFromPersistence () { .catch((reason) => { log.error('Problem saving migrated data', versionedData) }) + if (versionedData) { + diskStore.putState(versionedData) + } // return just the data return versionedData.data @@ -129,6 +132,7 @@ function setupController (initState) { debounce(2000), storeTransform(versionifyData), storeTransform(syncDataWithExtension), + asStream(diskStore), (error) => { log.error('pump hit error', error) } @@ -139,14 +143,14 @@ function setupController (initState) { return versionedData } - async function syncDataWithExtension(state) { + function syncDataWithExtension(state) { if (localStore.isSupported) { - try { - await localStore.set(state) - } catch (err) { + localStore.set(state) + .catch((err) => { log.error('error setting state in local store:', err) - } + }) } else { log.error('local store not supported') } + return state } -- cgit v1.2.3 From b97ac5106fd8479a81dc5c32ede99090427ee1b8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 7 Mar 2018 14:38:26 -0800 Subject: Add clarifying comment --- app/scripts/background.js | 1 + 1 file changed, 1 insertion(+) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index b5f7002dc..55eeed83f 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -80,6 +80,7 @@ async function loadStateFromPersistence () { log.error('error fetching state from local store:', err) } + // If localStore is supported but has not been written to yet, ignore: if (Object.keys(localData).length > 0) { versionedData = localData } -- cgit v1.2.3 From 64fcd271028ff57c34dd930b76ce23081eff814a Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 7 Mar 2018 14:42:59 -0800 Subject: Tighten up data loading code --- app/scripts/background.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 55eeed83f..e8a7594ac 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -68,10 +68,10 @@ async function initialize () { async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) - // read from disk - versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) - // fetch from extension store and merge in data + // read from disk + // first from preferred, async API: + let localStoreData if (localStore.isSupported) { let localData try { @@ -82,10 +82,14 @@ async function loadStateFromPersistence () { // If localStore is supported but has not been written to yet, ignore: if (Object.keys(localData).length > 0) { - versionedData = localData + localStoreData = localData } } + versionedData = localStoreData || + diskStore.getState() || + migrator.generateInitialState(firstTimeState) + // migrate data versionedData = await migrator.migrateData(versionedData) -- cgit v1.2.3 From 98efca0a9798db205ef8068c038a225a79c575cd Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 8 Mar 2018 14:10:28 -0800 Subject: background - storage - cleanup storage wiring --- app/scripts/background.js | 34 ++++++++-------------------------- app/scripts/lib/local-store.js | 30 ++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 34 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index e8a7594ac..ef5513ec7 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -71,36 +71,19 @@ async function loadStateFromPersistence () { // read from disk // first from preferred, async API: - let localStoreData - if (localStore.isSupported) { - let localData - try { - localData = await localStore.get() - } catch (err) { - log.error('error fetching state from local store:', err) - } - - // If localStore is supported but has not been written to yet, ignore: - if (Object.keys(localData).length > 0) { - localStoreData = localData - } - } - - versionedData = localStoreData || + versionedData = (await localStore.get()) || diskStore.getState() || migrator.generateInitialState(firstTimeState) // migrate data versionedData = await migrator.migrateData(versionedData) + if (!versionedData) { + throw new Error('MetaMask - migrator returned undefined') + } // write to disk - localStore.set(versionedData) - .catch((reason) => { - log.error('Problem saving migrated data', versionedData) - }) - if (versionedData) { - diskStore.putState(versionedData) - } + if (localStore.isSupported) localStore.set(versionedData) + diskStore.putState(versionedData) // return just the data return versionedData.data @@ -134,7 +117,7 @@ function setupController (initState) { // setup state persistence pump( asStream(controller.store), - debounce(2000), + debounce(1000), storeTransform(versionifyData), storeTransform(syncDataWithExtension), asStream(diskStore), @@ -154,8 +137,7 @@ function setupController (initState) { .catch((err) => { log.error('error setting state in local store:', err) }) - } else { log.error('local store not supported') } - + } return state } diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 9e8d8db37..73482a636 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -3,6 +3,7 @@ // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local const extension = require('extensionizer') +const { promisify } = require('util').promisify module.exports = class ExtensionStore { constructor() { @@ -10,15 +11,28 @@ module.exports = class ExtensionStore { if (!this.isSupported) { log.error('Storage local API not available.') } + const local = extension.storage.local + this._get = promisify(local.get).bind(local) + this._set = promisify(local.set).bind(local) } - get() { - return new Promise((resolve) => { - extension.storage.local.get(null, resolve) - }) + + async get() { + if (!this.isSupported) return undefined + const result = await this._get() + // extension.storage.local always returns an obj + // if the object is empty, treat it as undefined + if (isEmpty(result)) { + return undefined + } else { + return result + } } - set(state) { - return new Promise((resolve) => { - extension.storage.local.set(state, resolve) - }) + + async set(state) { + return this._set(state) } } + +function isEmpty(obj) { + return 0 === Object.keys(obj).length +} -- cgit v1.2.3 From a88e436b7d45d9a7f9f4d4a4be58aff5e58e9074 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 8 Mar 2018 14:55:35 -0800 Subject: lint fix --- app/scripts/lib/local-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 73482a636..781aea17e 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -34,5 +34,5 @@ module.exports = class ExtensionStore { } function isEmpty(obj) { - return 0 === Object.keys(obj).length + return Object.keys(obj).length === 0 } -- cgit v1.2.3 From f7138d81e38661ef9262c6a31b66d962238b5c9c Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Mar 2018 11:41:26 -0700 Subject: Add sigRequest for Signature Request --- app/_locales/en/messages.json | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app') diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index f4a8fe943..1ca31427d 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -519,6 +519,9 @@ "signNotice": { "message": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. " }, + "sigRequest": { + "message": "Signature Request" + }, "sigRequested": { "message": "Signature Requested" }, -- cgit v1.2.3 From d195cfab50b42d26f3cf9436845838e075e959de Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 13 Mar 2018 15:13:05 -0700 Subject: transactions - insure if a to field in tx params has a truthy valu that it is a valid addres and if it is falsy that it is not null to fix issue #3509 --- app/scripts/lib/tx-gas-utils.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index 6f6ff7852..e61db3332 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -4,7 +4,7 @@ const { BnMultiplyByFraction, bnToHex, } = require('./util') -const addHexPrefix = require('ethereumjs-util').addHexPrefix +const {addHexPrefix, isValidAddress} = require('ethereumjs-util') const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. /* @@ -101,6 +101,12 @@ module.exports = class TxGasUtil { async validateTxParams (txParams) { this.validateRecipient(txParams) + if ('to' in txParams) { + if ( txParams.to === null ) delete txParams.to + else if ( txParams.to !== undefined && !isValidAddress(txParams.to) ) { + throw new Error(`Invalid transaction value of ${txParams.to} not a valid to address.`) + } + } if ('value' in txParams) { const value = txParams.value.toString() if (value.includes('-')) { -- cgit v1.2.3 From c465d510b100fdf9926413751df04cbd59de68eb Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 13 Mar 2018 15:26:45 -0700 Subject: fix error message --- app/scripts/lib/tx-gas-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index e61db3332..3b0494e04 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -104,7 +104,7 @@ module.exports = class TxGasUtil { if ('to' in txParams) { if ( txParams.to === null ) delete txParams.to else if ( txParams.to !== undefined && !isValidAddress(txParams.to) ) { - throw new Error(`Invalid transaction value of ${txParams.to} not a valid to address.`) + throw new Error(`Invalid recipient address`) } } if ('value' in txParams) { -- cgit v1.2.3 From e5a83d3f1a3ebe9115c07e162ee4bca0f157b8b1 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 13 Mar 2018 15:32:03 -0700 Subject: transactions move validation of the to field to validateRecipient --- app/scripts/lib/tx-gas-utils.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index 3b0494e04..a8f473a88 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -101,12 +101,6 @@ module.exports = class TxGasUtil { async validateTxParams (txParams) { this.validateRecipient(txParams) - if ('to' in txParams) { - if ( txParams.to === null ) delete txParams.to - else if ( txParams.to !== undefined && !isValidAddress(txParams.to) ) { - throw new Error(`Invalid recipient address`) - } - } if ('value' in txParams) { const value = txParams.value.toString() if (value.includes('-')) { @@ -119,12 +113,14 @@ module.exports = class TxGasUtil { } } validateRecipient (txParams) { - if (txParams.to === '0x') { + if (txParams.to === '0x' || txParams.to === null ) { if (txParams.data) { delete txParams.to } else { throw new Error('Invalid recipient address') } + } else if ( txParams.to !== undefined && !isValidAddress(txParams.to) ) { + throw new Error('Invalid recipient address') } return txParams } -- cgit v1.2.3 From 22cd7882038d05e51c5b76f2f4c76c15b2fd89f6 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 13 Mar 2018 15:39:33 -0700 Subject: tx-gas-utils - fix code style --- app/scripts/lib/tx-gas-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index a8f473a88..0fa9dd8d4 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -4,7 +4,7 @@ const { BnMultiplyByFraction, bnToHex, } = require('./util') -const {addHexPrefix, isValidAddress} = require('ethereumjs-util') +const { addHexPrefix, isValidAddress } = require('ethereumjs-util') const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. /* -- cgit v1.2.3