From 9a7b1cc5ad9d84225c2109073f8034bb8498b2f0 Mon Sep 17 00:00:00 2001 From: Juan Cortes Ross Date: Wed, 13 Feb 2019 01:48:54 +0100 Subject: [PATCH 01/23] Refactored the partners section out --- src/components/ExchangePage/index.js | 126 ------------------ src/components/ExchangePage/logos/bigmama.js | 16 --- .../ExchangePage/logos/btcdirect.js | 67 ---------- .../ExchangePage/logos/changelly.js | 26 ---- .../ExchangePage/logos/coinberry.js | 116 ---------------- .../ExchangePage/logos/coinhouse.js | 58 -------- src/components/ExchangePage/logos/paybis.js | 46 ------- src/components/ExchangePage/logos/simplex.js | 27 ---- src/components/MainSideBar/index.js | 2 +- .../PartnerCard.js} | 17 +-- src/components/PartnersPage/index.js | 33 +++++ src/components/layout/Default.js | 4 +- static/i18n/en/app.json | 24 ++-- static/images/logos/exchanges/change-now.png | Bin 30750 -> 0 bytes static/images/logos/exchanges/genesis.svg | 6 - static/images/logos/exchanges/kyber-swap.png | Bin 54258 -> 0 bytes static/images/logos/exchanges/luno.svg | 14 -- static/images/logos/exchanges/shapeshift.svg | 93 ------------- static/images/logos/exchanges/thor-swap.png | Bin 23198 -> 0 bytes 19 files changed, 59 insertions(+), 616 deletions(-) delete mode 100644 src/components/ExchangePage/index.js delete mode 100644 src/components/ExchangePage/logos/bigmama.js delete mode 100644 src/components/ExchangePage/logos/btcdirect.js delete mode 100644 src/components/ExchangePage/logos/changelly.js delete mode 100644 src/components/ExchangePage/logos/coinberry.js delete mode 100644 src/components/ExchangePage/logos/coinhouse.js delete mode 100644 src/components/ExchangePage/logos/paybis.js delete mode 100644 src/components/ExchangePage/logos/simplex.js rename src/components/{ExchangePage/ExchangeCard.js => PartnersPage/PartnerCard.js} (67%) create mode 100644 src/components/PartnersPage/index.js delete mode 100644 static/images/logos/exchanges/change-now.png delete mode 100644 static/images/logos/exchanges/genesis.svg delete mode 100644 static/images/logos/exchanges/kyber-swap.png delete mode 100644 static/images/logos/exchanges/luno.svg delete mode 100644 static/images/logos/exchanges/shapeshift.svg delete mode 100644 static/images/logos/exchanges/thor-swap.png diff --git a/src/components/ExchangePage/index.js b/src/components/ExchangePage/index.js deleted file mode 100644 index 0a1e46a9..00000000 --- a/src/components/ExchangePage/index.js +++ /dev/null @@ -1,126 +0,0 @@ -// @flow - -import React, { PureComponent } from 'react' -import { translate } from 'react-i18next' -import shuffle from 'lodash/shuffle' - -import type { T } from 'types/common' -import { urls } from 'config/urls' -import { i } from 'helpers/staticPath' - -import TrackPage from 'analytics/TrackPage' -import Box from 'components/base/Box' -import ExchangeCard from './ExchangeCard' - -import CoinhouseLogo from './logos/coinhouse' -import ChangellyLogo from './logos/changelly' -import CoinmamaLogo from './logos/bigmama' -import SimplexLogo from './logos/simplex' -import PaybisLogo from './logos/paybis' -import Coinberry from './logos/coinberry' -import BtcDirect from './logos/btcdirect' - -type Props = { - t: T, -} - -const cards = shuffle([ - { - key: 'coinhouse', - id: 'coinhouse', - url: urls.coinhouse, - logo: , - }, - { - key: 'changelly', - id: 'changelly', - url: urls.changelly, - logo: , - }, - { - key: 'coinmama', - id: 'coinmama', - url: urls.coinmama, - logo: , - }, - { - key: 'simplex', - id: 'simplex', - url: urls.simplex, - logo: , - }, - { - key: 'paybis', - id: 'paybis', - url: urls.paybis, - logo: , - }, - { - key: 'luno', - id: 'luno', - url: urls.luno, - logo: Luno, - }, - { - key: 'shapeshift', - id: 'shapeshift', - url: urls.shapeshift, - logo: Shapeshift, - }, - { - key: 'genesis', - id: 'genesis', - url: urls.genesis, - logo: Genesis, - }, - { - key: 'kyberSwap', - id: 'kyberSwap', - url: urls.kyberSwap, - logo: KyberSwap, - }, - { - key: 'changeNow', - id: 'changeNow', - url: urls.changeNow, - logo: ChangeNow, - }, - { - key: 'thorSwap', - id: 'thorSwap', - url: urls.thorSwap, - logo: ThorSwap, - }, - { - key: 'coinberry', - id: 'coinberry', - url: urls.coinberry, - logo: , - }, - { - key: 'btcDirect', - id: 'btcDirect', - url: urls.btcDirect, - logo: , - }, -]) - -class ExchangePage extends PureComponent { - render() { - const { t } = this.props - return ( - - - - {t('exchange.title')} - - - {t('exchange.desc')} - - {cards.map(card => )} - - ) - } -} - -export default translate()(ExchangePage) diff --git a/src/components/ExchangePage/logos/bigmama.js b/src/components/ExchangePage/logos/bigmama.js deleted file mode 100644 index 58dd5df2..00000000 --- a/src/components/ExchangePage/logos/bigmama.js +++ /dev/null @@ -1,16 +0,0 @@ -// @flow - -import React from 'react' - -const inner = ( - - - - -) - -export default ({ width }: { width: number }) => ( - - {inner} - -) diff --git a/src/components/ExchangePage/logos/btcdirect.js b/src/components/ExchangePage/logos/btcdirect.js deleted file mode 100644 index 70840be4..00000000 --- a/src/components/ExchangePage/logos/btcdirect.js +++ /dev/null @@ -1,67 +0,0 @@ -// @flow - -import React from 'react' - -const styles = { - fill: '#0086fb', -} - -const inner = ( - <> - - - - - - - - - - - - - - -) - -export default ({ width }: { width: number }) => ( - - {inner} - -) diff --git a/src/components/ExchangePage/logos/changelly.js b/src/components/ExchangePage/logos/changelly.js deleted file mode 100644 index 0a57bed0..00000000 --- a/src/components/ExchangePage/logos/changelly.js +++ /dev/null @@ -1,26 +0,0 @@ -// @flow - -import React from 'react' - -const inner = ( - - - - - -) - -export default ({ width }: { width: number }) => ( - - {inner} - -) diff --git a/src/components/ExchangePage/logos/coinberry.js b/src/components/ExchangePage/logos/coinberry.js deleted file mode 100644 index 46396d39..00000000 --- a/src/components/ExchangePage/logos/coinberry.js +++ /dev/null @@ -1,116 +0,0 @@ -// @flow - -import React from 'react' - -const styles = { - blue: { - fill: '#334F93', - }, - pink: { - fill: '#EC2D6E', - }, -} - -const inner = ( - <> - - - - - - - - - - - - - - - - - -) - -export default ({ width }: { width: number }) => ( - - {inner} - -) diff --git a/src/components/ExchangePage/logos/coinhouse.js b/src/components/ExchangePage/logos/coinhouse.js deleted file mode 100644 index b8cdf175..00000000 --- a/src/components/ExchangePage/logos/coinhouse.js +++ /dev/null @@ -1,58 +0,0 @@ -// @flow - -import React, { Fragment } from 'react' - -const inner = ( - - - - - - - - - - - - - -) - -export default ({ width }: { width: number }) => ( - - {inner} - -) diff --git a/src/components/ExchangePage/logos/paybis.js b/src/components/ExchangePage/logos/paybis.js deleted file mode 100644 index 2c6336ac..00000000 --- a/src/components/ExchangePage/logos/paybis.js +++ /dev/null @@ -1,46 +0,0 @@ -// @flow - -import React, { Fragment } from 'react' - -const inner = ( - - - - - - - - - - - - - - - - -) - -export default ({ width, height }: { width: number, height: number }) => ( - - {inner} - -) diff --git a/src/components/ExchangePage/logos/simplex.js b/src/components/ExchangePage/logos/simplex.js deleted file mode 100644 index 94d68a37..00000000 --- a/src/components/ExchangePage/logos/simplex.js +++ /dev/null @@ -1,27 +0,0 @@ -// @flow - -import React, { Fragment } from 'react' - -const inner = ( - - - - - -) - -export default ({ width, height }: { width: number, height: number }) => ( - - {inner} - -) diff --git a/src/components/MainSideBar/index.js b/src/components/MainSideBar/index.js index 4ada30c9..4ec9af02 100644 --- a/src/components/MainSideBar/index.js +++ b/src/components/MainSideBar/index.js @@ -88,7 +88,7 @@ class MainSideBar extends PureComponent { handleOpenSendModal = () => this.props.openModal(MODAL_SEND) handleOpenReceiveModal = () => this.props.openModal(MODAL_RECEIVE) handleClickManager = () => this.push('/manager') - handleClickExchange = () => this.push('/exchange') + handleClickExchange = () => this.push('/partners') handleClickDev = () => this.push('/dev') handleOpenImportModal = () => this.props.openModal(MODAL_ADD_ACCOUNTS) diff --git a/src/components/ExchangePage/ExchangeCard.js b/src/components/PartnersPage/PartnerCard.js similarity index 67% rename from src/components/ExchangePage/ExchangeCard.js rename to src/components/PartnersPage/PartnerCard.js index 5b8366d4..57c12c9d 100644 --- a/src/components/ExchangePage/ExchangeCard.js +++ b/src/components/PartnersPage/PartnerCard.js @@ -11,29 +11,30 @@ import { FakeLink } from 'components/base/Link' type CardType = { id: string, - logo: any, + Logo: any, url: string, } -export default class ExchangeCard extends PureComponent<{ t: T, card: CardType }> { +export default class PartnerCard extends PureComponent<{ t: T, card: CardType }> { onClick = () => { const { card } = this.props - openURL(card.url, 'VisitExchange', { id: card.id }) + openURL(card.url, 'VisitPartner', { id: card.id }) } + render() { const { - card: { logo, id }, + card: { Logo, id }, t, } = this.props return ( - - {logo} + + - {t(`exchange.${id}`)} + {t(`partners.${id}`)} - {t('exchange.visitWebsite')} + {t('partners.visitWebsite')} diff --git a/src/components/PartnersPage/index.js b/src/components/PartnersPage/index.js new file mode 100644 index 00000000..7b5a0460 --- /dev/null +++ b/src/components/PartnersPage/index.js @@ -0,0 +1,33 @@ +// @flow + +import React, { PureComponent } from 'react' +import { T, translate } from 'react-i18next' + +import partners from '@ledgerhq/live-common/lib/partners/react' +import TrackPage from 'analytics/TrackPage' +import Box from 'components/base/Box' +import PartnerCard from './PartnerCard' + +type Props = { + t: T, +} + +class PartnersPage extends PureComponent { + render() { + const { t } = this.props + return ( + + + + {t('partners.title')} + + + {t('partners.desc')} + + {partners.map(card => )} + + ) + } +} + +export default translate()(PartnersPage) diff --git a/src/components/layout/Default.js b/src/components/layout/Default.js index 14156b39..8926fa12 100644 --- a/src/components/layout/Default.js +++ b/src/components/layout/Default.js @@ -19,7 +19,7 @@ import Idler from 'components/Idler' import AccountPage from 'components/AccountPage' import DashboardPage from 'components/DashboardPage' import ManagerPage from 'components/ManagerPage' -import ExchangePage from 'components/ExchangePage' +import PartnersPage from 'components/PartnersPage' import DevToolsPage from 'components/DevToolsPage' import SettingsPage from 'components/SettingsPage' import KeyboardContent from 'components/KeyboardContent' @@ -117,7 +117,7 @@ class Default extends Component { - + diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json index bc8ab0b4..49c22b96 100644 --- a/static/i18n/en/app.json +++ b/static/i18n/en/app.json @@ -163,23 +163,27 @@ } } }, - "exchange": { + "partners": { "title": "Buy crypto", "desc": "Try a few services we've selected", "visitWebsite": "Visit website", - "coinhouse": "Coinhouse is a trusted platform for individuals and institutional investors looking to analyze, acquire, sell and securely store crypto assets.", + + "btcdirect": "Buy and sell with the greatest of ease at Europe's leading cryptocurrency broker. Sign up for free and receive your coins within minutes! Our users rate us with an 8,7 on Trustpilot", "changelly": "Changelly is a popular instant crypto asset exchange with 100+ coins and tokens listed.", + "changenow": "ChangeNOW is one of the leading custody-free instant exchange services", + "coinberry": "Coinberry is the most trusted crypto platform in Canada with better-than-bank security, best-in-class user interface and No Fee funding & withdraw. Pre-register to get early access to our platform if you are not a Canadian citizen.", + "coinhouse": "Coinhouse is a trusted platform for individuals and institutional investors looking to analyze, acquire, sell and securely store crypto assets.", "coinmama": "Coinmama is a financial service that makes it fast, safe and fun to buy digital assets, anywhere in the world.", - "simplex": "Simplex is a EU licensed financial institution, providing a fraudless credit card payment solution.", - "paybis": "it is safe and easy to Buy Bitcoin with credit card from PayBis. Service operates in US, Canada, Germany, Russia and Saudi Arabia.", + "genesis": "Genesis is an institutional trading firm offering liquidity and borrow for digital currencies, including bitcoin, bitcoin cash, ethereum, ethereum classic, litecoin, and XRP.", + "kyberswap": "Fast, simple and secure token swap platform. Powered by Kyber Network's on-chain liquidity protocol.", "luno": "Luno makes it safe and easy to buy, store and learn about cryptocurrencies like Bitcoin and Ethereum", + "paybis": "it is safe and easy to Buy Bitcoin with credit card from PayBis. Service operates in US, Canada, Germany, Russia and Saudi Arabia.", "shapeshift": "ShapeShift is an online marketplace where users can buy and sell digital assets. It is a fast and secure way for the world to buy and sell digital assets, with no lengthy signup process, no counterparty risk, and no friction.", - "genesis": "Genesis is an institutional trading firm offering liquidity and borrow for digital currencies, including bitcoin, bitcoin cash, ethereum, ethereum classic, litecoin, and XRP.", - "kyberSwap": "Fast, simple and secure token swap platform. Powered by Kyber Network's on-chain liquidity protocol.", - "thorSwap": "ThorSwap is an instant, safe and fair crypto asset market powered by decentralized atomic swap technologies. It is the most convenient way to start trading, no registration or KYC for small amount transactions.", - "changeNow": "ChangeNOW is one of the leading custody-free instant exchange services", - "coinberry": "Coinberry is the most trusted crypto platform in Canada with better-than-bank security, best-in-class user interface and No Fee funding & withdraw. Pre-register to get early access to our platform if you are not a Canadian citizen.", - "btcDirect": "Buy and sell with the greatest of ease at Europe's leading cryptocurrency broker. Sign up for free and receive your coins within minutes! Our users rate us with an 8,7 on Trustpilot" + "simplex": "Simplex is a EU licensed financial institution, providing a fraudless credit card payment solution.", + "taxtoken": "Automated cryptocurrency tax and cost basis software for US citizens.", + "thorswap": "ThorSwap is an instant, safe and fair crypto asset market powered by decentralized atomic swap technologies. It is the most convenient way to start trading, no registration or KYC for small amount transactions.", + "bitpanda": "Bitpanda is Europe’s leading retail broker for buying and selling Bitcoin, Ethereum, IOTA and many more. Deposit money using your credit card, SOFORT-Transfer, NETELLER, and other options.", + "exmo": "Founded in 2013 and based in London, Kiev, Barcelona, and Moscow, EXMO is #1 exchange in Eastern Europe, and one of the world's largest global exchanges in volume and liquidity." }, "genuinecheck": { "modal": { diff --git a/static/images/logos/exchanges/change-now.png b/static/images/logos/exchanges/change-now.png deleted file mode 100644 index fb3f8a77d9692aa70531d7178889d94dccf1f714..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30750 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

*|sxs4hJvHdz`-MCaCen`6y+y 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 diff --git a/static/images/logos/exchanges/genesis.svg b/static/images/logos/exchanges/genesis.svg deleted file mode 100644 index 6aa3ea56..00000000 --- a/static/images/logos/exchanges/genesis.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/static/images/logos/exchanges/kyber-swap.png b/static/images/logos/exchanges/kyber-swap.png deleted file mode 100644 index 45472e4fb13e962d90031dd93518afe4dbe5440c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54258 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 - - - - - - - - - - - - - diff --git a/static/images/logos/exchanges/shapeshift.svg b/static/images/logos/exchanges/shapeshift.svg deleted file mode 100644 index 5efd76eb..00000000 --- a/static/images/logos/exchanges/shapeshift.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/images/logos/exchanges/thor-swap.png b/static/images/logos/exchanges/thor-swap.png deleted file mode 100644 index f3851d66d2ae5cfd47f0399991f89ca9460032e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23198 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¥OrS9iYdcdj@cw?dg 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 From 0be9b415fa12530a4cb2c5b6f15320c63772914a Mon Sep 17 00:00:00 2001 From: Juan Cortes Ross Date: Thu, 14 Feb 2019 23:41:30 +0100 Subject: [PATCH 02/23] Adds the developer mode to exported data --- src/reducers/settings.js | 4 +++- yarn.lock | 20 +------------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/reducers/settings.js b/src/reducers/settings.js index 85141467..30ff551f 100644 --- a/src/reducers/settings.js +++ b/src/reducers/settings.js @@ -244,10 +244,12 @@ export const exportSettingsSelector = createSelector( counterValueCurrencySelector, counterValueExchangeSelector, state => state.settings.currenciesSettings, - (counterValueCurrency, counterValueExchange, currenciesSettings) => ({ + developerModeSelector, + (counterValueCurrency, counterValueExchange, currenciesSettings, developerModeEnabled) => ({ counterValue: counterValueCurrency.ticker, counterValueExchange, currenciesSettings, + developerModeEnabled, }), ) diff --git a/yarn.lock b/yarn.lock index cae22ea3..dcdf3da4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13495,17 +13495,7 @@ react-treebeard@^2.1.0: shallowequal "^0.2.2" velocity-react "^1.3.1" -react@*, react@^16.2.0: - version "16.6.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.6.1.tgz#ee2aef4f0a09e494594882029821049772f915fe" - integrity sha512-OtawJThYlvRgm9BXK+xTL7BIlDx8vv21j+fbQDjRRUyok6y7NyjlweGorielTahLZHYIdKUoK2Dp9ByVWuMqxw== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.11.0" - -react@^16.6.3: +react@*, react@^16.2.0, react@^16.6.3: version "16.6.3" resolved "https://registry.yarnpkg.com/react/-/react-16.6.3.tgz#25d77c91911d6bbdd23db41e70fb094cc1e0871c" integrity sha512-zCvmH2vbEolgKxtqXL2wmGCUxUyNheYn/C+PD1YAjfxHC54+MhdruyhO7QieQrYsYeTxrn93PM2y0jRH1zEExw== @@ -14424,14 +14414,6 @@ sax@^1.2.4, sax@~1.2.1, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.11.0.tgz#def1f1bfa6550cc57981a87106e65e8aea41a6b5" - integrity sha512-MAYbBfmiEHxF0W+c4CxMpEqMYK+rYF584VP/qMKSiHM6lTkBKKYOJaDiSILpJHla6hBOsVd6GucPL46o2Uq3sg== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler@^0.11.2: version "0.11.3" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.11.3.tgz#b5769b90cf8b1464f3f3cfcafe8e3cd7555a2d6b" From 670ea1b1d92eb7bc289de47d5a23be5cc37431e2 Mon Sep 17 00:00:00 2001 From: Dimitri Sabadie Date: Fri, 1 Feb 2019 15:17:29 +0100 Subject: [PATCH 03/23] =?UTF-8?q?Use=20the=20freshResetAll=20libcore?= =?UTF-8?q?=E2=80=99s=20function=20when=20resetting=20the=20app.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also, bump libcore’s version to 2.5.0 (release-candidate). --- package.json | 2 +- src/helpers/reset.js | 17 +++++------------ yarn.lock | 8 ++++---- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 5a256f90..cd1acc86 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@ledgerhq/hw-app-xrp": "^4.35.0", "@ledgerhq/hw-transport": "^4.35.0", "@ledgerhq/hw-transport-node-hid": "^4.35.0", - "@ledgerhq/ledger-core": "2.0.0-rc.16", + "@ledgerhq/ledger-core": "2.0.0-rc.19", "@ledgerhq/live-common": "4.16.1", "animated": "^0.2.2", "async": "^2.6.1", diff --git a/src/helpers/reset.js b/src/helpers/reset.js index 28439120..a8103a6b 100644 --- a/src/helpers/reset.js +++ b/src/helpers/reset.js @@ -1,23 +1,16 @@ // @flow -import fs from 'fs' import { shell, remote } from 'electron' -import path from 'path' -import rimraf from 'rimraf' import resolveUserDataDirectory from 'helpers/resolveUserDataDirectory' import { disable as disableDBMiddleware } from 'middlewares/db' import db from 'helpers/db' import { delay } from 'helpers/promise' import killInternalProcess from 'commands/killInternalProcess' -import { DBNotReset } from '@ledgerhq/errors' +import withLibcore from 'helpers/withLibcore' -async function resetLibcoreDatabase() { +async function resetLibcore() { await killInternalProcess.send().toPromise() - const dbpath = path.resolve(resolveUserDataDirectory(), 'sqlite/') - rimraf.sync(dbpath, { glob: false }) - if (fs.existsSync(dbpath)) { - throw new DBNotReset() - } + withLibcore(core => core.freshResetAll()) } function reload() { @@ -30,7 +23,7 @@ export async function hardReset() { disableDBMiddleware() db.resetAll() await delay(500) - await resetLibcoreDatabase() + await resetLibcore() reload() } @@ -38,7 +31,7 @@ export async function softReset({ cleanAccountsCache }: *) { cleanAccountsCache() await delay(500) await db.cleanCache() - await resetLibcoreDatabase() + await resetLibcore() reload() } diff --git a/yarn.lock b/yarn.lock index 3ed0695a..8040cfb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1722,10 +1722,10 @@ dependencies: events "^3.0.0" -"@ledgerhq/ledger-core@2.0.0-rc.16": - version "2.0.0-rc.16" - resolved "https://registry.yarnpkg.com/@ledgerhq/ledger-core/-/ledger-core-2.0.0-rc.16.tgz#51f141c0143edb020e38855bf2e2619e3446e74f" - integrity sha512-gmbeXRBg4NSqzH6+EajYTzaQlwN5ugaN1nH0SI6BvRqMfcorxNRE8byfh3F2u+7TNchBW72vOZnKPDShaR9/pQ== +"@ledgerhq/ledger-core@2.0.0-rc.19": + version "2.0.0-rc.19" + resolved "https://registry.yarnpkg.com/@ledgerhq/ledger-core/-/ledger-core-2.0.0-rc.19.tgz#f8cd0bdc4e8f067bd95aced895d3e1190bb63f06" + integrity sha512-pkSVOFNGYYiujJFCJ7JkQrwK5YMVx6MoyXBD4jA+SKthlZ8zo3X3jfhRJdZ1rUiI87GP/ncdh0Kc+epuWTqlDQ== dependencies: bindings "^1.3.0" nan "^2.6.2" From c4efdeb8d5c0d103737ba8787ce5003b5e56f4bd Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Wed, 13 Feb 2019 16:25:29 +0100 Subject: [PATCH 04/23] Bump ledgerjs libs --- package.json | 10 ++-- yarn.lock | 129 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 87 insertions(+), 52 deletions(-) diff --git a/package.json b/package.json index 5a256f90..c102b4f6 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,11 @@ }, "dependencies": { "@ledgerhq/errors": "^4.39.0", - "@ledgerhq/hw-app-btc": "^4.35.0", - "@ledgerhq/hw-app-eth": "^4.35.0", - "@ledgerhq/hw-app-xrp": "^4.35.0", - "@ledgerhq/hw-transport": "^4.35.0", - "@ledgerhq/hw-transport-node-hid": "^4.35.0", + "@ledgerhq/hw-app-btc": "^4.38.6", + "@ledgerhq/hw-app-eth": "^4.38.6", + "@ledgerhq/hw-app-xrp": "^4.38.6", + "@ledgerhq/hw-transport": "^4.38.6", + "@ledgerhq/hw-transport-node-hid": "^4.38.6", "@ledgerhq/ledger-core": "2.0.0-rc.16", "@ledgerhq/live-common": "4.16.1", "animated": "^0.2.2", diff --git a/yarn.lock b/yarn.lock index 3ed0695a..035f98db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1677,49 +1677,60 @@ camelcase "^5.0.0" prettier "^1.13.7" -"@ledgerhq/errors@^4.32.0", "@ledgerhq/errors@^4.39.0": - version "4.39.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-4.39.0.tgz#10b9889f78df94ce36a4b34d9a3a45aac77be0e9" - integrity sha512-kBr2rnoYDACRCxTLtEufE4oCvYj6vx2oFWVVjwskBxYsF5LC9R8Mbg5C4GgvDweiWW4Io8HA9p9jCsOfdCDygg== +"@ledgerhq/devices@^4.38.0": + version "4.38.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-4.38.0.tgz#06e4ac7f1e49827b9cd32c34c2f20c28c3b42fdc" + integrity sha512-6XfuSoJIXmW6xloWNdXDNsL8JZrUb4Xh9pKwh7NzxqQx50rqQ0JI1wxrZQJB0ZRevnk0SCMbIbT6aQOxmF8CIg== + dependencies: + "@ledgerhq/errors" "^4.38.0" + +"@ledgerhq/errors@^4.32.0", "@ledgerhq/errors@^4.38.0": + version "4.38.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-4.38.0.tgz#5260118b2cb1069f706d9316bf6f2ee1f6935f43" + integrity sha512-ZVpwiQV4y6OqMcOhZ7xQR37xpZdYGXnZftlYtT9muzXrak/HPHc19oPpwiuqKmHAbgfio6qEVk9Lp3yWLY9bPQ== -"@ledgerhq/hw-app-btc@^4.32.0", "@ledgerhq/hw-app-btc@^4.35.0": - version "4.35.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-btc/-/hw-app-btc-4.35.0.tgz#aafd655c988da39f774b0a4706e7f8897222f414" - integrity sha512-oX9YcQAuU+rOJm/lE7YF5+JXNppHcUv23ZltGz5CbWHnhm7Tqo4MOR8N5oSnHKlHW+IawfWCPN5PqdF7RGyQ5w== +"@ledgerhq/hw-app-btc@^4.32.0", "@ledgerhq/hw-app-btc@^4.38.6": + version "4.38.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-btc/-/hw-app-btc-4.38.6.tgz#731d2982f8d0f6d617806eebaedde46fdb0a5ad2" + integrity sha512-akJ4VPP7rg7kkyvpvNCUuU6ls4ZYD76TBXcO2fKklIgp/KZCuLW0sm0TiWguyA7N7LY0A30pKpeG+yYHJrfQig== dependencies: - "@ledgerhq/hw-transport" "^4.35.0" + "@ledgerhq/hw-transport" "^4.38.6" create-hash "^1.1.3" -"@ledgerhq/hw-app-eth@^4.32.0", "@ledgerhq/hw-app-eth@^4.35.0": - version "4.35.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.35.0.tgz#3a8c1b0db87224a24ff5441a0e819122e5585f2d" - integrity sha512-MSDr8+CaoXhtm64ELuI/8wpcfmrMUjzGJgASY6bnjc82vAW+6sHNZlTU0zWRTZxqQUuZ8WpuJP159cf92MWq3g== +"@ledgerhq/hw-app-eth@^4.32.0", "@ledgerhq/hw-app-eth@^4.38.6": + version "4.38.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.38.6.tgz#4a7c3bfa41a376b9d932379039cb7bce075d80b4" + integrity sha512-wy8L5ng9EOqdUUEMEOyNf6LrbuhonXCXTdLilppPMPtxwd9vqAMZ2WMoD0glnSvW/eVRL76KhpvKXabEyvmEEg== dependencies: - "@ledgerhq/hw-transport" "^4.35.0" + "@ledgerhq/hw-transport" "^4.38.6" -"@ledgerhq/hw-app-xrp@^4.32.0", "@ledgerhq/hw-app-xrp@^4.35.0": - version "4.35.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-xrp/-/hw-app-xrp-4.35.0.tgz#f6aec06ae53f8732d90f745963a2de96c2ffa432" - integrity sha512-kQLdr9xrYvkFR9+QVyTNtmSGFDfrQ63ac0QhWKEoILiiQ0dxfZ7qCCp/qPJk/sx9H8dMX37X6y+xAnSU1frbfg== +"@ledgerhq/hw-app-xrp@^4.32.0", "@ledgerhq/hw-app-xrp@^4.38.6": + version "4.38.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-xrp/-/hw-app-xrp-4.38.6.tgz#4b22a8980ca2ef9e52456d6128dd86d7191e18fa" + integrity sha512-5KB+eGeLVV6Q2dygyEpLa5gxmt9B5vs63Q1S9kzgJejKeZx2pJDN9Hu65okZ5JZMDLN+yzrsOmjLUuoJKtIOuA== dependencies: - "@ledgerhq/hw-transport" "^4.35.0" + "@ledgerhq/hw-transport" "^4.38.6" bip32-path "0.4.2" -"@ledgerhq/hw-transport-node-hid@^4.35.0": - version "4.35.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-4.35.0.tgz#0eba08e5edd14a8c779ebaf73ec21976ee5f112e" - integrity sha512-Otnymk9B7qCEfjych/SvTvJsMM+DqyoB0saEwL80ukjuGFqMunecrG5w8nC4aCc169IVz70Spkg2uU90TBUCuw== +"@ledgerhq/hw-transport-node-hid@^4.38.6": + version "4.38.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-4.38.6.tgz#c87b78008247fbb54c57f5b6125d5db09af42dd3" + integrity sha512-fJZ0I5lOeScTBC/6dq2UTc+dwllC4LIPrLpwE1QsR5ku7dARF290v1RHd+Cz+eY4On3cQ9XjoAIxjMNH+sfvfA== dependencies: - "@ledgerhq/hw-transport" "^4.35.0" + "@ledgerhq/devices" "^4.38.0" + "@ledgerhq/errors" "^4.38.0" + "@ledgerhq/hw-transport" "^4.38.6" lodash "^4.17.11" - node-hid "^0.7.2" - usb "^1.3.3" + node-hid "^0.7.6" + usb "^1.5.0" -"@ledgerhq/hw-transport@^4.21.0", "@ledgerhq/hw-transport@^4.32.0", "@ledgerhq/hw-transport@^4.35.0": - version "4.35.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-4.35.0.tgz#aa7b851111ed759cd7489fa07a7b34c1773e8314" - integrity sha512-o8ekdoCkHMvOByIKDmAMNDjm8Q5cu+sbqmebPtGrHAPbgIZBUbNA5UupY/Om+xypdxXYnuBw+MF8FyIVOjnIsg== +"@ledgerhq/hw-transport@^4.21.0", "@ledgerhq/hw-transport@^4.32.0", "@ledgerhq/hw-transport@^4.38.6": + version "4.38.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-4.38.6.tgz#a7a2d24d87f16f507c1e00dbdfb246dae9adc7a8" + integrity sha512-zRKarFc6bp3zcLNiku+ObAeawHevsvMEqkJo7hdSarKFBb8TjBBiS8CDIXy3xs9651HtZNOv6WHGTQFHdBbcwA== dependencies: + "@ledgerhq/devices" "^4.38.0" + "@ledgerhq/errors" "^4.38.0" events "^3.0.0" "@ledgerhq/ledger-core@2.0.0-rc.16": @@ -4172,6 +4183,13 @@ bindings@^1.3.0: resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5" integrity sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew== +bindings@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.4.0.tgz#909efa49f2ebe07ecd3cb136778f665052040127" + integrity sha512-7znEVX22Djn+nYjxCWKDne0RRloa9XfYa84yk3s+HkE3LpDYZmhArYr9O9huBoHY3/oXispx5LorIX7Sl2CgSQ== + dependencies: + file-uri-to-path "1.0.0" + bip32-path@0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/bip32-path/-/bip32-path-0.4.2.tgz#5db0416ad6822712f077836e2557b8697c0c7c99" @@ -7844,6 +7862,11 @@ file-loader@^1.1.11: loader-utils "^1.0.2" schema-utils "^0.4.5" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -11330,16 +11353,21 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@^2.10.0, nan@^2.8.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.0.tgz#9d443fdb5e13a20770cc5e602eee59760a685885" - integrity sha512-zT5nC0JhbljmyEf+Z456nvm7iO7XgRV2hYxoBtPpnyp+0Q4aCoP6uWNn76v/I6k2kCYNLWqWbwBWQcjsNI/bjw== +nan@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== nan@^2.2.1, nan@^2.6.2, nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== +nan@^2.8.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.0.tgz#9d443fdb5e13a20770cc5e602eee59760a685885" + integrity sha512-zT5nC0JhbljmyEf+Z456nvm7iO7XgRV2hYxoBtPpnyp+0Q4aCoP6uWNn76v/I6k2kCYNLWqWbwBWQcjsNI/bjw== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -11417,6 +11445,13 @@ node-abi@^2.2.0: dependencies: semver "^5.4.1" +node-abi@^2.7.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.1.tgz#a8997ae91176a5fbaa455b194976e32683cda643" + integrity sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw== + dependencies: + semver "^5.4.1" + node-dir@0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" @@ -11465,14 +11500,14 @@ node-gyp@^3.6.0: tar "^2.0.0" which "1" -node-hid@^0.7.2: - version "0.7.4" - resolved "https://registry.yarnpkg.com/node-hid/-/node-hid-0.7.4.tgz#2db109acee654b56bf518ffb3fd92cf9cd0647c1" - integrity sha512-gvgNDPoszObn7avIDYMUvVv1T0xQB4/CZFJWckra/LXAc0qHYho4M1LCnCKlLIocL2R5/3qGv0J4AjRMdwgjxg== +node-hid@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/node-hid/-/node-hid-0.7.6.tgz#61523694f1111d209fca55bb704732dad029f3bc" + integrity sha512-cjbjL1CmOpImKQrqkvQKZUWuzvofwECZQ50zoih5vtPRowIZ4TFJDTN3tJYfVhbQYM9PGqDFXLcTILjx9EPvzw== dependencies: - bindings "^1.3.0" - nan "^2.10.0" - prebuild-install "^5.2.1" + bindings "^1.3.1" + nan "^2.12.1" + prebuild-install "^5.2.2" node-int64@^0.4.0: version "0.4.0" @@ -12769,10 +12804,10 @@ prebuild-install@^2.0.0: tunnel-agent "^0.6.0" which-pm-runs "^1.0.0" -prebuild-install@^5.2.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.2.tgz#237888f21bfda441d0ee5f5612484390bccd4046" - integrity sha512-4e8VJnP3zJdZv/uP0eNWmr2r9urp4NECw7Mt1OSAi3rcLrbBRxGiAkfUFtre2MhQ5wfREAjRV+K1gubvs/GPsA== +prebuild-install@^5.2.2: + version "5.2.4" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.4.tgz#8cc41a217ef778a31d3a876fe6668d05406db750" + integrity sha512-CG3JnpTZXdmr92GW4zbcba4jkDha6uHraJ7hW4Fn8j0mExxwOKK20hqho8ZuBDCKYCHYIkFM1P2jhtG+KpP4fg== dependencies: detect-libc "^1.0.3" expand-template "^2.0.3" @@ -12780,7 +12815,7 @@ prebuild-install@^5.2.1: minimist "^1.2.0" mkdirp "^0.5.1" napi-build-utils "^1.0.1" - node-abi "^2.2.0" + node-abi "^2.7.0" noop-logger "^0.1.1" npmlog "^4.0.1" os-homedir "^1.0.1" @@ -16165,7 +16200,7 @@ url@^0.11.0, url@~0.11.0: punycode "1.3.2" querystring "0.2.0" -usb@^1.3.3: +usb@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/usb/-/usb-1.5.0.tgz#3e07b23c6dacf06a7c8801ae913926702a818218" integrity sha512-/0stiQEmweuO2BKv2avzQQ8ypDUjo4Osz5sSEi+d0F4Rc+ddX1xED3uf4Tkelc1eADlfn0JQZYHP0bI7CNDA0Q== From 0484c3aaf959330c2c8a76a3e158435a8f1a83a5 Mon Sep 17 00:00:00 2001 From: Dimitri Sabadie Date: Fri, 15 Feb 2019 15:41:57 +0100 Subject: [PATCH 05/23] Fix IPC code for resetting libcore. --- src/commands/index.js | 2 ++ src/commands/libcoreReset.js | 15 +++++++++++++++ src/helpers/reset.js | 4 ++-- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/commands/libcoreReset.js diff --git a/src/commands/index.js b/src/commands/index.js index 893c6d53..f158dba1 100644 --- a/src/commands/index.js +++ b/src/commands/index.js @@ -16,6 +16,7 @@ import installApp from 'commands/installApp' import killInternalProcess from 'commands/killInternalProcess' import libcoreGetFees from 'commands/libcoreGetFees' import libcoreGetVersion from 'commands/libcoreGetVersion' +import libcoreReset from 'commands/libcoreReset' import libcoreScanAccounts from 'commands/libcoreScanAccounts' import libcoreScanFromXPUB from 'commands/libcoreScanFromXPUB' import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast' @@ -44,6 +45,7 @@ const all: Array> = [ killInternalProcess, libcoreGetFees, libcoreGetVersion, + libcoreReset, libcoreScanAccounts, libcoreScanFromXPUB, libcoreSignAndBroadcast, diff --git a/src/commands/libcoreReset.js b/src/commands/libcoreReset.js new file mode 100644 index 00000000..6ca30cd0 --- /dev/null +++ b/src/commands/libcoreReset.js @@ -0,0 +1,15 @@ +// @flow + +import { createCommand, Command } from 'helpers/ipc' +import { of } from 'rxjs' +import withLibcore from 'helpers/withLibcore' + +type Input = void +type Result = boolean + +const cmd: Command = createCommand('libcoreReset', () => { + withLibcore(core => core.getPoolInstance().freshResetAll()) + return of(true) +}) + +export default cmd diff --git a/src/helpers/reset.js b/src/helpers/reset.js index a8103a6b..f198a60d 100644 --- a/src/helpers/reset.js +++ b/src/helpers/reset.js @@ -6,11 +6,11 @@ import { disable as disableDBMiddleware } from 'middlewares/db' import db from 'helpers/db' import { delay } from 'helpers/promise' import killInternalProcess from 'commands/killInternalProcess' -import withLibcore from 'helpers/withLibcore' +import libcoreReset from 'commands/libcoreReset' async function resetLibcore() { + await libcoreReset.send().toPromise() await killInternalProcess.send().toPromise() - withLibcore(core => core.freshResetAll()) } function reload() { From 0cf43de2404debd184d21b13d4478de07ca7ddeb Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Wed, 13 Feb 2019 17:58:50 +0100 Subject: [PATCH 06/23] fix ci job --- .circleci/config.yml | 2 +- package.json | 10 +++--- yarn.lock | 74 ++++++++++++++++++++++---------------------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e590dbc9..79faeabd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ jobs: <<: *defaults steps: - run: sudo apt-get update - - run: sudo apt-get install -y libudev-dev + - run: sudo apt-get install -y libudev-dev libusb-1.0-0-dev - run: name: Install latest yarn command: | diff --git a/package.json b/package.json index c102b4f6..d0ff8dda 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,11 @@ }, "dependencies": { "@ledgerhq/errors": "^4.39.0", - "@ledgerhq/hw-app-btc": "^4.38.6", - "@ledgerhq/hw-app-eth": "^4.38.6", - "@ledgerhq/hw-app-xrp": "^4.38.6", - "@ledgerhq/hw-transport": "^4.38.6", - "@ledgerhq/hw-transport-node-hid": "^4.38.6", + "@ledgerhq/hw-app-btc": "^4.39.0", + "@ledgerhq/hw-app-eth": "^4.39.0", + "@ledgerhq/hw-app-xrp": "^4.39.0", + "@ledgerhq/hw-transport": "^4.39.0", + "@ledgerhq/hw-transport-node-hid": "^4.40.0", "@ledgerhq/ledger-core": "2.0.0-rc.16", "@ledgerhq/live-common": "4.16.1", "animated": "^0.2.2", diff --git a/yarn.lock b/yarn.lock index 035f98db..57a58e38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1677,60 +1677,60 @@ camelcase "^5.0.0" prettier "^1.13.7" -"@ledgerhq/devices@^4.38.0": - version "4.38.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-4.38.0.tgz#06e4ac7f1e49827b9cd32c34c2f20c28c3b42fdc" - integrity sha512-6XfuSoJIXmW6xloWNdXDNsL8JZrUb4Xh9pKwh7NzxqQx50rqQ0JI1wxrZQJB0ZRevnk0SCMbIbT6aQOxmF8CIg== +"@ledgerhq/devices@^4.39.0": + version "4.39.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-4.39.0.tgz#47d23a1a58004da162e007e0c456ab2119038c7d" + integrity sha512-2Jd7CVvMJDZxxaSpQpfOMeGWf7M0f6nZqZQWfjsUDQHw45Kunck101pXr6U/5UejJiLl/fhyLqvaXz0X0cs+1A== dependencies: - "@ledgerhq/errors" "^4.38.0" + "@ledgerhq/errors" "^4.39.0" -"@ledgerhq/errors@^4.32.0", "@ledgerhq/errors@^4.38.0": - version "4.38.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-4.38.0.tgz#5260118b2cb1069f706d9316bf6f2ee1f6935f43" - integrity sha512-ZVpwiQV4y6OqMcOhZ7xQR37xpZdYGXnZftlYtT9muzXrak/HPHc19oPpwiuqKmHAbgfio6qEVk9Lp3yWLY9bPQ== +"@ledgerhq/errors@^4.32.0", "@ledgerhq/errors@^4.39.0": + version "4.39.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-4.39.0.tgz#10b9889f78df94ce36a4b34d9a3a45aac77be0e9" + integrity sha512-kBr2rnoYDACRCxTLtEufE4oCvYj6vx2oFWVVjwskBxYsF5LC9R8Mbg5C4GgvDweiWW4Io8HA9p9jCsOfdCDygg== -"@ledgerhq/hw-app-btc@^4.32.0", "@ledgerhq/hw-app-btc@^4.38.6": - version "4.38.6" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-btc/-/hw-app-btc-4.38.6.tgz#731d2982f8d0f6d617806eebaedde46fdb0a5ad2" - integrity sha512-akJ4VPP7rg7kkyvpvNCUuU6ls4ZYD76TBXcO2fKklIgp/KZCuLW0sm0TiWguyA7N7LY0A30pKpeG+yYHJrfQig== +"@ledgerhq/hw-app-btc@^4.32.0", "@ledgerhq/hw-app-btc@^4.39.0": + version "4.39.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-btc/-/hw-app-btc-4.39.0.tgz#5b564e683a43a50002579834ec54aa790fde35f1" + integrity sha512-xPOtoIgsErycMFTKHb0yHLqlKn0C+9msLBsA1zRPNsWMdxEEBO5pzFVmn5ha1j3q/73yeICHlcB4KZcTb7CShA== dependencies: - "@ledgerhq/hw-transport" "^4.38.6" + "@ledgerhq/hw-transport" "^4.39.0" create-hash "^1.1.3" -"@ledgerhq/hw-app-eth@^4.32.0", "@ledgerhq/hw-app-eth@^4.38.6": - version "4.38.6" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.38.6.tgz#4a7c3bfa41a376b9d932379039cb7bce075d80b4" - integrity sha512-wy8L5ng9EOqdUUEMEOyNf6LrbuhonXCXTdLilppPMPtxwd9vqAMZ2WMoD0glnSvW/eVRL76KhpvKXabEyvmEEg== +"@ledgerhq/hw-app-eth@^4.32.0", "@ledgerhq/hw-app-eth@^4.39.0": + version "4.39.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.39.0.tgz#3cbba1f1650665c4c29c7b9fa246cb2360495867" + integrity sha512-IKPcLTcGohh/S6Z1LaAfn2pGyxfT6xu958/xV+5H4a3Ej0CWKaxcno4FkhaxH4OiViF0F5SEFzxtH+UntH2jdg== dependencies: - "@ledgerhq/hw-transport" "^4.38.6" + "@ledgerhq/hw-transport" "^4.39.0" -"@ledgerhq/hw-app-xrp@^4.32.0", "@ledgerhq/hw-app-xrp@^4.38.6": - version "4.38.6" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-xrp/-/hw-app-xrp-4.38.6.tgz#4b22a8980ca2ef9e52456d6128dd86d7191e18fa" - integrity sha512-5KB+eGeLVV6Q2dygyEpLa5gxmt9B5vs63Q1S9kzgJejKeZx2pJDN9Hu65okZ5JZMDLN+yzrsOmjLUuoJKtIOuA== +"@ledgerhq/hw-app-xrp@^4.32.0", "@ledgerhq/hw-app-xrp@^4.39.0": + version "4.39.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-xrp/-/hw-app-xrp-4.39.0.tgz#cc399649f17873778e34bcde16f488faef3117e5" + integrity sha512-lbrG7AhQdJzt/zhu0G5yfC2t4zlytWuzbNLrPp/VQKJJPUKsC98H81pmfMzn1lFBdm8frmBVUW6reN5p7wDS2Q== dependencies: - "@ledgerhq/hw-transport" "^4.38.6" + "@ledgerhq/hw-transport" "^4.39.0" bip32-path "0.4.2" -"@ledgerhq/hw-transport-node-hid@^4.38.6": - version "4.38.6" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-4.38.6.tgz#c87b78008247fbb54c57f5b6125d5db09af42dd3" - integrity sha512-fJZ0I5lOeScTBC/6dq2UTc+dwllC4LIPrLpwE1QsR5ku7dARF290v1RHd+Cz+eY4On3cQ9XjoAIxjMNH+sfvfA== +"@ledgerhq/hw-transport-node-hid@^4.40.0": + version "4.40.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-4.40.0.tgz#7f35194f94e20374e1bd6a04e5299032c5e81b6c" + integrity sha512-Nxp2Ys5lxgWTUG/A+W7O3nemkIBigW0LSJI6QrCDdLDg7deU+Zp6QA/CDS95BLijqi5m0AqKE2U4IyQh4OFnhQ== dependencies: - "@ledgerhq/devices" "^4.38.0" - "@ledgerhq/errors" "^4.38.0" - "@ledgerhq/hw-transport" "^4.38.6" + "@ledgerhq/devices" "^4.39.0" + "@ledgerhq/errors" "^4.39.0" + "@ledgerhq/hw-transport" "^4.39.0" lodash "^4.17.11" node-hid "^0.7.6" usb "^1.5.0" -"@ledgerhq/hw-transport@^4.21.0", "@ledgerhq/hw-transport@^4.32.0", "@ledgerhq/hw-transport@^4.38.6": - version "4.38.6" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-4.38.6.tgz#a7a2d24d87f16f507c1e00dbdfb246dae9adc7a8" - integrity sha512-zRKarFc6bp3zcLNiku+ObAeawHevsvMEqkJo7hdSarKFBb8TjBBiS8CDIXy3xs9651HtZNOv6WHGTQFHdBbcwA== +"@ledgerhq/hw-transport@^4.21.0", "@ledgerhq/hw-transport@^4.32.0", "@ledgerhq/hw-transport@^4.39.0": + version "4.39.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-4.39.0.tgz#602c6ea3fef56d1df205274ea742b4cf85613f6c" + integrity sha512-XkVAy2SFRDdE3qQGGVxB7RQdsdIx1fcoRNReU7NQXK59fYqxue+ZoiGtynEoHq9RKMg8EBG2kBXSVEh1iPdOlA== dependencies: - "@ledgerhq/devices" "^4.38.0" - "@ledgerhq/errors" "^4.38.0" + "@ledgerhq/devices" "^4.39.0" + "@ledgerhq/errors" "^4.39.0" events "^3.0.0" "@ledgerhq/ledger-core@2.0.0-rc.16": From 404f036e1598e24d29ccef58ce292abad2f60e5c Mon Sep 17 00:00:00 2001 From: Dimitri Sabadie Date: Fri, 15 Feb 2019 16:42:41 +0100 Subject: [PATCH 07/23] Use a safer way to call the reset code in the libcoreReset cmd. --- src/commands/libcoreReset.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/libcoreReset.js b/src/commands/libcoreReset.js index 6ca30cd0..30d56139 100644 --- a/src/commands/libcoreReset.js +++ b/src/commands/libcoreReset.js @@ -1,15 +1,15 @@ // @flow import { createCommand, Command } from 'helpers/ipc' -import { of } from 'rxjs' +import { from } from 'rxjs' import withLibcore from 'helpers/withLibcore' type Input = void type Result = boolean -const cmd: Command = createCommand('libcoreReset', () => { - withLibcore(core => core.getPoolInstance().freshResetAll()) - return of(true) -}) +const cmd: Command = createCommand( + 'libcoreReset', + () => from(withLibcore(core => core.getPoolInstance().freshResetAll())) +) export default cmd From ee28174cc703b246e46c7c4cef225801c89ef73b Mon Sep 17 00:00:00 2001 From: Juan Cortes Ross Date: Wed, 13 Feb 2019 17:16:01 +0100 Subject: [PATCH 08/23] Version bump for live-common to benefit from partners refactoring --- .flowconfig | 3 +++ package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.flowconfig b/.flowconfig index b7155c37..9a82dfc0 100644 --- a/.flowconfig +++ b/.flowconfig @@ -6,6 +6,8 @@ [untyped] .*/node_modules/react-select /node_modules/qrloop/lib/Buffer.js* +/node_modules/@ledgerhq/live-common/lib/partners/icons/react/* +/node_modules/@ledgerhq/live-common/lib/partners/react.jsarn [include] @@ -18,5 +20,6 @@ flow-defs [options] module.system.node.resolve_dirname=node_modules module.system.node.resolve_dirname=./src +munge_underscores=true [strict] diff --git a/package.json b/package.json index 02fb1dae..8eb80e56 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@ledgerhq/hw-transport": "^4.35.0", "@ledgerhq/hw-transport-node-hid": "^4.35.0", "@ledgerhq/ledger-core": "2.0.0-rc.16", - "@ledgerhq/live-common": "4.16.1", + "@ledgerhq/live-common": "4.18.0", "animated": "^0.2.2", "async": "^2.6.1", "axios": "^0.18.0", diff --git a/yarn.lock b/yarn.lock index cae22ea3..656f58e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1730,10 +1730,10 @@ bindings "^1.3.0" nan "^2.6.2" -"@ledgerhq/live-common@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-4.16.1.tgz#9b8d29bad5867f422566b51ba8ef262ba32a49ae" - integrity sha512-a0ckySEeCj+xnSr6zkbx2uFri3W+uHbEf0I5HIUjm7hXP4N36Rm8vPP+xR5oHpzIaj1DzpcFVDIBm9TgIhXwMA== +"@ledgerhq/live-common@4.18.0": + version "4.18.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-4.18.0.tgz#0e087e18ec147feaebfaf66e6346138b4a7e4fd2" + integrity sha512-hcIzeuw96T2eYm13KYatg32zNyl5o16yyJrc+C+xB5mG0FeL6zSAEvodLsLqVIeJ22YXl5lVAlx8y4VVI0AseA== dependencies: "@aeternity/ledger-app-api" "0.0.4" "@ledgerhq/errors" "^4.32.0" From b5bacfb22893da42313abc8bbf3851db2b8cc342 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Mon, 18 Feb 2019 15:51:31 +0100 Subject: [PATCH 09/23] update for nano x --- package.json | 1 + src/analytics/segment.js | 3 ++- src/components/ManagerPage/DeviceInfos.js | 7 ++++--- src/components/ManagerPage/FirmwareUpdate.js | 13 +++++++------ src/renderer/events.js | 11 ++++++++--- src/types/common.js | 5 +---- static/i18n/en/app.json | 4 +--- 7 files changed, 24 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index d0ff8dda..66670729 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ } }, "dependencies": { + "@ledgerhq/devices": "^4.39.0", "@ledgerhq/errors": "^4.39.0", "@ledgerhq/hw-app-btc": "^4.39.0", "@ledgerhq/hw-app-eth": "^4.39.0", diff --git a/src/analytics/segment.js b/src/analytics/segment.js index 0d5f01e7..dacff414 100644 --- a/src/analytics/segment.js +++ b/src/analytics/segment.js @@ -3,6 +3,7 @@ import uuid from 'uuid/v4' import logger from 'logger' import invariant from 'invariant' +import { getDeviceModel } from '@ledgerhq/devices' import { getSystemLocale } from 'helpers/systemLocale' import { langAndRegionSelector, shareAnalyticsSelector } from 'reducers/settings' import { getCurrentDevice } from 'reducers/devices' @@ -34,7 +35,7 @@ const extraProperties = store => { const systemLocale = getSystemLocale() const device = getCurrentDevice(state) const deviceInfo = device && { - productId: device.productId, + productId: getDeviceModel(device.modelId).usbProductId, } return { appVersion: __APP_VERSION__, diff --git a/src/components/ManagerPage/DeviceInfos.js b/src/components/ManagerPage/DeviceInfos.js index df2c87c2..b60e5db0 100644 --- a/src/components/ManagerPage/DeviceInfos.js +++ b/src/components/ManagerPage/DeviceInfos.js @@ -5,7 +5,7 @@ import React, { PureComponent } from 'react' import Text from 'components/base/Text' import Box, { Card } from 'components/base/Box' import Button from 'components/base/Button' - +import { getDeviceModel } from '@ledgerhq/devices' import type { Device, MemoryInfos } from 'types/common' import MemInfos from './MemInfos' @@ -43,10 +43,11 @@ class DeviceInfos extends PureComponent { return {'You dont have any device connected'} } + const deviceInfos = getDeviceModel(device.modelId) + const title = ( - {device.manufacturer} - {` ${device.product}`} + {`${deviceInfos.productName}`} ) return ( diff --git a/src/components/ManagerPage/FirmwareUpdate.js b/src/components/ManagerPage/FirmwareUpdate.js index 9eb9d547..85af33fa 100644 --- a/src/components/ManagerPage/FirmwareUpdate.js +++ b/src/components/ManagerPage/FirmwareUpdate.js @@ -3,10 +3,10 @@ import React, { PureComponent, Fragment } from 'react' import { translate } from 'react-i18next' +import { getDeviceModel } from '@ledgerhq/devices' +import type { DeviceInfo, FirmwareUpdateContext } from '@ledgerhq/live-common/lib/types/manager' import type { Device, T } from 'types/common' - -import type { DeviceInfo, FirmwareUpdateContext } from '@ledgerhq/live-common/lib/types/manager' import type { StepId } from 'components/modals/UpdateFirmware' import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice' @@ -81,18 +81,19 @@ class FirmwareUpdate extends PureComponent { render() { const { deviceInfo, t, device } = this.props const { firmware, modal, stepId, ready } = this.state + + const deviceSpecs = getDeviceModel(device.modelId) + return ( - {device.product === 'Blue' ? : } + {deviceSpecs.id === 'blue' ? : } - {device.product === 'Blue' - ? t('manager.firmware.titleBlue') - : t('manager.firmware.titleNano')} + {deviceSpecs.productName} t('manager.yourDeviceIsGenuine')}> diff --git a/src/renderer/events.js b/src/renderer/events.js index f233913c..0ef0920c 100644 --- a/src/renderer/events.js +++ b/src/renderer/events.js @@ -51,14 +51,19 @@ export default ({ store }: { store: Object }) => { function syncDevices() { syncDeviceSub = listenDevices.send().subscribe( - ({ device, type }) => { + ({ device, deviceModel, type }) => { if (device) { + const stateDevice = { + path: device.path, + modelId: deviceModel ? deviceModel.id : 'nanoS', + type: 'hid', + } if (type === 'add') { d.device('Device - add') - store.dispatch(addDevice(device)) + store.dispatch(addDevice(stateDevice)) } else if (type === 'remove') { d.device('Device - remove') - store.dispatch(removeDevice(device)) + store.dispatch(removeDevice(stateDevice)) } } }, diff --git a/src/types/common.js b/src/types/common.js index 84ccc162..c219b115 100644 --- a/src/types/common.js +++ b/src/types/common.js @@ -1,11 +1,8 @@ // @flow export type Device = { - manufacturer: string, path: string, - product: string, - productId: string, - vendorId: string, + modelId: string, } // -------------------- Settings diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json index 9aed68e6..e3dbe1b8 100644 --- a/static/i18n/en/app.json +++ b/static/i18n/en/app.json @@ -254,8 +254,6 @@ }, "firmware": { "installed": "Firmware version {{version}}", - "titleNano": "Ledger Nano S", - "titleBlue": "Ledger Blue", "update": "Update", "latest": "Firmware version {{version}} is available", "disclaimerTitle": "You are about to install <1><0>firmware version {{version}}.", @@ -933,4 +931,4 @@ "description": "Please contact Ledger Support" } } -} +} \ No newline at end of file From a27a9d16f9c9d0d313f8ebf9e91c6aba909bbc32 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 19 Feb 2019 12:02:37 +0100 Subject: [PATCH 10/23] refactor onboarding state for new types of devices --- src/components/Onboarding/index.js | 6 ++--- src/components/Onboarding/steps/Analytics.js | 3 ++- src/components/Onboarding/steps/Finish.js | 3 ++- .../GenuineCheck/GenuineCheckErrorPage.js | 5 ++-- .../GenuineCheck/GenuineCheckUnavailable.js | 4 +++- .../Onboarding/steps/GenuineCheck/index.js | 4 +++- .../Onboarding/steps/SelectDevice.js | 23 ++++++++++--------- .../Onboarding/steps/SelectPIN/index.js | 11 ++++++--- .../Onboarding/steps/SetPassword.js | 3 ++- .../steps/WriteSeed/WriteSeedRestore.js | 2 +- .../Onboarding/steps/WriteSeed/index.js | 5 ++-- src/helpers/devices.js | 18 +++++++++++++++ src/reducers/onboarding.js | 12 ++++++---- 13 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 src/helpers/devices.js diff --git a/src/components/Onboarding/index.js b/src/components/Onboarding/index.js index 557567bc..8ced1375 100644 --- a/src/components/Onboarding/index.js +++ b/src/components/Onboarding/index.js @@ -19,7 +19,7 @@ import { prevStep, jumpStep, updateGenuineCheck, - isLedgerNano, + deviceType, flowType, relaunchOnboarding, onboardingRelaunchedSelector, @@ -102,7 +102,7 @@ export type StepProps = { getDeviceInfo: Function, updateGenuineCheck: Function, openModal: Function, - isLedgerNano: Function, + deviceType: Function, flowType: Function, } @@ -171,7 +171,7 @@ class Onboarding extends PureComponent { settings, updateGenuineCheck, openModal, - isLedgerNano, + deviceType, flowType, prevStep, nextStep, diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 6e1a01d0..4a3893e8 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -13,6 +13,7 @@ import Track from 'analytics/Track' import { openModal } from 'reducers/modals' import { MODAL_SHARE_ANALYTICS, MODAL_TECHNICAL_DATA } from 'config/constants' import { openURL } from 'helpers/linking' +import { cleanDeviceName } from 'helpers/devices' import { urls } from 'config/urls' import ShareAnalytics from '../../modals/ShareAnalytics' import TechnicalData from '../../modals/TechnicalData' @@ -73,7 +74,7 @@ class Analytics extends PureComponent { category="Onboarding" name="Analytics" flowType={onboarding.flowType} - deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} + deviceType={cleanDeviceName(onboarding.deviceType)} /> {t('onboarding.analytics.title')} diff --git a/src/components/Onboarding/steps/Finish.js b/src/components/Onboarding/steps/Finish.js index cde25867..7e465151 100644 --- a/src/components/Onboarding/steps/Finish.js +++ b/src/components/Onboarding/steps/Finish.js @@ -18,6 +18,7 @@ import IconSocialReddit from 'icons/Reddit' import IconSocialGithub from 'icons/Github' import { lighten } from 'styles/helpers' +import { cleanDeviceName } from 'helpers/devices' import type { StepProps } from '..' import { Title, Description } from '../helperComponents' @@ -72,7 +73,7 @@ export default class Finish extends Component { category="Onboarding" name="Finish" flowType={onboarding.flowType} - deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} + deviceType={cleanDeviceName(onboarding.deviceType)} /> diff --git a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js index 65518f46..6fdabca2 100644 --- a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js +++ b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js @@ -11,6 +11,7 @@ import Box from 'components/base/Box' import Button from 'components/base/Button' import ExternalLinkButton from 'components/base/ExternalLinkButton' import TrackPage from 'analytics/TrackPage' +import { cleanDeviceName } from 'helpers/devices' import { Title, Description, OnboardingFooterWrapper } from '../../helperComponents' @@ -28,7 +29,7 @@ class GenuineCheckErrorPage extends PureComponent { category="Onboarding" name={`Genuine Check Error Page - ${page}`} flowType={onboarding.flowType} - deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} + deviceType={cleanDeviceName(onboarding.deviceType)} /> ) } @@ -59,7 +60,7 @@ class GenuineCheckErrorPage extends PureComponent { )} - {onboarding.isLedgerNano ? ( + {onboarding.deviceType === 'nanoS' ? ( ) : ( diff --git a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js index 727d59f3..194ce8a3 100644 --- a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js +++ b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js @@ -6,6 +6,8 @@ import { colors } from 'styles/theme' import type { T } from 'types/common' import type { OnboardingState } from 'reducers/onboarding' +import { cleanDeviceName } from 'helpers/devices' + import FakeLink from 'components/base/FakeLink' import IconExclamationCircle from 'icons/ExclamationCircle' import Box from 'components/base/Box' @@ -76,7 +78,7 @@ export function GenuineCheckUnavailableMessage({ handleOpenGenuineCheckModal() track('Genuine Check Retry', { flowType: onboarding.flowType, - deviceType: onboarding.isLedgerNano ? 'Nano S' : 'Blue', + deviceType: cleanDeviceName(onboarding.deviceType), }) }} > diff --git a/src/components/Onboarding/steps/GenuineCheck/index.js b/src/components/Onboarding/steps/GenuineCheck/index.js index b8ab0de8..3501fa67 100644 --- a/src/components/Onboarding/steps/GenuineCheck/index.js +++ b/src/components/Onboarding/steps/GenuineCheck/index.js @@ -7,6 +7,8 @@ import { colors } from 'styles/theme' import { updateGenuineCheck } from 'reducers/onboarding' +import { cleanDeviceName } from 'helpers/devices' + import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' import Button from 'components/base/Button' @@ -171,7 +173,7 @@ class GenuineCheck extends PureComponent { category="Onboarding" name="Genuine Check" flowType={onboarding.flowType} - deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} + deviceType={cleanDeviceName(onboarding.deviceType)} /> {t('onboarding.genuineCheck.title')} diff --git a/src/components/Onboarding/steps/SelectDevice.js b/src/components/Onboarding/steps/SelectDevice.js index c65e253b..9c7bd95e 100644 --- a/src/components/Onboarding/steps/SelectDevice.js +++ b/src/components/Onboarding/steps/SelectDevice.js @@ -7,7 +7,8 @@ import { i } from 'helpers/staticPath' import { rgba } from 'styles/helpers' -import { isLedgerNano } from 'reducers/onboarding' +import { deviceType } from 'reducers/onboarding' +import type { DeviceType } from 'reducers/onboarding' import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' @@ -19,11 +20,11 @@ import OnboardingFooter from '../OnboardingFooter' import type { StepProps } from '..' -const mapDispatchToProps = { isLedgerNano } +const mapDispatchToProps = { deviceType } class SelectDevice extends PureComponent { - handleIsLedgerNano = (isLedgerNano: boolean) => { - this.props.isLedgerNano(isLedgerNano) + handleDeviceType = (deviceType: DeviceType) => { + this.props.deviceType(deviceType) } handleContinue = () => { @@ -46,20 +47,20 @@ class SelectDevice extends PureComponent { this.handleIsLedgerNano(true)} + isActive={onboarding.deviceType === 'nanoS'} + onClick={() => this.handleDeviceType('nanoS')} > - {onboarding.isLedgerNano && } + {onboarding.deviceType === 'nanoS' && } {t('onboarding.selectDevice.ledgerNanoCard.title')} this.handleIsLedgerNano(false)} + isActive={onboarding.deviceType === 'blue'} + onClick={() => this.handleDeviceType('blue')} > - {!onboarding.isLedgerNano && onboarding.isLedgerNano !== null && } + {onboarding.deviceType === 'blue' && } @@ -73,7 +74,7 @@ class SelectDevice extends PureComponent { t={t} nextStep={this.handleContinue} prevStep={() => jumpStep('init')} - isContinueDisabled={onboarding.isLedgerNano === null} + isContinueDisabled={onboarding.deviceType === ''} /> ) diff --git a/src/components/Onboarding/steps/SelectPIN/index.js b/src/components/Onboarding/steps/SelectPIN/index.js index 38370eb2..40daf187 100644 --- a/src/components/Onboarding/steps/SelectPIN/index.js +++ b/src/components/Onboarding/steps/SelectPIN/index.js @@ -5,6 +5,7 @@ import React from 'react' import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' +import { cleanDeviceName } from 'helpers/devices' import GrowScroll from 'components/base/GrowScroll' import { Title, FixedTopContainer } from '../../helperComponents' import OnboardingFooter from '../../OnboardingFooter' @@ -25,20 +26,24 @@ export default (props: StepProps) => { category="Onboarding" name="Choose PIN" flowType={onboarding.flowType} - deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} + deviceType={cleanDeviceName(onboarding.deviceType)} /> {onboarding.flowType === 'restoreDevice' ? ( {t('onboarding.selectPIN.restore.title')} - {onboarding.isLedgerNano ? : } + {onboarding.deviceType === 'nanoS' ? ( + + ) : ( + + )} ) : ( {t('onboarding.selectPIN.initialize.title')} - {onboarding.isLedgerNano ? : } + {onboarding.deviceType === 'nanoS' ? : } )} diff --git a/src/components/Onboarding/steps/SetPassword.js b/src/components/Onboarding/steps/SetPassword.js index 06efaca9..b3a31abe 100644 --- a/src/components/Onboarding/steps/SetPassword.js +++ b/src/components/Onboarding/steps/SetPassword.js @@ -5,6 +5,7 @@ import { connect } from 'react-redux' import { colors } from 'styles/theme' import db from 'helpers/db' +import { cleanDeviceName } from 'helpers/devices' import { saveSettings } from 'actions/settings' import Box from 'components/base/Box' @@ -105,7 +106,7 @@ class SetPassword extends PureComponent { category="Onboarding" name="Set Password" flowType={onboarding.flowType} - deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} + deviceType={cleanDeviceName(onboarding.deviceType)} /> diff --git a/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js b/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js index a193353e..0e524cbe 100644 --- a/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js +++ b/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js @@ -123,7 +123,7 @@ class WriteSeedRestore extends PureComponent { - {onboarding.isLedgerNano ? ( + {onboarding.deviceType === 'nanoS' ? ( {stepsNano.map(step => )} diff --git a/src/components/Onboarding/steps/WriteSeed/index.js b/src/components/Onboarding/steps/WriteSeed/index.js index bcae0463..2fcb49be 100644 --- a/src/components/Onboarding/steps/WriteSeed/index.js +++ b/src/components/Onboarding/steps/WriteSeed/index.js @@ -6,6 +6,7 @@ import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' import GrowScroll from 'components/base/GrowScroll' +import { cleanDeviceName } from 'helpers/devices' import OnboardingFooter from '../../OnboardingFooter' import WriteSeedNano from './WriteSeedNano' @@ -24,12 +25,12 @@ export default (props: StepProps) => { category="Onboarding" name="Recovery Phase" flowType={onboarding.flowType} - deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} + deviceType={cleanDeviceName(onboarding.deviceType)} /> {onboarding.flowType === 'restoreDevice' ? ( - ) : onboarding.isLedgerNano ? ( + ) : onboarding.deviceType === 'nanoS' ? ( ) : ( diff --git a/src/helpers/devices.js b/src/helpers/devices.js new file mode 100644 index 00000000..3ca12baf --- /dev/null +++ b/src/helpers/devices.js @@ -0,0 +1,18 @@ +// @flow +import { getDeviceModel } from '@ledgerhq/devices' + +import type { DeviceType } from 'reducers/onboarding' + +export const deviceModelName = (id: DeviceType): string => { + const device = getDeviceModel(id) + if (device) return device.productName + + return '' +} + +export const cleanDeviceName = (id: DeviceType): string => { + const fullName = deviceModelName(id) + if (fullName) return fullName.split('Ledger ')[1] + + return '' +} diff --git a/src/reducers/onboarding.js b/src/reducers/onboarding.js index 14911cd5..59f14c18 100644 --- a/src/reducers/onboarding.js +++ b/src/reducers/onboarding.js @@ -15,6 +15,8 @@ type Step = { }, } +export type DeviceType = 'nanoX' | 'nanoS' | 'blue' | '' + export type OnboardingState = { stepIndex: number, stepName: string, // TODO: specify that the string comes from Steps type @@ -27,7 +29,7 @@ export type OnboardingState = { genuineCheckUnavailable: ?Error, displayErrorScreen: boolean, }, - isLedgerNano: boolean | null, + deviceType: DeviceType, flowType: string, onboardingRelaunched?: boolean, } @@ -43,7 +45,7 @@ const initialState: OnboardingState = { genuineCheckUnavailable: null, displayErrorScreen: false, }, - isLedgerNano: null, + deviceType: '', flowType: '', onboardingRelaunched: false, steps: [ @@ -167,9 +169,9 @@ const handlers = { ...state, flowType, }), - ONBOARDING_SET_DEVICE_TYPE: (state: OnboardingState, { payload: isLedgerNano }) => ({ + ONBOARDING_SET_DEVICE_TYPE: (state: OnboardingState, { payload: deviceType }) => ({ ...state, - isLedgerNano, + deviceType, }), ONBOARDING_RELAUNCH: (state: OnboardingState, { payload: onboardingRelaunched }) => ({ ...initialState, @@ -187,5 +189,5 @@ export const nextStep = createAction('ONBOARDING_NEXT_STEP') export const prevStep = createAction('ONBOARDING_PREV_STEP') export const jumpStep = createAction('ONBOARDING_JUMP_STEP') export const updateGenuineCheck = createAction('UPDATE_GENUINE_CHECK') -export const isLedgerNano = createAction('ONBOARDING_SET_DEVICE_TYPE') +export const deviceType = createAction('ONBOARDING_SET_DEVICE_TYPE') export const flowType = createAction('ONBOARDING_SET_FLOW_TYPE') From 51e9dfb320ea9564b2e5744b4e21fb9817cfbc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Tue, 19 Feb 2019 14:02:31 +0100 Subject: [PATCH 11/23] stop the sync when opening the Clean/Reset modals --- src/components/SettingsPage/CleanButton.js | 5 ++++- src/components/SettingsPage/ResetButton.js | 5 ++++- src/components/base/Modal/ConfirmModal.js | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/SettingsPage/CleanButton.js b/src/components/SettingsPage/CleanButton.js index 8a3081ea..f1954aa4 100644 --- a/src/components/SettingsPage/CleanButton.js +++ b/src/components/SettingsPage/CleanButton.js @@ -6,6 +6,7 @@ import { translate } from 'react-i18next' import logger from 'logger' import type { T } from 'types/common' import { cleanAccountsCache } from 'actions/accounts' +import SyncSkipUnderPriority from 'components/SyncSkipUnderPriority' import Button from 'components/base/Button' import ConfirmModal from 'components/base/Modal/ConfirmModal' import { softReset } from 'helpers/reset' @@ -69,7 +70,9 @@ class CleanButton extends PureComponent { title={t('settings.softResetModal.title')} subTitle={t('common.areYouSure')} desc={t('settings.softResetModal.desc')} - /> + > + + diff --git a/src/components/SettingsPage/ResetButton.js b/src/components/SettingsPage/ResetButton.js index 2708c75e..daa282b2 100644 --- a/src/components/SettingsPage/ResetButton.js +++ b/src/components/SettingsPage/ResetButton.js @@ -7,6 +7,7 @@ import { translate } from 'react-i18next' import logger from 'logger' import type { T } from 'types/common' import { hardReset } from 'helpers/reset' +import SyncSkipUnderPriority from 'components/SyncSkipUnderPriority' import Box from 'components/base/Box' import Button from 'components/base/Button' import ConfirmModal from 'components/base/Modal/ConfirmModal' @@ -73,7 +74,9 @@ class ResetButton extends PureComponent { )} - /> + > + + diff --git a/src/components/base/Modal/ConfirmModal.js b/src/components/base/Modal/ConfirmModal.js index 416eb5a7..06066bc9 100644 --- a/src/components/base/Modal/ConfirmModal.js +++ b/src/components/base/Modal/ConfirmModal.js @@ -50,6 +50,7 @@ class ConfirmModal extends PureComponent { t, analyticsName, centered, + children, ...props } = this.props @@ -91,6 +92,7 @@ class ConfirmModal extends PureComponent { {desc} + {children} )} /> From 986032e7c83f312619c3b89ac3a87c3b5a0a67b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Tue, 19 Feb 2019 14:02:50 +0100 Subject: [PATCH 12/23] kill before clearing --- src/commands/libcoreReset.js | 5 ++--- src/helpers/reset.js | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/commands/libcoreReset.js b/src/commands/libcoreReset.js index 30d56139..9e3d9f3e 100644 --- a/src/commands/libcoreReset.js +++ b/src/commands/libcoreReset.js @@ -7,9 +7,8 @@ import withLibcore from 'helpers/withLibcore' type Input = void type Result = boolean -const cmd: Command = createCommand( - 'libcoreReset', - () => from(withLibcore(core => core.getPoolInstance().freshResetAll())) +const cmd: Command = createCommand('libcoreReset', () => + from(withLibcore(core => core.getPoolInstance().freshResetAll())), ) export default cmd diff --git a/src/helpers/reset.js b/src/helpers/reset.js index f198a60d..d0ead9ca 100644 --- a/src/helpers/reset.js +++ b/src/helpers/reset.js @@ -9,8 +9,10 @@ import killInternalProcess from 'commands/killInternalProcess' import libcoreReset from 'commands/libcoreReset' async function resetLibcore() { - await libcoreReset.send().toPromise() + // we need to stop everything that is happening right now, like syncs await killInternalProcess.send().toPromise() + // we can now ask libcore to reset itself + await libcoreReset.send().toPromise() } function reload() { From 0d5c6cf651d0716dbe489333eb4364bb6ed7aa97 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 19 Feb 2019 13:22:36 +0100 Subject: [PATCH 13/23] LL-635 setup a new Nano X on desktop --- .../Onboarding/steps/SelectDevice.js | 17 +++- .../steps/SelectPIN/SelectPINnanoX.js | 81 +++++++++++++++++++ .../Onboarding/steps/SelectPIN/index.js | 28 +++++-- static/i18n/en/app.json | 14 ++-- ...ger-nano-onb.svg => ledger-nano-s-onb.svg} | 0 static/images/ledger-nano-x-onb.svg | 8 ++ static/images/select-pin-nano-x-onb.svg | 24 ++++++ 7 files changed, 155 insertions(+), 17 deletions(-) create mode 100644 src/components/Onboarding/steps/SelectPIN/SelectPINnanoX.js rename static/images/{ledger-nano-onb.svg => ledger-nano-s-onb.svg} (100%) create mode 100644 static/images/ledger-nano-x-onb.svg create mode 100644 static/images/select-pin-nano-x-onb.svg diff --git a/src/components/Onboarding/steps/SelectDevice.js b/src/components/Onboarding/steps/SelectDevice.js index 9c7bd95e..7d2a5a04 100644 --- a/src/components/Onboarding/steps/SelectDevice.js +++ b/src/components/Onboarding/steps/SelectDevice.js @@ -9,6 +9,7 @@ import { rgba } from 'styles/helpers' import { deviceType } from 'reducers/onboarding' import type { DeviceType } from 'reducers/onboarding' +import { deviceModelName } from 'helpers/devices' import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' @@ -46,15 +47,25 @@ class SelectDevice extends PureComponent { + this.handleDeviceType('nanoX')} + > + {onboarding.deviceType === 'nanoX' && } + + + + {deviceModelName('nanoX')} + this.handleDeviceType('nanoS')} > {onboarding.deviceType === 'nanoS' && } - + - {t('onboarding.selectDevice.ledgerNanoCard.title')} + {deviceModelName('nanoS')} { - {t('onboarding.selectDevice.ledgerBlueCard.title')} + {deviceModelName('blue')} diff --git a/src/components/Onboarding/steps/SelectPIN/SelectPINnanoX.js b/src/components/Onboarding/steps/SelectPIN/SelectPINnanoX.js new file mode 100644 index 00000000..600ef06d --- /dev/null +++ b/src/components/Onboarding/steps/SelectPIN/SelectPINnanoX.js @@ -0,0 +1,81 @@ +// @flow +import React, { PureComponent } from 'react' +import { translate, Trans } from 'react-i18next' +import { colors } from 'styles/theme' +import { i } from 'helpers/staticPath' + +import Box from 'components/base/Box' + +import type { T } from 'types/common' + +import IconChevronRight from 'icons/ChevronRight' + +import { IconOptionRow, DisclaimerBox, OptionRow, Inner } from '../../helperComponents' + +type Props = { + t: T, +} + +class SelectPINnanoX extends PureComponent { + render() { + const { t } = this.props + + const stepsLedgerNano = [ + { + key: 'step1', + icon: {'1.'}, + desc: t('onboarding.selectPIN.initialize.instructions.nanoX.step1'), + }, + { + key: 'step2', + icon: {'2.'}, + desc: ( + + + + ), + }, + { + key: 'step3', + icon: {'3.'}, + desc: t('onboarding.selectPIN.initialize.instructions.nanoX.step3'), + }, + { + key: 'step4', + icon: {'4.'}, + desc: t('onboarding.selectPIN.initialize.instructions.nanoX.step4'), + }, + ] + const disclaimerNotes = [ + { + key: 'note1', + icon: , + desc: t('onboarding.selectPIN.disclaimer.note1'), + }, + { + key: 'note2', + icon: , + desc: t('onboarding.selectPIN.disclaimer.note2'), + }, + { + key: 'note3', + icon: , + desc: t('onboarding.selectPIN.disclaimer.note3'), + }, + ] + + return ( + + + + + {stepsLedgerNano.map(step => )} + + + + + ) + } +} + +export default translate()(SelectPINnanoX) diff --git a/src/components/Onboarding/steps/SelectPIN/index.js b/src/components/Onboarding/steps/SelectPIN/index.js index 40daf187..4fee53d8 100644 --- a/src/components/Onboarding/steps/SelectPIN/index.js +++ b/src/components/Onboarding/steps/SelectPIN/index.js @@ -4,6 +4,7 @@ import React from 'react' import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' +import type { DeviceType } from 'reducers/onboarding' import { cleanDeviceName } from 'helpers/devices' import GrowScroll from 'components/base/GrowScroll' @@ -11,11 +12,28 @@ import { Title, FixedTopContainer } from '../../helperComponents' import OnboardingFooter from '../../OnboardingFooter' import SelectPINnano from './SelectPINnano' import SelectPINblue from './SelectPINblue' +import SelectPINnanoX from './SelectPINnanoX' import SelectPINrestoreNano from './SelectPINrestoreNano' import SelectPINrestoreBlue from './SelectPINrestoreBlue' - import type { StepProps } from '../..' +const SelectPinSwitcher = ({ + deviceType, + restore = false, +}: { + deviceType: DeviceType, + restore?: boolean, +}) => { + switch (deviceType) { + case 'nanoX': + return restore ? : // TODO: Restore NanoX + case 'blue': + return restore ? : + default: + return restore ? : + } +} + export default (props: StepProps) => { const { nextStep, prevStep, t, onboarding } = props @@ -32,18 +50,14 @@ export default (props: StepProps) => { {t('onboarding.selectPIN.restore.title')} - {onboarding.deviceType === 'nanoS' ? ( - - ) : ( - - )} + ) : ( {t('onboarding.selectPIN.initialize.title')} - {onboarding.deviceType === 'nanoS' ? : } + )} diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json index e3dbe1b8..0080018a 100644 --- a/static/i18n/en/app.json +++ b/static/i18n/en/app.json @@ -563,13 +563,7 @@ } }, "selectDevice": { - "title": "Select your device", - "ledgerNanoCard": { - "title": "Ledger Nano S" - }, - "ledgerBlueCard": { - "title": "Ledger Blue" - } + "title": "Select your device" }, "selectPIN": { "disclaimer": { @@ -586,6 +580,12 @@ "step3": "Press the left or right button to select a digit. Press both buttons to validate.", "step4": "Select ✓ to confirm your PIN code. Select ⬅ to erase a digit." }, + "nanoX": { + "step1": "Connect the Ledger Nano X to your computer.", + "step2": "Press both buttons to choose Set up as new device.", + "step3": "Press the left or right button to select a digit.", + "step4": "Select ✓ to confirm your PIN code. Select ⬅ to erase a digit." + }, "blue": { "step1": "Connect the Ledger Blue to your computer.", "step2": "Tap on <1><0>Configure as new device.", diff --git a/static/images/ledger-nano-onb.svg b/static/images/ledger-nano-s-onb.svg similarity index 100% rename from static/images/ledger-nano-onb.svg rename to static/images/ledger-nano-s-onb.svg diff --git a/static/images/ledger-nano-x-onb.svg b/static/images/ledger-nano-x-onb.svg new file mode 100644 index 00000000..1b9d4405 --- /dev/null +++ b/static/images/ledger-nano-x-onb.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/static/images/select-pin-nano-x-onb.svg b/static/images/select-pin-nano-x-onb.svg new file mode 100644 index 00000000..7693c90e --- /dev/null +++ b/static/images/select-pin-nano-x-onb.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + From 1c4b0fc073d6a82c16cf2f074d44700663500d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Tue, 19 Feb 2019 14:36:05 +0100 Subject: [PATCH 14/23] bugfixes killInternalProcess --- src/commands/killInternalProcess.js | 7 ++++--- src/helpers/reset.js | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/commands/killInternalProcess.js b/src/commands/killInternalProcess.js index 428fecd4..33ad0102 100644 --- a/src/commands/killInternalProcess.js +++ b/src/commands/killInternalProcess.js @@ -1,10 +1,10 @@ // @flow import { createCommand, Command } from 'helpers/ipc' -import { of } from 'rxjs' +import { never } from 'rxjs' type Input = void -type Result = boolean +type Result = void const cmd: Command = createCommand('killInternalProcess', () => { setTimeout(() => { @@ -12,7 +12,8 @@ const cmd: Command = createCommand('killInternalProcess', () => { // special exit code for better identification process.exit(42) }) - return of(true) + // The command shouldn't finish now because process.exit will make it end! + return never() }) export default cmd diff --git a/src/helpers/reset.js b/src/helpers/reset.js index d0ead9ca..7a8e51ac 100644 --- a/src/helpers/reset.js +++ b/src/helpers/reset.js @@ -10,7 +10,10 @@ import libcoreReset from 'commands/libcoreReset' async function resetLibcore() { // we need to stop everything that is happening right now, like syncs - await killInternalProcess.send().toPromise() + await killInternalProcess + .send() + .toPromise() + .catch(() => {}) // this is a normal error due to the crash of the process, we ignore it // we can now ask libcore to reset itself await libcoreReset.send().toPromise() } From ad2fe2d403d2b0d070f9160d79f24ca5684a5a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Tue, 19 Feb 2019 14:39:08 +0100 Subject: [PATCH 15/23] fixes flow --- src/components/base/Modal/ConfirmModal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/base/Modal/ConfirmModal.js b/src/components/base/Modal/ConfirmModal.js index 06066bc9..a2ff1e83 100644 --- a/src/components/base/Modal/ConfirmModal.js +++ b/src/components/base/Modal/ConfirmModal.js @@ -29,6 +29,7 @@ type Props = { analyticsName: string, cancellable?: boolean, centered?: boolean, + children?: *, } class ConfirmModal extends PureComponent { From 8c10c73167f28c05fa97c34eb8942c455a8303a8 Mon Sep 17 00:00:00 2001 From: Dimitri Sabadie Date: Tue, 19 Feb 2019 15:35:22 +0100 Subject: [PATCH 16/23] Bump @ledgerhq/ledger-core version up to 2.0.0-rc.21. --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a63150a4..7df684a5 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@ledgerhq/hw-app-xrp": "^4.39.0", "@ledgerhq/hw-transport": "^4.39.0", "@ledgerhq/hw-transport-node-hid": "^4.40.0", - "@ledgerhq/ledger-core": "2.0.0-rc.19", + "@ledgerhq/ledger-core": "2.0.0-rc.21", "@ledgerhq/live-common": "4.16.1", "animated": "^0.2.2", "async": "^2.6.1", diff --git a/yarn.lock b/yarn.lock index 0a8ba716..a09487a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1733,10 +1733,10 @@ "@ledgerhq/errors" "^4.39.0" events "^3.0.0" -"@ledgerhq/ledger-core@2.0.0-rc.19": - version "2.0.0-rc.19" - resolved "https://registry.yarnpkg.com/@ledgerhq/ledger-core/-/ledger-core-2.0.0-rc.19.tgz#f8cd0bdc4e8f067bd95aced895d3e1190bb63f06" - integrity sha512-pkSVOFNGYYiujJFCJ7JkQrwK5YMVx6MoyXBD4jA+SKthlZ8zo3X3jfhRJdZ1rUiI87GP/ncdh0Kc+epuWTqlDQ== +"@ledgerhq/ledger-core@2.0.0-rc.21": + version "2.0.0-rc.21" + resolved "https://registry.yarnpkg.com/@ledgerhq/ledger-core/-/ledger-core-2.0.0-rc.21.tgz#f9e48cf162150ef3d5089ac19e9effcef4626697" + integrity sha512-DqBY1D95wz3a56k8bx7e8YhTsVake/4ZBxH5RgUnXl4OQYRQNKyrtqt94yKvYi+JkRqtU2z60XgB5mo58jaq+w== dependencies: bindings "^1.3.0" nan "^2.6.2" From 4c55166efabc84d9cd719346e574f0bd9993cb70 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 19 Feb 2019 15:57:48 +0100 Subject: [PATCH 17/23] cleaner names and removed useless helper --- src/components/Onboarding/index.js | 6 +-- src/components/Onboarding/steps/Analytics.js | 7 +++- src/components/Onboarding/steps/Finish.js | 8 +++- .../GenuineCheck/GenuineCheckErrorPage.js | 9 +++-- .../GenuineCheck/GenuineCheckUnavailable.js | 9 +++-- .../Onboarding/steps/GenuineCheck/index.js | 9 +++-- .../Onboarding/steps/SelectDevice.js | 39 ++++++++++--------- .../Onboarding/steps/SelectPIN/index.js | 22 +++++------ .../Onboarding/steps/SetPassword.js | 5 ++- .../steps/WriteSeed/WriteSeedRestore.js | 2 +- .../Onboarding/steps/WriteSeed/index.js | 9 +++-- src/helpers/devices.js | 18 --------- src/reducers/onboarding.js | 12 +++--- 13 files changed, 74 insertions(+), 81 deletions(-) delete mode 100644 src/helpers/devices.js diff --git a/src/components/Onboarding/index.js b/src/components/Onboarding/index.js index 8ced1375..e511db45 100644 --- a/src/components/Onboarding/index.js +++ b/src/components/Onboarding/index.js @@ -19,7 +19,7 @@ import { prevStep, jumpStep, updateGenuineCheck, - deviceType, + deviceModelId, flowType, relaunchOnboarding, onboardingRelaunchedSelector, @@ -102,7 +102,7 @@ export type StepProps = { getDeviceInfo: Function, updateGenuineCheck: Function, openModal: Function, - deviceType: Function, + deviceModelId: Function, flowType: Function, } @@ -171,7 +171,7 @@ class Onboarding extends PureComponent { settings, updateGenuineCheck, openModal, - deviceType, + deviceModelId, flowType, prevStep, nextStep, diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 4a3893e8..9bfb7f85 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -3,6 +3,8 @@ import React, { PureComponent } from 'react' import styled from 'styled-components' import { connect } from 'react-redux' +import { getDeviceModel } from '@ledgerhq/devices' + import { saveSettings } from 'actions/settings' import Box from 'components/base/Box' import Switch from 'components/base/Switch' @@ -13,7 +15,6 @@ import Track from 'analytics/Track' import { openModal } from 'reducers/modals' import { MODAL_SHARE_ANALYTICS, MODAL_TECHNICAL_DATA } from 'config/constants' import { openURL } from 'helpers/linking' -import { cleanDeviceName } from 'helpers/devices' import { urls } from 'config/urls' import ShareAnalytics from '../../modals/ShareAnalytics' import TechnicalData from '../../modals/TechnicalData' @@ -68,13 +69,15 @@ class Analytics extends PureComponent { const { nextStep, t, onboarding } = this.props const { analyticsToggle, sentryLogsToggle } = this.state + const model = getDeviceModel(onboarding.deviceModelId) + return ( {t('onboarding.analytics.title')} diff --git a/src/components/Onboarding/steps/Finish.js b/src/components/Onboarding/steps/Finish.js index 7e465151..ed2c926f 100644 --- a/src/components/Onboarding/steps/Finish.js +++ b/src/components/Onboarding/steps/Finish.js @@ -3,6 +3,8 @@ import React, { Component } from 'react' import { openURL } from 'helpers/linking' import styled from 'styled-components' +import { getDeviceModel } from '@ledgerhq/devices' + import { i } from 'helpers/staticPath' import { urls } from 'config/urls' @@ -18,7 +20,6 @@ import IconSocialReddit from 'icons/Reddit' import IconSocialGithub from 'icons/Github' import { lighten } from 'styles/helpers' -import { cleanDeviceName } from 'helpers/devices' import type { StepProps } from '..' import { Title, Description } from '../helperComponents' @@ -67,13 +68,16 @@ export default class Finish extends Component { render() { const { finish, t, onboarding } = this.props const { emit } = this.state + + const model = getDeviceModel(onboarding.deviceModelId) + return ( diff --git a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js index 6fdabca2..614da79d 100644 --- a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js +++ b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js @@ -11,7 +11,7 @@ import Box from 'components/base/Box' import Button from 'components/base/Button' import ExternalLinkButton from 'components/base/ExternalLinkButton' import TrackPage from 'analytics/TrackPage' -import { cleanDeviceName } from 'helpers/devices' +import { getDeviceModel } from '@ledgerhq/devices' import { Title, Description, OnboardingFooterWrapper } from '../../helperComponents' @@ -24,12 +24,15 @@ type Props = { class GenuineCheckErrorPage extends PureComponent { trackErrorPage = (page: string) => { const { onboarding } = this.props + + const model = getDeviceModel(onboarding.deviceModelId) + return ( ) } @@ -60,7 +63,7 @@ class GenuineCheckErrorPage extends PureComponent { )} - {onboarding.deviceType === 'nanoS' ? ( + {onboarding.deviceModelId === 'nanoS' ? ( ) : ( diff --git a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js index 194ce8a3..b22208d2 100644 --- a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js +++ b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js @@ -1,13 +1,12 @@ // @flow import React from 'react' -import { colors } from 'styles/theme' +import { getDeviceModel } from '@ledgerhq/devices' +import { colors } from 'styles/theme' import type { T } from 'types/common' import type { OnboardingState } from 'reducers/onboarding' -import { cleanDeviceName } from 'helpers/devices' - import FakeLink from 'components/base/FakeLink' import IconExclamationCircle from 'icons/ExclamationCircle' import Box from 'components/base/Box' @@ -56,6 +55,8 @@ export function GenuineCheckUnavailableMessage({ t: T, onboarding: OnboardingState, }) { + const model = getDeviceModel(onboarding.deviceModelId) + return ( diff --git a/src/components/Onboarding/steps/GenuineCheck/index.js b/src/components/Onboarding/steps/GenuineCheck/index.js index 3501fa67..6a763b14 100644 --- a/src/components/Onboarding/steps/GenuineCheck/index.js +++ b/src/components/Onboarding/steps/GenuineCheck/index.js @@ -3,12 +3,11 @@ import React, { PureComponent } from 'react' import { connect } from 'react-redux' import styled from 'styled-components' -import { colors } from 'styles/theme' +import { getDeviceModel } from '@ledgerhq/devices' +import { colors } from 'styles/theme' import { updateGenuineCheck } from 'reducers/onboarding' -import { cleanDeviceName } from 'helpers/devices' - import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' import Button from 'components/base/Button' @@ -167,13 +166,15 @@ class GenuineCheck extends PureComponent { return this.renderGenuineFail() } + const model = getDeviceModel(onboarding.deviceModelId) + return ( {t('onboarding.genuineCheck.title')} diff --git a/src/components/Onboarding/steps/SelectDevice.js b/src/components/Onboarding/steps/SelectDevice.js index 7d2a5a04..c34b84ea 100644 --- a/src/components/Onboarding/steps/SelectDevice.js +++ b/src/components/Onboarding/steps/SelectDevice.js @@ -3,13 +3,14 @@ import React, { PureComponent } from 'react' import styled from 'styled-components' import { connect } from 'react-redux' +import { getDeviceModel } from '@ledgerhq/devices' + import { i } from 'helpers/staticPath' import { rgba } from 'styles/helpers' -import { deviceType } from 'reducers/onboarding' -import type { DeviceType } from 'reducers/onboarding' -import { deviceModelName } from 'helpers/devices' +import { deviceModelId } from 'reducers/onboarding' +import type { DeviceModelId } from 'reducers/onboarding' import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' @@ -21,11 +22,11 @@ import OnboardingFooter from '../OnboardingFooter' import type { StepProps } from '..' -const mapDispatchToProps = { deviceType } +const mapDispatchToProps = { deviceModelId } class SelectDevice extends PureComponent { - handleDeviceType = (deviceType: DeviceType) => { - this.props.deviceType(deviceType) + handleDeviceModelId = (deviceModelId: DeviceModelId) => { + this.props.deviceModelId(deviceModelId) } handleContinue = () => { @@ -48,34 +49,34 @@ class SelectDevice extends PureComponent { this.handleDeviceType('nanoX')} + isActive={onboarding.deviceModelId === 'nanoX'} + onClick={() => this.handleDeviceModelId('nanoX')} > - {onboarding.deviceType === 'nanoX' && } + {onboarding.deviceModelId === 'nanoX' && } - {deviceModelName('nanoX')} + {getDeviceModel('nanoX').productName} this.handleDeviceType('nanoS')} + isActive={onboarding.deviceModelId === 'nanoS'} + onClick={() => this.handleDeviceModelId('nanoS')} > - {onboarding.deviceType === 'nanoS' && } + {onboarding.deviceModelId === 'nanoS' && } - {deviceModelName('nanoS')} + {getDeviceModel('nanoS').productName} this.handleDeviceType('blue')} + isActive={onboarding.deviceModelId === 'blue'} + onClick={() => this.handleDeviceModelId('blue')} > - {onboarding.deviceType === 'blue' && } + {onboarding.deviceModelId === 'blue' && } - {deviceModelName('blue')} + {getDeviceModel('blue').productName} @@ -85,7 +86,7 @@ class SelectDevice extends PureComponent { t={t} nextStep={this.handleContinue} prevStep={() => jumpStep('init')} - isContinueDisabled={onboarding.deviceType === ''} + isContinueDisabled={onboarding.deviceModelId === ''} /> ) diff --git a/src/components/Onboarding/steps/SelectPIN/index.js b/src/components/Onboarding/steps/SelectPIN/index.js index 4fee53d8..603d9cb7 100644 --- a/src/components/Onboarding/steps/SelectPIN/index.js +++ b/src/components/Onboarding/steps/SelectPIN/index.js @@ -1,12 +1,12 @@ // @flow import React from 'react' +import { getDeviceModel } from '@ledgerhq/devices' import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' -import type { DeviceType } from 'reducers/onboarding' +import type { DeviceModelId } from 'reducers/onboarding' -import { cleanDeviceName } from 'helpers/devices' import GrowScroll from 'components/base/GrowScroll' import { Title, FixedTopContainer } from '../../helperComponents' import OnboardingFooter from '../../OnboardingFooter' @@ -17,14 +17,8 @@ import SelectPINrestoreNano from './SelectPINrestoreNano' import SelectPINrestoreBlue from './SelectPINrestoreBlue' import type { StepProps } from '../..' -const SelectPinSwitcher = ({ - deviceType, - restore = false, -}: { - deviceType: DeviceType, - restore?: boolean, -}) => { - switch (deviceType) { +const SelectPin = ({ modelId, restore = false }: { modelId: DeviceModelId, restore?: boolean }) => { + switch (modelId) { case 'nanoX': return restore ? : // TODO: Restore NanoX case 'blue': @@ -37,6 +31,8 @@ const SelectPinSwitcher = ({ export default (props: StepProps) => { const { nextStep, prevStep, t, onboarding } = props + const model = getDeviceModel(onboarding.deviceModelId) + return ( @@ -44,20 +40,20 @@ export default (props: StepProps) => { category="Onboarding" name="Choose PIN" flowType={onboarding.flowType} - deviceType={cleanDeviceName(onboarding.deviceType)} + deviceType={model ? model.productName : ''} /> {onboarding.flowType === 'restoreDevice' ? ( {t('onboarding.selectPIN.restore.title')} - + ) : ( {t('onboarding.selectPIN.initialize.title')} - + )} diff --git a/src/components/Onboarding/steps/SetPassword.js b/src/components/Onboarding/steps/SetPassword.js index b3a31abe..c356ad11 100644 --- a/src/components/Onboarding/steps/SetPassword.js +++ b/src/components/Onboarding/steps/SetPassword.js @@ -2,10 +2,11 @@ import React, { PureComponent, Fragment } from 'react' import { connect } from 'react-redux' +import { getDeviceModel } from '@ledgerhq/devices' + import { colors } from 'styles/theme' import db from 'helpers/db' -import { cleanDeviceName } from 'helpers/devices' import { saveSettings } from 'actions/settings' import Box from 'components/base/Box' @@ -106,7 +107,7 @@ class SetPassword extends PureComponent { category="Onboarding" name="Set Password" flowType={onboarding.flowType} - deviceType={cleanDeviceName(onboarding.deviceType)} + deviceType={getDeviceModel(onboarding.deviceModelId).productName} /> diff --git a/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js b/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js index 0e524cbe..bbe8063f 100644 --- a/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js +++ b/src/components/Onboarding/steps/WriteSeed/WriteSeedRestore.js @@ -123,7 +123,7 @@ class WriteSeedRestore extends PureComponent { - {onboarding.deviceType === 'nanoS' ? ( + {onboarding.deviceModelId === 'nanoS' ? ( {stepsNano.map(step => )} diff --git a/src/components/Onboarding/steps/WriteSeed/index.js b/src/components/Onboarding/steps/WriteSeed/index.js index 2fcb49be..afa6d14b 100644 --- a/src/components/Onboarding/steps/WriteSeed/index.js +++ b/src/components/Onboarding/steps/WriteSeed/index.js @@ -1,12 +1,11 @@ // @flow import React from 'react' - +import { getDeviceModel } from '@ledgerhq/devices' import Box from 'components/base/Box' import TrackPage from 'analytics/TrackPage' import GrowScroll from 'components/base/GrowScroll' -import { cleanDeviceName } from 'helpers/devices' import OnboardingFooter from '../../OnboardingFooter' import WriteSeedNano from './WriteSeedNano' @@ -18,6 +17,8 @@ import type { StepProps } from '../..' export default (props: StepProps) => { const { nextStep, prevStep, t, onboarding } = props + const model = getDeviceModel(onboarding.deviceModelId) + return ( @@ -25,12 +26,12 @@ export default (props: StepProps) => { category="Onboarding" name="Recovery Phase" flowType={onboarding.flowType} - deviceType={cleanDeviceName(onboarding.deviceType)} + deviceType={model ? model.productName : ''} /> {onboarding.flowType === 'restoreDevice' ? ( - ) : onboarding.deviceType === 'nanoS' ? ( + ) : onboarding.deviceModelId === 'nanoS' ? ( ) : ( diff --git a/src/helpers/devices.js b/src/helpers/devices.js deleted file mode 100644 index 3ca12baf..00000000 --- a/src/helpers/devices.js +++ /dev/null @@ -1,18 +0,0 @@ -// @flow -import { getDeviceModel } from '@ledgerhq/devices' - -import type { DeviceType } from 'reducers/onboarding' - -export const deviceModelName = (id: DeviceType): string => { - const device = getDeviceModel(id) - if (device) return device.productName - - return '' -} - -export const cleanDeviceName = (id: DeviceType): string => { - const fullName = deviceModelName(id) - if (fullName) return fullName.split('Ledger ')[1] - - return '' -} diff --git a/src/reducers/onboarding.js b/src/reducers/onboarding.js index 59f14c18..3e4cea75 100644 --- a/src/reducers/onboarding.js +++ b/src/reducers/onboarding.js @@ -15,7 +15,7 @@ type Step = { }, } -export type DeviceType = 'nanoX' | 'nanoS' | 'blue' | '' +export type DeviceModelId = 'nanoX' | 'nanoS' | 'blue' | '' export type OnboardingState = { stepIndex: number, @@ -29,7 +29,7 @@ export type OnboardingState = { genuineCheckUnavailable: ?Error, displayErrorScreen: boolean, }, - deviceType: DeviceType, + deviceModelId: DeviceModelId, flowType: string, onboardingRelaunched?: boolean, } @@ -45,7 +45,7 @@ const initialState: OnboardingState = { genuineCheckUnavailable: null, displayErrorScreen: false, }, - deviceType: '', + deviceModelId: '', flowType: '', onboardingRelaunched: false, steps: [ @@ -169,9 +169,9 @@ const handlers = { ...state, flowType, }), - ONBOARDING_SET_DEVICE_TYPE: (state: OnboardingState, { payload: deviceType }) => ({ + ONBOARDING_SET_DEVICE_TYPE: (state: OnboardingState, { payload: deviceModelId }) => ({ ...state, - deviceType, + deviceModelId, }), ONBOARDING_RELAUNCH: (state: OnboardingState, { payload: onboardingRelaunched }) => ({ ...initialState, @@ -189,5 +189,5 @@ export const nextStep = createAction('ONBOARDING_NEXT_STEP') export const prevStep = createAction('ONBOARDING_PREV_STEP') export const jumpStep = createAction('ONBOARDING_JUMP_STEP') export const updateGenuineCheck = createAction('UPDATE_GENUINE_CHECK') -export const deviceType = createAction('ONBOARDING_SET_DEVICE_TYPE') +export const deviceModelId = createAction('ONBOARDING_SET_DEVICE_TYPE') export const flowType = createAction('ONBOARDING_SET_FLOW_TYPE') From 4edbcfbfd46221dc0dd4c3211af148bb83ba8e09 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 19 Feb 2019 16:29:03 +0100 Subject: [PATCH 18/23] LL-636 recover nano x from passphrase in onboarding --- .../steps/SelectPIN/SelectPINRestoreNanoX.js | 82 +++++++++++++++++++ .../Onboarding/steps/SelectPIN/index.js | 3 +- static/i18n/en/app.json | 7 ++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/components/Onboarding/steps/SelectPIN/SelectPINRestoreNanoX.js diff --git a/src/components/Onboarding/steps/SelectPIN/SelectPINRestoreNanoX.js b/src/components/Onboarding/steps/SelectPIN/SelectPINRestoreNanoX.js new file mode 100644 index 00000000..997bb4ae --- /dev/null +++ b/src/components/Onboarding/steps/SelectPIN/SelectPINRestoreNanoX.js @@ -0,0 +1,82 @@ +// @flow +import React, { PureComponent } from 'react' +import { translate } from 'react-i18next' +import { colors } from 'styles/theme' +import { i } from 'helpers/staticPath' + +import Box from 'components/base/Box' + +import type { T } from 'types/common' + +import IconChevronRight from 'icons/ChevronRight' + +import { IconOptionRow, DisclaimerBox, OptionRow, Inner } from '../../helperComponents' + +type Props = { + t: T, +} + +class SelectPINrestoreNanoX extends PureComponent { + render() { + const { t } = this.props + + const stepsLedgerNano = [ + { + key: 'step1', + icon: {'1.'}, + desc: t('onboarding.selectPIN.restore.instructions.nanoX.step1'), + }, + { + key: 'step2', + icon: {'2.'}, + desc: t('onboarding.selectPIN.restore.instructions.nanoX.step2'), + }, + { + key: 'step3', + icon: {'3.'}, + desc: t('onboarding.selectPIN.restore.instructions.nanoX.step3'), + }, + { + key: 'step4', + icon: {'4.'}, + desc: t('onboarding.selectPIN.restore.instructions.nanoX.step4'), + }, + { + key: 'step5', + icon: {'5.'}, + desc: t('onboarding.selectPIN.restore.instructions.nanoX.step5'), + }, + ] + const disclaimerNotes = [ + { + key: 'note1', + icon: , + desc: t('onboarding.selectPIN.disclaimer.note1'), + }, + { + key: 'note2', + icon: , + desc: t('onboarding.selectPIN.disclaimer.note2'), + }, + { + key: 'note3', + icon: , + desc: t('onboarding.selectPIN.disclaimer.note3'), + }, + ] + + return ( + + + + + {stepsLedgerNano.map(step => )} + + + + + ) + } +} + +export default translate()(SelectPINrestoreNanoX) diff --git a/src/components/Onboarding/steps/SelectPIN/index.js b/src/components/Onboarding/steps/SelectPIN/index.js index 603d9cb7..bef8b153 100644 --- a/src/components/Onboarding/steps/SelectPIN/index.js +++ b/src/components/Onboarding/steps/SelectPIN/index.js @@ -14,13 +14,14 @@ import SelectPINnano from './SelectPINnano' import SelectPINblue from './SelectPINblue' import SelectPINnanoX from './SelectPINnanoX' import SelectPINrestoreNano from './SelectPINrestoreNano' +import SelectPINRestoreNanoX from './SelectPINRestoreNanoX' import SelectPINrestoreBlue from './SelectPINrestoreBlue' import type { StepProps } from '../..' const SelectPin = ({ modelId, restore = false }: { modelId: DeviceModelId, restore?: boolean }) => { switch (modelId) { case 'nanoX': - return restore ? : // TODO: Restore NanoX + return restore ? : case 'blue': return restore ? : default: diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json index 0080018a..d4c82529 100644 --- a/static/i18n/en/app.json +++ b/static/i18n/en/app.json @@ -602,6 +602,13 @@ "step3": "Press the left or right button to select a digit. Press both buttons to validate.", "step4": "Select ✓ to confirm your PIN code. Select ⬅ to erase a digit." }, + "nanoX": { + "step1": "Connect your Ledger Nano X to your computer.", + "step2": "Press both buttons as instructed on your Ledger Nano X screen.", + "step3": "Press the left button to cancel Configure as new device.", + "step4": "Press the right button to select Restore configuration.", + "step5": "Choose a PIN code between 4 and 8 digits long." + }, "blue": { "step1": "Connect the Ledger Blue to your computer.", "step2": "Tap on <1><0>Restore configuration.", From cec11abf63a9cdca64318f3b04a017352d2ae8dc Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 19 Feb 2019 18:13:12 +0100 Subject: [PATCH 19/23] fix error screen with nano x --- .../GenuineCheck/GenuineCheckErrorPage.js | 17 +++++++--- static/images/nano-x-error-onb.svg | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 static/images/nano-x-error-onb.svg diff --git a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js index 614da79d..ef142f1b 100644 --- a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js +++ b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js @@ -15,6 +15,17 @@ import { getDeviceModel } from '@ledgerhq/devices' import { Title, Description, OnboardingFooterWrapper } from '../../helperComponents' +const Img = ({ type }: { type: string }) => { + switch (type) { + case 'blue': + return + case 'nanoX': + return + default: + return + } +} + type Props = { t: T, redoGenuineCheck: () => void, @@ -63,11 +74,7 @@ class GenuineCheckErrorPage extends PureComponent { )} - {onboarding.deviceModelId === 'nanoS' ? ( - - ) : ( - - )} + ) diff --git a/static/images/nano-x-error-onb.svg b/static/images/nano-x-error-onb.svg new file mode 100644 index 00000000..341a227b --- /dev/null +++ b/static/images/nano-x-error-onb.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4525c6b9f355e74e31e41666dd0441aef37e65cc Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 19 Feb 2019 18:42:45 +0100 Subject: [PATCH 20/23] removed unused checks --- src/components/Onboarding/steps/Analytics.js | 2 +- src/components/Onboarding/steps/Finish.js | 2 +- .../Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js | 2 +- .../Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js | 2 +- src/components/Onboarding/steps/GenuineCheck/index.js | 2 +- src/components/Onboarding/steps/SelectPIN/index.js | 2 +- src/components/Onboarding/steps/WriteSeed/index.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 9bfb7f85..ca032261 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -77,7 +77,7 @@ class Analytics extends PureComponent { category="Onboarding" name="Analytics" flowType={onboarding.flowType} - deviceType={model ? model.productName : ''} + deviceType={model.productName} /> {t('onboarding.analytics.title')} diff --git a/src/components/Onboarding/steps/Finish.js b/src/components/Onboarding/steps/Finish.js index ed2c926f..925317cf 100644 --- a/src/components/Onboarding/steps/Finish.js +++ b/src/components/Onboarding/steps/Finish.js @@ -77,7 +77,7 @@ export default class Finish extends Component { category="Onboarding" name="Finish" flowType={onboarding.flowType} - deviceType={model ? model.productName : ''} + deviceType={model.productName} /> diff --git a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js index ef142f1b..9afa0f64 100644 --- a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js +++ b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckErrorPage.js @@ -43,7 +43,7 @@ class GenuineCheckErrorPage extends PureComponent { category="Onboarding" name={`Genuine Check Error Page - ${page}`} flowType={onboarding.flowType} - deviceType={model ? model.productName : ''} + deviceType={model.productName} /> ) } diff --git a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js index b22208d2..0af9fe65 100644 --- a/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js +++ b/src/components/Onboarding/steps/GenuineCheck/GenuineCheckUnavailable.js @@ -79,7 +79,7 @@ export function GenuineCheckUnavailableMessage({ handleOpenGenuineCheckModal() track('Genuine Check Retry', { flowType: onboarding.flowType, - deviceType: model ? model.productName : '', + deviceType: model.productName, }) }} > diff --git a/src/components/Onboarding/steps/GenuineCheck/index.js b/src/components/Onboarding/steps/GenuineCheck/index.js index 6a763b14..c1754965 100644 --- a/src/components/Onboarding/steps/GenuineCheck/index.js +++ b/src/components/Onboarding/steps/GenuineCheck/index.js @@ -174,7 +174,7 @@ class GenuineCheck extends PureComponent { category="Onboarding" name="Genuine Check" flowType={onboarding.flowType} - deviceType={model ? model.productName : ''} + deviceType={model.productName} /> {t('onboarding.genuineCheck.title')} diff --git a/src/components/Onboarding/steps/SelectPIN/index.js b/src/components/Onboarding/steps/SelectPIN/index.js index bef8b153..1ad65fad 100644 --- a/src/components/Onboarding/steps/SelectPIN/index.js +++ b/src/components/Onboarding/steps/SelectPIN/index.js @@ -41,7 +41,7 @@ export default (props: StepProps) => { category="Onboarding" name="Choose PIN" flowType={onboarding.flowType} - deviceType={model ? model.productName : ''} + deviceType={model.productName} /> {onboarding.flowType === 'restoreDevice' ? ( diff --git a/src/components/Onboarding/steps/WriteSeed/index.js b/src/components/Onboarding/steps/WriteSeed/index.js index afa6d14b..24bb5c7a 100644 --- a/src/components/Onboarding/steps/WriteSeed/index.js +++ b/src/components/Onboarding/steps/WriteSeed/index.js @@ -26,7 +26,7 @@ export default (props: StepProps) => { category="Onboarding" name="Recovery Phase" flowType={onboarding.flowType} - deviceType={model ? model.productName : ''} + deviceType={model.productName} /> {onboarding.flowType === 'restoreDevice' ? ( From 0ed37db197e58293502932091e35fbdda7c67bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Wed, 20 Feb 2019 08:08:17 +0100 Subject: [PATCH 21/23] Update twitter link --- src/config/urls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/urls.js b/src/config/urls.js index 4802926b..0094262d 100644 --- a/src/config/urls.js +++ b/src/config/urls.js @@ -4,7 +4,7 @@ export const urls = { liveHome: 'https://www.ledger.com/pages/ledger-live', // Social - twitter: 'https://twitter.com/LedgerHQ', + twitter: 'https://twitter.com/Ledger', github: 'https://github.com/LedgerHQ/ledger-live-desktop', reddit: 'https://www.reddit.com/r/ledgerwallet/', From b3fd9709291f1977248ddf4b60407eacd441e315 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Tue, 19 Feb 2019 17:54:22 +0100 Subject: [PATCH 22/23] LL-1017 nano X on manager --- src/components/DashboardPage/index.js | 2 +- src/components/EnsureDeviceApp.js | 5 ++- src/components/GenuineCheck.js | 17 +++++---- src/components/ManagerPage/FirmwareUpdate.js | 14 +++++++- .../ManagerPage/ManagerGenuineCheck.js | 2 +- src/icons/device/NanoX.js | 34 ++++++------------ src/icons/device/NanoXBanner.js | 30 ++++++++++++++++ src/icons/device/index.js | 1 + static/i18n/en/app.json | 8 ++--- static/images/logos/connectDevice.png | Bin 9024 -> 5932 bytes 10 files changed, 74 insertions(+), 39 deletions(-) create mode 100644 src/icons/device/NanoXBanner.js diff --git a/src/components/DashboardPage/index.js b/src/components/DashboardPage/index.js index f3317bb5..02ee3ea3 100644 --- a/src/components/DashboardPage/index.js +++ b/src/components/DashboardPage/index.js @@ -3,7 +3,7 @@ import React, { PureComponent, Fragment } from 'react' import uniq from 'lodash/uniq' import { compose } from 'redux' -import IconNanoX from 'icons/device/NanoX' +import IconNanoX from 'icons/device/NanoXBanner' import { translate } from 'react-i18next' import { connect } from 'react-redux' import { push } from 'react-router-redux' diff --git a/src/components/EnsureDeviceApp.js b/src/components/EnsureDeviceApp.js index 623166a9..abe7c37c 100644 --- a/src/components/EnsureDeviceApp.js +++ b/src/components/EnsureDeviceApp.js @@ -98,8 +98,11 @@ class EnsureDeviceApp extends Component<{ id: 'device', title: ( - {'Connect and unlock your '} + {'Connect your'} {'Ledger device'} + {'to your computer and enter your'} + {'PIN code'} + {' on your device'} ), icon: usbIcon, diff --git a/src/components/GenuineCheck.js b/src/components/GenuineCheck.js index d3487591..00046d99 100644 --- a/src/components/GenuineCheck.js +++ b/src/components/GenuineCheck.js @@ -146,8 +146,11 @@ class GenuineCheck extends PureComponent { id: 'device', title: ( - {'Connect and unlock your '} + {'Connect your'} {'Ledger device'} + {'to your computer and enter your'} + {'PIN code'} + {'on your device'} ), icon: usbIcon, @@ -157,9 +160,9 @@ class GenuineCheck extends PureComponent { id: 'deviceInfo', title: ( - {'Navigate to the '} - {'dashboard'} - {' on your device'} + {'Go to'} + {'Home screen'} + {'on your device'} ), icon: homeIcon, @@ -169,9 +172,9 @@ class GenuineCheck extends PureComponent { id: 'isGenuine', title: ( - {'Allow '} - {'Ledger Manager'} - {' on your device'} + {'Confirm'} + {'Authentication'} + {'on your device'} ), icon: genuineCheckIcon, diff --git a/src/components/ManagerPage/FirmwareUpdate.js b/src/components/ManagerPage/FirmwareUpdate.js index 85af33fa..f9f9d4ee 100644 --- a/src/components/ManagerPage/FirmwareUpdate.js +++ b/src/components/ManagerPage/FirmwareUpdate.js @@ -18,6 +18,7 @@ import Box, { Card } from 'components/base/Box' import Text from 'components/base/Text' import NanoS from 'icons/device/NanoS' +import NanoX from 'icons/device/NanoX' import Blue from 'icons/device/Blue' import CheckFull from 'icons/CheckFull' @@ -26,6 +27,17 @@ import UpdateFirmwareButton from './UpdateFirmwareButton' export const getCleanVersion = (input: string): string => input.endsWith('-osu') ? input.replace('-osu', '') : input +const Icon = ({ type }: { type: string }) => { + switch (type) { + case 'blue': + return + case 'nanoX': + return + default: + return + } +} + export type ModalStatus = 'closed' | 'disclaimer' | 'install' | 'error' | 'success' type Props = { @@ -88,7 +100,7 @@ class FirmwareUpdate extends PureComponent { - {deviceSpecs.id === 'blue' ? : } + diff --git a/src/components/ManagerPage/ManagerGenuineCheck.js b/src/components/ManagerPage/ManagerGenuineCheck.js index fed46656..b8782b4c 100644 --- a/src/components/ManagerPage/ManagerGenuineCheck.js +++ b/src/components/ManagerPage/ManagerGenuineCheck.js @@ -28,7 +28,7 @@ class ManagerGenuineCheck extends PureComponent { connect your device {t('manager.device.title')} diff --git a/src/icons/device/NanoX.js b/src/icons/device/NanoX.js index f72d05a4..e40572f2 100644 --- a/src/icons/device/NanoX.js +++ b/src/icons/device/NanoX.js @@ -2,29 +2,15 @@ import React from 'react' -export default ({ size = 30, ...p }: { size: number }) => ( - - - - - - - - - - - - - - - - +const path = ( + +) + +export default ({ size, ...p }: { size: number }) => ( + + {path} ) diff --git a/src/icons/device/NanoXBanner.js b/src/icons/device/NanoXBanner.js new file mode 100644 index 00000000..f72d05a4 --- /dev/null +++ b/src/icons/device/NanoXBanner.js @@ -0,0 +1,30 @@ +// @flow + +import React from 'react' + +export default ({ size = 30, ...p }: { size: number }) => ( + + + + + + + + + + + + + + + + + +) diff --git a/src/icons/device/index.js b/src/icons/device/index.js index f5282739..acfd1b3d 100644 --- a/src/icons/device/index.js +++ b/src/icons/device/index.js @@ -1,3 +1,4 @@ export Blue from './Blue' export NanoS from './NanoS' export NanoX from './NanoX' +export NanoXBanner from './NanoXBanner' diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json index d4c82529..3c23830e 100644 --- a/static/i18n/en/app.json +++ b/static/i18n/en/app.json @@ -145,10 +145,10 @@ "messageIfSkipped": "Your {{currencyName}} address has not been confirmed on your Ledger device. Please verify it for optimal security." }, "deviceConnect": { - "dashboard": "Navigate to the <1><0>{{managerAppName}} on your device", - "step1": "Connect and unlock your <1>Ledger device", + "dashboard": "Go to <1>Home screen on your device", + "step1": "Connect your <1>Ledger device to your computer and enter your <3>PIN code on your device", "step2": "Navigate to the <1><0>{{managerAppName}} app on your device", - "step3": "Allow <1><0>Ledger Manager on your device" + "step3": "Confirm <1>Authentication on your device" }, "emptyState": { "sidebar": { @@ -283,7 +283,7 @@ "subtitle": "Install or uninstall apps on your device", "device": { "title": "Connect your device", - "desc": "Follow the steps below to open the Manager", + "desc": "Please connect your Ledger device and follow the steps below to access to the manager", "cta": "Connect my device" } }, diff --git a/static/images/logos/connectDevice.png b/static/images/logos/connectDevice.png index 2ef15562ba6a5e1d034258b72eb2eec6c67f4daa..5a5121e3437f9309af2c0abece2da3f65013435d 100755 GIT binary patch literal 5932 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 skCe+a*r%~$X}5#Lx`R~)>L Date: Wed, 20 Feb 2019 15:03:56 +0100 Subject: [PATCH 23/23] fix wording --- src/components/GenuineCheck.js | 13 +++++-------- static/i18n/en/app.json | 8 ++++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/GenuineCheck.js b/src/components/GenuineCheck.js index 00046d99..8f25ec41 100644 --- a/src/components/GenuineCheck.js +++ b/src/components/GenuineCheck.js @@ -146,11 +146,8 @@ class GenuineCheck extends PureComponent { id: 'device', title: ( - {'Connect your'} + {'Connect and unlock your'} {'Ledger device'} - {'to your computer and enter your'} - {'PIN code'} - {'on your device'} ), icon: usbIcon, @@ -160,8 +157,8 @@ class GenuineCheck extends PureComponent { id: 'deviceInfo', title: ( - {'Go to'} - {'Home screen'} + {'Navigate to the'} + {'Dashboard'} {'on your device'} ), @@ -172,8 +169,8 @@ class GenuineCheck extends PureComponent { id: 'isGenuine', title: ( - {'Confirm'} - {'Authentication'} + {'Allow'} + {'Ledger Manager'} {'on your device'} ), diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json index 3c23830e..94e7b5ab 100644 --- a/static/i18n/en/app.json +++ b/static/i18n/en/app.json @@ -145,10 +145,10 @@ "messageIfSkipped": "Your {{currencyName}} address has not been confirmed on your Ledger device. Please verify it for optimal security." }, "deviceConnect": { - "dashboard": "Go to <1>Home screen on your device", - "step1": "Connect your <1>Ledger device to your computer and enter your <3>PIN code on your device", + "dashboard": "Navigate to the <1>Dashboard on your device", + "step1": "Connect and unlock your <1>Ledger device", "step2": "Navigate to the <1><0>{{managerAppName}} app on your device", - "step3": "Confirm <1>Authentication on your device" + "step3": "Allow <1>Ledger Manager on your device" }, "emptyState": { "sidebar": { @@ -283,7 +283,7 @@ "subtitle": "Install or uninstall apps on your device", "device": { "title": "Connect your device", - "desc": "Please connect your Ledger device and follow the steps below to access to the manager", + "desc": "Follow the steps below to open the Manager", "cta": "Connect my device" } },