Browse Source

Merge pull request #1475 from LedgerHQ/develop

Prepare for patch release 1.1.8
master
Gaëtan Renaudeau 6 years ago
committed by GitHub
parent
commit
9e536b644e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .circleci/config.yml
  2. 1
      .eslintrc
  3. 8
      .gitignore
  4. 12
      README.md
  5. 4
      build/linux/arch/PKGBUILD
  6. 13
      package.json
  7. 85
      scripts/create-draft-release.js
  8. 8
      scripts/helpers/display-env.sh
  9. 14
      scripts/release.sh
  10. 4
      src/api/Ethereum.js
  11. 4
      src/api/Fees.js
  12. 6
      src/api/network.js
  13. 5
      src/bridge/EthereumJSBridge.js
  14. 3
      src/bridge/LibcoreBridge.js
  15. 4
      src/bridge/RippleJSBridge.js
  16. 1
      src/bridge/index.js
  17. 3
      src/commands/getCurrentFirmware.js
  18. 6
      src/commands/getDeviceInfo.js
  19. 2
      src/commands/getIsGenuine.js
  20. 4
      src/commands/getLatestFirmwareForDevice.js
  21. 2
      src/commands/index.js
  22. 6
      src/commands/installApp.js
  23. 2
      src/commands/installMcu.js
  24. 2
      src/commands/installOsuFirmware.js
  25. 4
      src/commands/libcoreGetFees.js
  26. 21
      src/commands/libcoreHardReset.js
  27. 4
      src/commands/listAppVersions.js
  28. 5
      src/commands/listApps.js
  29. 5
      src/commands/listCategories.js
  30. 3
      src/commands/shouldFlashMcu.js
  31. 10
      src/commands/uninstallApp.js
  32. 16
      src/components/DashboardPage/EmptyState.js
  33. 3
      src/components/EnsureDeviceApp.js
  34. 2
      src/components/GenuineCheck.js
  35. 6
      src/components/IsUnlocked.js
  36. 6
      src/components/ManagerPage/AppSearchBar.js
  37. 22
      src/components/ManagerPage/AppsList.js
  38. 2
      src/components/ManagerPage/Dashboard.js
  39. 5
      src/components/ManagerPage/FirmwareUpdate.js
  40. 2
      src/components/ManagerPage/index.js
  41. 8
      src/components/Onboarding/OnboardingFooter.js
  42. 2
      src/components/Onboarding/steps/Analytics.js
  43. 4
      src/components/Onboarding/steps/Finish.js
  44. 34
      src/components/QRCodeExporter.js
  45. 3
      src/components/RecipientAddress/index.js
  46. 2
      src/components/RenderError.js
  47. 20
      src/components/SettingsPage/CleanButton.js
  48. 2
      src/components/SettingsPage/DevModeButton.js
  49. 4
      src/components/SettingsPage/DisablePasswordModal.js
  50. 4
      src/components/SettingsPage/PasswordForm.js
  51. 4
      src/components/SettingsPage/PasswordModal.js
  52. 2
      src/components/SettingsPage/ResetButton.js
  53. 2
      src/components/SettingsPage/index.js
  54. 2
      src/components/TopBar/index.js
  55. 5
      src/components/base/InputCurrency/index.js
  56. 1
      src/components/base/QRCode/index.js
  57. 6
      src/components/base/Select/createStyles.js
  58. 6
      src/components/base/Select/index.js
  59. 5
      src/components/modals/AccountSettingRenderBody.js
  60. 4
      src/components/modals/Disclaimer.js
  61. 4
      src/components/modals/UpdateFirmware/index.js
  62. 36
      src/config/errors.js
  63. 26
      src/helpers/apps/installApp.js
  64. 15
      src/helpers/apps/listAppVersions.js
  65. 3
      src/helpers/apps/listApps.js
  66. 5
      src/helpers/apps/listCategories.js
  67. 18
      src/helpers/apps/uninstallApp.js
  68. 3
      src/helpers/debugAppInfosForCurrency/btc.js
  69. 5
      src/helpers/devices/getCurrentFirmware.js
  70. 12
      src/helpers/devices/getDeviceInfo.js
  71. 6
      src/helpers/devices/getDeviceVersion.js
  72. 12
      src/helpers/devices/getIsGenuine.js
  73. 36
      src/helpers/devices/getLatestFirmwareForDevice.js
  74. 2
      src/helpers/devices/shouldFlashMcu.js
  75. 3
      src/helpers/firmware/getFirmwareInfo.js
  76. 7
      src/helpers/firmware/getNextMCU.js
  77. 15
      src/helpers/firmware/installFinalFirmware.js
  78. 11
      src/helpers/firmware/installMcu.js
  79. 12
      src/helpers/firmware/installOsuFirmware.js
  80. 4
      src/helpers/getAddressForCurrency/btc.js
  81. 13
      src/helpers/hardReset.js
  82. 9
      src/helpers/libcore.js
  83. 35
      src/helpers/reset.js
  84. 14
      src/helpers/socket.js
  85. 132
      src/helpers/types.js
  86. 4
      static/i18n/en/errors.json
  87. 64
      test-e2e/nav_to_settings.spec.js
  88. 306
      yarn.lock

4
.circleci/config.yml

@ -13,10 +13,10 @@ jobs:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- v7-yarn-packages-{{ checksum "yarn.lock" }} - v8-yarn-packages-{{ checksum "yarn.lock" }}
- run: yarn install - run: yarn install
- save_cache: - save_cache:
key: v7-yarn-packages-{{ checksum "yarn.lock" }} key: v8-yarn-packages-{{ checksum "yarn.lock" }}
paths: paths:
- node_modules - node_modules
- run: yarn lint - run: yarn lint

1
.eslintrc

@ -21,6 +21,7 @@
"jest": false, "jest": false,
"describe": false, "describe": false,
"beforeEach": false, "beforeEach": false,
"afterEach": false,
"test": false, "test": false,
"it": false, "it": false,
"expect": false, "expect": false,

8
.gitignore

@ -10,11 +10,3 @@
/build/linux/arch/src /build/linux/arch/src
/build/linux/arch/*.tar.gz /build/linux/arch/*.tar.gz
/build/linux/arch/*.tar.xz /build/linux/arch/*.tar.xz
# TODO this should be in devs global gitignore
# it makes no sense to have it here
*.log
.DS_Store
.vscode
thumbs.db
jsconfig.json

12
README.md

@ -159,3 +159,15 @@ yarn reset-files
├── webpack : build configuration ├── webpack : build configuration
└── yarn.lock └── yarn.lock
``` ```
## Troubleshooting
#### The 'gyp==0.1' distribution was not found and is required by the application
You will need to install the python gyp module
```
pip install git+https://chromium.googlesource.com/external/gyp
```
see [stackoverflow/40025591](https://stackoverflow.com/questions/40025591/the-gyp-0-1-distribution-was-not-found)

4
build/linux/arch/PKGBUILD

@ -2,7 +2,7 @@
# shellcheck disable=SC2154,SC2034,SC2164 # shellcheck disable=SC2154,SC2034,SC2164
pkgname=ledger-live pkgname=ledger-live
pkgver=1.0.7 pkgver=1.1.0
pkgrel=1 pkgrel=1
pkgdesc="Open source companion app for your Ledger devices" pkgdesc="Open source companion app for your Ledger devices"
arch=('x86_64') arch=('x86_64')
@ -15,7 +15,7 @@ changelog=
source=("https://github.com/LedgerHQ/ledger-live-desktop/archive/v${pkgver}.tar.gz" source=("https://github.com/LedgerHQ/ledger-live-desktop/archive/v${pkgver}.tar.gz"
"ledger-live.desktop") "ledger-live.desktop")
md5sums=('d60d772a03c0a1c59df07f93b0268a4c' md5sums=('5dc6bd1e8d6dedcfe760d1c75565aad8'
'52705147909a0a988907a23a71199092') '52705147909a0a988907a23a71199092')
# TODO sign with ledger pgp # TODO sign with ledger pgp
validpgpkeys=() validpgpkeys=()

13
package.json

@ -13,10 +13,11 @@
"dist": "bash ./scripts/dist.sh", "dist": "bash ./scripts/dist.sh",
"dist:dir": "bash ./scripts/dist-dir.sh", "dist:dir": "bash ./scripts/dist-dir.sh",
"compile": "bash ./scripts/compile.sh", "compile": "bash ./scripts/compile.sh",
"lint": "eslint src webpack .storybook", "lint": "eslint src webpack .storybook test-e2e",
"flow": "flow", "flow": "flow",
"test": "jest", "test": "jest src",
"prettier": "prettier --write \"{src,webpack,.storybook}/**/*.{js,json}\"", "test-e2e": "jest test-e2e",
"prettier": "prettier --write \"{src,webpack,.storybook,test-e2e}/**/*.{js,json}\"",
"ci": "yarn lint && yarn flow && yarn prettier && yarn test", "ci": "yarn lint && yarn flow && yarn prettier && yarn test",
"storybook": "NODE_ENV=development STORYBOOK_ENV=1 start-storybook -s ./static -p 4444", "storybook": "NODE_ENV=development STORYBOOK_ENV=1 start-storybook -s ./static -p 4444",
"publish-storybook": "bash ./scripts/legacy/publish-storybook.sh", "publish-storybook": "bash ./scripts/legacy/publish-storybook.sh",
@ -38,7 +39,7 @@
"@ledgerhq/hw-transport": "^4.13.0", "@ledgerhq/hw-transport": "^4.13.0",
"@ledgerhq/hw-transport-node-hid": "4.22.0", "@ledgerhq/hw-transport-node-hid": "4.22.0",
"@ledgerhq/ledger-core": "2.0.0-rc.6", "@ledgerhq/ledger-core": "2.0.0-rc.6",
"@ledgerhq/live-common": "3.0.2", "@ledgerhq/live-common": "^3.3.0",
"animated": "^0.2.2", "animated": "^0.2.2",
"async": "^2.6.1", "async": "^2.6.1",
"axios": "^0.18.0", "axios": "^0.18.0",
@ -118,6 +119,7 @@
"@babel/preset-flow": "7.0.0-beta.42", "@babel/preset-flow": "7.0.0-beta.42",
"@babel/preset-react": "7.0.0-beta.42", "@babel/preset-react": "7.0.0-beta.42",
"@babel/preset-stage-0": "7.0.0-beta.42", "@babel/preset-stage-0": "7.0.0-beta.42",
"@octokit/rest": "^15.10.0",
"@storybook/addon-actions": "^3.4.7", "@storybook/addon-actions": "^3.4.7",
"@storybook/addon-knobs": "^3.4.7", "@storybook/addon-knobs": "^3.4.7",
"@storybook/addon-links": "^3.4.7", "@storybook/addon-links": "^3.4.7",
@ -134,7 +136,7 @@
"chance": "^1.0.13", "chance": "^1.0.13",
"concurrently": "3.5.1", "concurrently": "3.5.1",
"dotenv": "^5.0.1", "dotenv": "^5.0.1",
"electron": "1.8.7", "electron": "1.8.8",
"electron-builder": "20.14.7", "electron-builder": "20.14.7",
"electron-devtools-installer": "^2.2.3", "electron-devtools-installer": "^2.2.3",
"electron-rebuild": "^1.7.3", "electron-rebuild": "^1.7.3",
@ -158,6 +160,7 @@
"prettier": "^1.13.5", "prettier": "^1.13.5",
"react-hot-loader": "^4.3.2", "react-hot-loader": "^4.3.2",
"react-test-renderer": "^16.4.1", "react-test-renderer": "^16.4.1",
"spectron": "^3.8.0",
"webpack": "^4.6.0", "webpack": "^4.6.0",
"webpack-bundle-analyzer": "^2.11.1", "webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.0.14", "webpack-cli": "^2.0.14",

85
scripts/create-draft-release.js

@ -0,0 +1,85 @@
#!/usr/bin/env node
/* eslint-disable no-console */
const util = require('util')
const exec = util.promisify(require('child_process').exec)
const octokit = require('@octokit/rest')()
const repo = {
owner: 'LedgerHQ',
repo: 'ledger-live-desktop',
}
async function getTag() {
const { stdout } = await exec('git tag --points-at HEAD')
const tag = stdout.replace('\n', '')
if (!tag) {
throw new Error(`Unable to get current tag. Is your HEAD on a tagged commit?`)
}
return tag
}
async function checkDraft(tag) {
const { status, data } = await octokit.repos.getReleases(repo)
if (status !== 200) {
throw new Error(`Got HTTP status ${status} when trying to fetch releases list.`)
}
for (const release of data) {
if (release.tag_name === tag) {
if (release.draft) {
return true
}
throw new Error(`A release tagged ${tag} exists but is not a draft.`)
}
}
return false
}
async function createDraft(tag) {
const params = {
...repo,
tag_name: tag,
name: tag,
draft: true,
prerelease: true,
}
const { status } = await octokit.repos.createRelease(params)
if (status !== 201) {
throw new Error(`Got HTTP status ${status} when trying to create the release draft.`)
}
}
async function main() {
try {
const token = process.env.GH_TOKEN
const tag = await getTag()
octokit.authenticate({
type: 'token',
token,
})
const existingDraft = await checkDraft(tag)
if (!existingDraft) {
console.log(`No draft exists for ${tag}, creating...`)
createDraft(tag)
} else {
console.log(`A draft already exists for ${tag}, nothing to do.`)
}
} catch (e) {
console.error(e)
process.exit(1)
}
}
main()

8
scripts/helpers/display-env.sh

@ -7,9 +7,15 @@ if [ "$GIT_REVISION" == "" ]; then
GIT_REVISION=$(git rev-parse HEAD) GIT_REVISION=$(git rev-parse HEAD)
fi fi
if [[ $(uname) == 'Darwin' ]]; then
osVersion="$(sw_vers -productName) $(sw_vers -productVersion)"
else
osVersion="$(uname -srmo)"
fi
echo echo
printf " │ \\e[4;1m%s\\e[0;0m\\n" "Ledger Live Desktop - ${GIT_REVISION}" printf " │ \\e[4;1m%s\\e[0;0m\\n" "Ledger Live Desktop - ${GIT_REVISION}"
printf " │ \\e[1;30m%s\\e[1;0m\\n" "$(uname -srmo)" printf " │ \\e[1;30m%s\\e[1;0m\\n" "${osVersion}"
printf " │ \\e[2;1mcommit \\e[0;33m%s\\e[0;0m\\n" "$(git rev-parse HEAD)" printf " │ \\e[2;1mcommit \\e[0;33m%s\\e[0;0m\\n" "$(git rev-parse HEAD)"
echo echo

14
scripts/release.sh

@ -25,6 +25,11 @@ fi
if [ ! -d "static/fonts/museosans" ]; then if [ ! -d "static/fonts/museosans" ]; then
if ! command -v aws ; then if ! command -v aws ; then
if ! command -v apt ; then
echo "Museo Sans is missing, and I can't fetch it (no aws, no apt)" >&2
exit 1
fi
runJob "sudo apt install awscli" "installing aws cli..." "installed aws cli" "failed to install aws cli" runJob "sudo apt install awscli" "installing aws cli..." "installed aws cli" "failed to install aws cli"
fi fi
@ -52,6 +57,15 @@ fi
# exit 1 # exit 1
# fi # fi
if [[ $(uname) == 'Linux' ]]; then # only run it on one target, to prevent race conditions
runJob \
"node scripts/create-draft-release.js" \
"creating a draft release on GitHub (if needed)..." \
"draft release ready" \
"failed to create a draft release"
fi
runJob "yarn compile" "compiling..." "compiled" "failed to compile" "verbose" runJob "yarn compile" "compiling..." "compiled" "failed to compile" "verbose"
runJob \ runJob \

4
src/api/Ethereum.js

@ -1,12 +1,10 @@
// @flow // @flow
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import { BigNumber } from 'bignumber.js' import { BigNumber } from 'bignumber.js'
import { createCustomErrorClass } from 'helpers/errors' import { LedgerAPINotAvailable } from 'config/errors'
import network from './network' import network from './network'
import { blockchainBaseURL } from './Ledger' import { blockchainBaseURL } from './Ledger'
export const LedgerAPINotAvailable = createCustomErrorClass('LedgerAPINotAvailable')
export type Block = { height: number } // TODO more fields actually export type Block = { height: number } // TODO more fields actually
export type Tx = { export type Tx = {
hash: string, hash: string,

4
src/api/Fees.js

@ -2,12 +2,10 @@
import invariant from 'invariant' import invariant from 'invariant'
import LRU from 'lru-cache' import LRU from 'lru-cache'
import type { Currency } from '@ledgerhq/live-common/lib/types' import type { Currency } from '@ledgerhq/live-common/lib/types'
import { createCustomErrorClass } from 'helpers/errors' import { FeeEstimationFailed } from 'config/errors'
import { blockchainBaseURL } from './Ledger' import { blockchainBaseURL } from './Ledger'
import network from './network' import network from './network'
const FeeEstimationFailed = createCustomErrorClass('FeeEstimationFailed')
export type Fees = { export type Fees = {
[_: string]: number, [_: string]: number,
} }

6
src/api/network.js

@ -3,13 +3,9 @@ import axios from 'axios'
import { GET_CALLS_RETRY, GET_CALLS_TIMEOUT } from 'config/constants' import { GET_CALLS_RETRY, GET_CALLS_TIMEOUT } from 'config/constants'
import { retry } from 'helpers/promise' import { retry } from 'helpers/promise'
import logger from 'logger' import logger from 'logger'
import { createCustomErrorClass } from 'helpers/errors' import { LedgerAPIErrorWithMessage, LedgerAPIError, NetworkDown } from 'config/errors'
import anonymizer from 'helpers/anonymizer' import anonymizer from 'helpers/anonymizer'
export const LedgerAPIErrorWithMessage = createCustomErrorClass('LedgerAPIErrorWithMessage')
export const LedgerAPIError = createCustomErrorClass('LedgerAPIError')
export const NetworkDown = createCustomErrorClass('NetworkDown')
const userFriendlyError = <A>(p: Promise<A>, { url, method, startTime }): Promise<A> => const userFriendlyError = <A>(p: Promise<A>, { url, method, startTime }): Promise<A> =>
p.catch(error => { p.catch(error => {
let errorToThrow let errorToThrow

5
src/bridge/EthereumJSBridge.js

@ -16,12 +16,9 @@ import { getDerivations } from 'helpers/derivations'
import getAddressCommand from 'commands/getAddress' import getAddressCommand from 'commands/getAddress'
import signTransactionCommand from 'commands/signTransaction' import signTransactionCommand from 'commands/signTransaction'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName' import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName'
import { createCustomErrorClass } from 'helpers/errors' import { NotEnoughBalance, ETHAddressNonEIP } from 'config/errors'
import { ETHAddressNonEIP } from 'config/errors'
import type { EditProps, WalletBridge } from './types' import type { EditProps, WalletBridge } from './types'
const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
type Transaction = { type Transaction = {
recipient: string, recipient: string,
amount: BigNumber, amount: BigNumber,

3
src/bridge/LibcoreBridge.js

@ -11,11 +11,10 @@ import libcoreSyncAccount from 'commands/libcoreSyncAccount'
import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast' import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast'
import libcoreGetFees from 'commands/libcoreGetFees' import libcoreGetFees from 'commands/libcoreGetFees'
import libcoreValidAddress from 'commands/libcoreValidAddress' import libcoreValidAddress from 'commands/libcoreValidAddress'
import { createCustomErrorClass } from 'helpers/errors' import { NotEnoughBalance } from 'config/errors'
import type { WalletBridge, EditProps } from './types' import type { WalletBridge, EditProps } from './types'
const NOT_ENOUGH_FUNDS = 52 const NOT_ENOUGH_FUNDS = 52
const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
const notImplemented = new Error('LibcoreBridge: not implemented') const notImplemented = new Error('LibcoreBridge: not implemented')

4
src/bridge/RippleJSBridge.js

@ -20,11 +20,9 @@ import {
import FeesRippleKind from 'components/FeesField/RippleKind' import FeesRippleKind from 'components/FeesField/RippleKind'
import AdvancedOptionsRippleKind from 'components/AdvancedOptions/RippleKind' import AdvancedOptionsRippleKind from 'components/AdvancedOptions/RippleKind'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName' import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName'
import { createCustomErrorClass } from 'helpers/errors' import { NotEnoughBalance } from 'config/errors'
import type { WalletBridge, EditProps } from './types' import type { WalletBridge, EditProps } from './types'
const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
type Transaction = { type Transaction = {
amount: BigNumber, amount: BigNumber,
recipient: string, recipient: string,

1
src/bridge/index.js

@ -12,6 +12,7 @@ const perFamily = {
bitcoin: LibcoreBridge, bitcoin: LibcoreBridge,
ripple: RippleJSBridge, ripple: RippleJSBridge,
ethereum: EthereumJSBridge, ethereum: EthereumJSBridge,
stellar: null,
} }
if (USE_MOCK_DATA) { if (USE_MOCK_DATA) {
const mockBridge = makeMockBridge() const mockBridge = makeMockBridge()

3
src/commands/getCurrentFirmware.js

@ -4,6 +4,7 @@ import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
import getCurrentFirmware from 'helpers/devices/getCurrentFirmware' import getCurrentFirmware from 'helpers/devices/getCurrentFirmware'
import type { FinalFirmware } from 'helpers/types'
type Input = { type Input = {
deviceId: string | number, deviceId: string | number,
@ -11,7 +12,7 @@ type Input = {
provider: number, provider: number,
} }
type Result = * type Result = FinalFirmware
const cmd: Command<Input, Result> = createCommand('getCurrentFirmware', data => const cmd: Command<Input, Result> = createCommand('getCurrentFirmware', data =>
fromPromise(getCurrentFirmware(data)), fromPromise(getCurrentFirmware(data)),

6
src/commands/getDeviceInfo.js

@ -5,13 +5,15 @@ import { fromPromise } from 'rxjs/observable/fromPromise'
import { withDevice } from 'helpers/deviceAccess' import { withDevice } from 'helpers/deviceAccess'
import getDeviceInfo from 'helpers/devices/getDeviceInfo' import getDeviceInfo from 'helpers/devices/getDeviceInfo'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo } from 'helpers/types'
type Input = { type Input = {
devicePath: string, devicePath: string,
} }
const cmd: Command<Input, DeviceInfo> = createCommand('getDeviceInfo', ({ devicePath }) => type Result = DeviceInfo
const cmd: Command<Input, Result> = createCommand('getDeviceInfo', ({ devicePath }) =>
fromPromise(withDevice(devicePath)(transport => getDeviceInfo(transport))), fromPromise(withDevice(devicePath)(transport => getDeviceInfo(transport))),
) )

2
src/commands/getIsGenuine.js

@ -2,7 +2,7 @@
import { createCommand, Command } from 'helpers/ipc' import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo } from 'helpers/types'
import getIsGenuine from 'helpers/devices/getIsGenuine' import getIsGenuine from 'helpers/devices/getIsGenuine'
import { withDevice } from 'helpers/deviceAccess' import { withDevice } from 'helpers/deviceAccess'

4
src/commands/getLatestFirmwareForDevice.js

@ -2,11 +2,11 @@
import { createCommand, Command } from 'helpers/ipc' import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo, OsuFirmware } from 'helpers/types'
import getLatestFirmwareForDevice from '../helpers/devices/getLatestFirmwareForDevice' import getLatestFirmwareForDevice from '../helpers/devices/getLatestFirmwareForDevice'
type Result = * type Result = ?(OsuFirmware & { shouldFlashMcu: boolean })
const cmd: Command<DeviceInfo, Result> = createCommand('getLatestFirmwareForDevice', data => const cmd: Command<DeviceInfo, Result> = createCommand('getLatestFirmwareForDevice', data =>
fromPromise(getLatestFirmwareForDevice(data)), fromPromise(getLatestFirmwareForDevice(data)),

2
src/commands/index.js

@ -17,7 +17,6 @@ import installOsuFirmware from 'commands/installOsuFirmware'
import isDashboardOpen from 'commands/isDashboardOpen' import isDashboardOpen from 'commands/isDashboardOpen'
import libcoreGetFees from 'commands/libcoreGetFees' import libcoreGetFees from 'commands/libcoreGetFees'
import libcoreGetVersion from 'commands/libcoreGetVersion' import libcoreGetVersion from 'commands/libcoreGetVersion'
import libcoreHardReset from 'commands/libcoreHardReset'
import libcoreScanAccounts from 'commands/libcoreScanAccounts' import libcoreScanAccounts from 'commands/libcoreScanAccounts'
import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast' import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast'
import libcoreSyncAccount from 'commands/libcoreSyncAccount' import libcoreSyncAccount from 'commands/libcoreSyncAccount'
@ -49,7 +48,6 @@ const all: Array<Command<any, any>> = [
isDashboardOpen, isDashboardOpen,
libcoreGetFees, libcoreGetFees,
libcoreGetVersion, libcoreGetVersion,
libcoreHardReset,
libcoreScanAccounts, libcoreScanAccounts,
libcoreSignAndBroadcast, libcoreSignAndBroadcast,
libcoreSyncAccount, libcoreSyncAccount,

6
src/commands/installApp.js

@ -6,15 +6,15 @@ import { fromPromise } from 'rxjs/observable/fromPromise'
import { withDevice } from 'helpers/deviceAccess' import { withDevice } from 'helpers/deviceAccess'
import installApp from 'helpers/apps/installApp' import installApp from 'helpers/apps/installApp'
import type { LedgerScriptParams } from 'helpers/types' import type { ApplicationVersion } from 'helpers/types'
type Input = { type Input = {
app: LedgerScriptParams, app: ApplicationVersion,
devicePath: string, devicePath: string,
targetId: string | number, targetId: string | number,
} }
type Result = * type Result = void
const cmd: Command<Input, Result> = createCommand( const cmd: Command<Input, Result> = createCommand(
'installApp', 'installApp',

2
src/commands/installMcu.js

@ -10,7 +10,7 @@ type Input = {
devicePath: string, devicePath: string,
} }
type Result = * type Result = void
const cmd: Command<Input, Result> = createCommand('installMcu', ({ devicePath }) => const cmd: Command<Input, Result> = createCommand('installMcu', ({ devicePath }) =>
fromPromise(withDevice(devicePath)(transport => installMcu(transport))), fromPromise(withDevice(devicePath)(transport => installMcu(transport))),

2
src/commands/installOsuFirmware.js

@ -14,7 +14,7 @@ type Input = {
firmware: Firmware, firmware: Firmware,
} }
type Result = * type Result = { success: boolean }
const cmd: Command<Input, Result> = createCommand( const cmd: Command<Input, Result> = createCommand(
'installOsuFirmware', 'installOsuFirmware',

4
src/commands/libcoreGetFees.js

@ -6,9 +6,7 @@ import withLibcore from 'helpers/withLibcore'
import { createCommand, Command } from 'helpers/ipc' import { createCommand, Command } from 'helpers/ipc'
import * as accountIdHelper from 'helpers/accountId' import * as accountIdHelper from 'helpers/accountId'
import { isValidAddress, libcoreAmountToBigNumber, bigNumberToLibcoreAmount } from 'helpers/libcore' import { isValidAddress, libcoreAmountToBigNumber, bigNumberToLibcoreAmount } from 'helpers/libcore'
import { createCustomErrorClass } from 'helpers/errors' import { InvalidAddress } from 'config/errors'
const InvalidAddress = createCustomErrorClass('InvalidAddress')
type BitcoinLikeTransaction = { type BitcoinLikeTransaction = {
// TODO we rename this Transaction concept into transactionInput // TODO we rename this Transaction concept into transactionInput

21
src/commands/libcoreHardReset.js

@ -1,21 +0,0 @@
// @flow
import { createCommand } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import withLibcore from 'helpers/withLibcore'
import { createCustomErrorClass } from 'helpers/errors'
const HardResetFail = createCustomErrorClass('HardResetFail')
const cmd = createCommand('libcoreHardReset', () =>
fromPromise(
withLibcore(async core => {
const result = await core.getPoolInstance().eraseDataSince(new Date(0))
if (result !== core.ERROR_CODE.FUTURE_WAS_SUCCESSFULL) {
throw new HardResetFail(`Hard reset fail with ${result} (check core.ERROR_CODE)`)
}
}),
),
)
export default cmd

4
src/commands/listAppVersions.js

@ -2,11 +2,11 @@
import { createCommand, Command } from 'helpers/ipc' import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo, ApplicationVersion } from 'helpers/types'
import listAppVersions from 'helpers/apps/listAppVersions' import listAppVersions from 'helpers/apps/listAppVersions'
type Result = * type Result = Array<ApplicationVersion>
const cmd: Command<DeviceInfo, Result> = createCommand('listAppVersions', deviceInfo => const cmd: Command<DeviceInfo, Result> = createCommand('listAppVersions', deviceInfo =>
fromPromise(listAppVersions(deviceInfo)), fromPromise(listAppVersions(deviceInfo)),

5
src/commands/listApps.js

@ -4,10 +4,11 @@ import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
import listApps from 'helpers/apps/listApps' import listApps from 'helpers/apps/listApps'
import type { Application } from 'helpers/types'
type Input = {} type Input = void
type Result = * type Result = Array<Application>
const cmd: Command<Input, Result> = createCommand('listApps', () => fromPromise(listApps())) const cmd: Command<Input, Result> = createCommand('listApps', () => fromPromise(listApps()))

5
src/commands/listCategories.js

@ -4,10 +4,11 @@ import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
import listCategories from 'helpers/apps/listCategories' import listCategories from 'helpers/apps/listCategories'
import type { Category } from 'helpers/types'
type Input = {} type Input = void
type Result = * type Result = Array<Category>
const cmd: Command<Input, Result> = createCommand('listCategories', () => const cmd: Command<Input, Result> = createCommand('listCategories', () =>
fromPromise(listCategories()), fromPromise(listCategories()),

3
src/commands/shouldFlashMcu.js

@ -2,9 +2,10 @@
import { createCommand, Command } from 'helpers/ipc' import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo'
import shouldFlashMcu from 'helpers/devices/shouldFlashMcu' import shouldFlashMcu from 'helpers/devices/shouldFlashMcu'
import type { DeviceInfo } from 'helpers/types'
type Result = boolean type Result = boolean
const cmd: Command<DeviceInfo, Result> = createCommand('shouldFlashMcu', data => const cmd: Command<DeviceInfo, Result> = createCommand('shouldFlashMcu', data =>

10
src/commands/uninstallApp.js

@ -6,20 +6,20 @@ import { withDevice } from 'helpers/deviceAccess'
import uninstallApp from 'helpers/apps/uninstallApp' import uninstallApp from 'helpers/apps/uninstallApp'
import type { LedgerScriptParams } from 'helpers/types' import type { ApplicationVersion } from 'helpers/types'
type Input = { type Input = {
app: LedgerScriptParams, app: ApplicationVersion,
devicePath: string, devicePath: string,
targetId: string | number, targetId: string | number,
} }
type Result = * type Result = void
const cmd: Command<Input, Result> = createCommand( const cmd: Command<Input, Result> = createCommand(
'uninstallApp', 'uninstallApp',
({ devicePath, targetId, ...rest }) => ({ devicePath, targetId, ...app }) =>
fromPromise(withDevice(devicePath)(transport => uninstallApp(transport, targetId, rest))), fromPromise(withDevice(devicePath)(transport => uninstallApp(transport, targetId, app))),
) )
export default cmd export default cmd

16
src/components/DashboardPage/EmptyState.js

@ -45,15 +45,25 @@ class EmptyState extends PureComponent<Props, *> {
height="157" height="157"
/> />
<Box mt={5} alignItems="center"> <Box mt={5} alignItems="center">
<Title>{t('app:emptyState.dashboard.title')}</Title> <Title data-e2e="dashboard_empty_title">{t('app:emptyState.dashboard.title')}</Title>
<Description mt={3} style={{ maxWidth: 600 }}> <Description mt={3} style={{ maxWidth: 600 }}>
{t('app:emptyState.dashboard.desc')} {t('app:emptyState.dashboard.desc')}
</Description> </Description>
<Box mt={5} horizontal style={{ width: 300 }} flow={3} justify="center"> <Box mt={5} horizontal style={{ width: 300 }} flow={3} justify="center">
<Button primary style={{ minWidth: 120 }} onClick={this.handleInstallApp}> <Button
primary
style={{ minWidth: 120 }}
onClick={this.handleInstallApp}
data-e2e="dashboard_empty_OpenManager"
>
{t('app:emptyState.dashboard.buttons.installApp')} {t('app:emptyState.dashboard.buttons.installApp')}
</Button> </Button>
<Button outline style={{ minWidth: 120 }} onClick={() => openModal(MODAL_ADD_ACCOUNTS)}> <Button
outline
style={{ minWidth: 120 }}
onClick={() => openModal(MODAL_ADD_ACCOUNTS)}
data-e2e="dashboard_empty_AddAccounts"
>
{t('app:emptyState.dashboard.buttons.addAccount')} {t('app:emptyState.dashboard.buttons.addAccount')}
</Button> </Button>
</Box> </Box>

3
src/components/EnsureDeviceApp.js

@ -12,7 +12,6 @@ import getAddress from 'commands/getAddress'
import { createCancelablePolling } from 'helpers/promise' import { createCancelablePolling } from 'helpers/promise'
import { standardDerivation } from 'helpers/derivations' import { standardDerivation } from 'helpers/derivations'
import { isSegwitPath } from 'helpers/bip32' import { isSegwitPath } from 'helpers/bip32'
import { BtcUnmatchedApp } from 'helpers/getAddressForCurrency/btc'
import DeviceInteraction from 'components/DeviceInteraction' import DeviceInteraction from 'components/DeviceInteraction'
import Text from 'components/base/Text' import Text from 'components/base/Text'
@ -21,7 +20,7 @@ import IconUsb from 'icons/Usb'
import type { Device } from 'types/common' import type { Device } from 'types/common'
import { WrongDeviceForAccount, CantOpenDevice } from 'config/errors' import { WrongDeviceForAccount, CantOpenDevice, BtcUnmatchedApp } from 'config/errors'
import { getCurrentDevice } from 'reducers/devices' import { getCurrentDevice } from 'reducers/devices'
const usbIcon = <IconUsb size={16} /> const usbIcon = <IconUsb size={16} />

2
src/components/GenuineCheck.js

@ -9,7 +9,7 @@ import { delay, createCancelablePolling } from 'helpers/promise'
import logger from 'logger' import logger from 'logger'
import type { T, Device } from 'types/common' import type { T, Device } from 'types/common'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo } from 'helpers/types'
import { GENUINE_TIMEOUT, DEVICE_INFOS_TIMEOUT, GENUINE_CACHE_DELAY } from 'config/constants' import { GENUINE_TIMEOUT, DEVICE_INFOS_TIMEOUT, GENUINE_CACHE_DELAY } from 'config/constants'

6
src/components/IsUnlocked.js

@ -12,12 +12,12 @@ import { i } from 'helpers/staticPath'
import IconTriangleWarning from 'icons/TriangleWarning' import IconTriangleWarning from 'icons/TriangleWarning'
import db from 'helpers/db' import db from 'helpers/db'
import hardReset from 'helpers/hardReset' import { hardReset } from 'helpers/reset'
import { fetchAccounts } from 'actions/accounts' import { fetchAccounts } from 'actions/accounts'
import { isLocked, unlock } from 'reducers/application' import { isLocked, unlock } from 'reducers/application'
import { createCustomErrorClass } from 'helpers/errors' import { PasswordIncorrectError } from 'config/errors'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import InputPassword from 'components/base/InputPassword' import InputPassword from 'components/base/InputPassword'
@ -26,8 +26,6 @@ import IconArrowRight from 'icons/ArrowRight'
import Button from './base/Button/index' import Button from './base/Button/index'
import ConfirmModal from './base/Modal/ConfirmModal' import ConfirmModal from './base/Modal/ConfirmModal'
const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect')
type InputValue = { type InputValue = {
password: string, password: string,
} }

6
src/components/ManagerPage/AppSearchBar.js

@ -3,7 +3,7 @@
import React, { PureComponent, Fragment } from 'react' import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import type { LedgerScriptParams } from 'helpers/types' import type { ApplicationVersion } from 'helpers/types'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Space from 'components/base/Space' import Space from 'components/base/Space'
@ -23,8 +23,8 @@ const CrossContainer = styled(Box).attrs({
` `
type Props = { type Props = {
list: Array<LedgerScriptParams>, list: Array<ApplicationVersion>,
children: (list: Array<LedgerScriptParams>) => React$Node, children: (list: Array<ApplicationVersion>) => React$Node,
} }
type State = { type State = {

22
src/components/ManagerPage/AppsList.js

@ -7,8 +7,7 @@ import { translate } from 'react-i18next'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { compose } from 'redux' import { compose } from 'redux'
import type { Device, T } from 'types/common' import type { Device, T } from 'types/common'
import type { LedgerScriptParams } from 'helpers/types' import type { Application, ApplicationVersion, DeviceInfo } from 'helpers/types'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo'
import { developerModeSelector } from 'reducers/settings' import { developerModeSelector } from 'reducers/settings'
import listApps from 'commands/listApps' import listApps from 'commands/listApps'
@ -66,7 +65,7 @@ type Props = {
type State = { type State = {
status: Status, status: Status,
error: ?Error, error: ?Error,
filteredAppVersionsList: LedgerScriptParams[], filteredAppVersionsList: Array<ApplicationVersion>,
appsLoaded: boolean, appsLoaded: boolean,
app: string, app: string,
mode: Mode, mode: Mode,
@ -102,9 +101,14 @@ class AppsList extends PureComponent<Props, State> {
filterAppVersions = (applicationsList, compatibleAppVersionsList) => { filterAppVersions = (applicationsList, compatibleAppVersionsList) => {
if (!this.props.isDevMode) { if (!this.props.isDevMode) {
return compatibleAppVersionsList.filter( return compatibleAppVersionsList.filter(version => {
version => applicationsList.find(e => e.id === version.app).category !== 2, const app = applicationsList.find(e => e.id === version.app)
) if (app) {
return app.category !== 2
}
return false
})
} }
return compatibleAppVersionsList return compatibleAppVersionsList
} }
@ -112,7 +116,7 @@ class AppsList extends PureComponent<Props, State> {
async fetchAppList() { async fetchAppList() {
try { try {
const { deviceInfo } = this.props const { deviceInfo } = this.props
const applicationsList = await listApps.send({}).toPromise() const applicationsList: Array<Application> = await listApps.send().toPromise()
const compatibleAppVersionsList = await listAppVersions.send(deviceInfo).toPromise() const compatibleAppVersionsList = await listAppVersions.send(deviceInfo).toPromise()
const filteredAppVersionsList = this.filterAppVersions( const filteredAppVersionsList = this.filterAppVersions(
applicationsList, applicationsList,
@ -131,7 +135,7 @@ class AppsList extends PureComponent<Props, State> {
} }
} }
handleInstallApp = (app: LedgerScriptParams) => async () => { handleInstallApp = (app: ApplicationVersion) => async () => {
this.setState({ status: 'busy', app: app.name, mode: 'installing' }) this.setState({ status: 'busy', app: app.name, mode: 'installing' })
try { try {
const { const {
@ -146,7 +150,7 @@ class AppsList extends PureComponent<Props, State> {
} }
} }
handleUninstallApp = (app: LedgerScriptParams) => async () => { handleUninstallApp = (app: ApplicationVersion) => async () => {
this.setState({ status: 'busy', app: app.name, mode: 'uninstalling' }) this.setState({ status: 'busy', app: app.name, mode: 'uninstalling' })
try { try {
const { const {

2
src/components/ManagerPage/Dashboard.js

@ -4,7 +4,7 @@ import { translate } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import type { T, Device } from 'types/common' import type { T, Device } from 'types/common'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo } from 'helpers/types'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Text from 'components/base/Text' import Text from 'components/base/Text'

5
src/components/ManagerPage/FirmwareUpdate.js

@ -9,7 +9,7 @@ import invariant from 'invariant'
import type { Device, T } from 'types/common' import type { Device, T } from 'types/common'
import type { LedgerScriptParams } from 'helpers/types' import type { DeviceInfo, OsuFirmware } from 'helpers/types'
import type { StepId } from 'components/modals/UpdateFirmware' import type { StepId } from 'components/modals/UpdateFirmware'
import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice' import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice'
@ -19,7 +19,6 @@ import installFinalFirmware from 'commands/installFinalFirmware'
import installMcu from 'commands/installMcu' import installMcu from 'commands/installMcu'
import DisclaimerModal from 'components/modals/UpdateFirmware/Disclaimer' import DisclaimerModal from 'components/modals/UpdateFirmware/Disclaimer'
import UpdateModal from 'components/modals/UpdateFirmware' import UpdateModal from 'components/modals/UpdateFirmware'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo'
import Tooltip from 'components/base/Tooltip' import Tooltip from 'components/base/Tooltip'
import Box, { Card } from 'components/base/Box' import Box, { Card } from 'components/base/Box'
@ -43,7 +42,7 @@ type Props = {
} }
type State = { type State = {
latestFirmware: ?LedgerScriptParams & ?{ shouldFlashMcu: boolean }, latestFirmware: ?OsuFirmware & ?{ shouldFlashMcu: boolean },
modal: ModalStatus, modal: ModalStatus,
stepId: ?StepId, stepId: ?StepId,
shouldFlash: boolean, shouldFlash: boolean,

2
src/components/ManagerPage/index.js

@ -6,7 +6,7 @@ import { openURL } from 'helpers/linking'
import { urls } from 'config/urls' import { urls } from 'config/urls'
import type { Device } from 'types/common' import type { Device } from 'types/common'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo } from 'helpers/types'
import Dashboard from './Dashboard' import Dashboard from './Dashboard'

8
src/components/Onboarding/OnboardingFooter.js

@ -26,7 +26,13 @@ const OnboardingFooter = ({
<Button outlineGrey onClick={() => prevStep()}> <Button outlineGrey onClick={() => prevStep()}>
{t('app:common.back')} {t('app:common.back')}
</Button> </Button>
<Button disabled={isContinueDisabled} primary onClick={() => nextStep()} ml="auto"> <Button
data-e2e="continue_button"
disabled={isContinueDisabled}
primary
onClick={() => nextStep()}
ml="auto"
>
{t('app:common.continue')} {t('app:common.continue')}
</Button> </Button>
</OnboardingFooterWrapper> </OnboardingFooterWrapper>

2
src/components/Onboarding/steps/Analytics.js

@ -70,7 +70,7 @@ class Analytics extends PureComponent<StepProps, State> {
deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'}
/> />
<StepContainerInner> <StepContainerInner>
<Title>{t('onboarding:analytics.title')}</Title> <Title data-e2e="onboarding_title">{t('onboarding:analytics.title')}</Title>
<Description>{t('onboarding:analytics.desc')}</Description> <Description>{t('onboarding:analytics.desc')}</Description>
<Box mt={5}> <Box mt={5}>
<Container> <Container>

4
src/components/Onboarding/steps/Finish.js

@ -103,11 +103,11 @@ export default class Finish extends Component<StepProps, *> {
</Box> </Box>
<Box pt={5} align="center"> <Box pt={5} align="center">
<Title>{t('onboarding:finish.title')}</Title> <Title data-e2e="finish_title">{t('onboarding:finish.title')}</Title>
<Description>{t('onboarding:finish.desc')}</Description> <Description>{t('onboarding:finish.desc')}</Description>
</Box> </Box>
<Box p={5}> <Box p={5}>
<Button primary onClick={() => finish()}> <Button primary onClick={() => finish()} data-e2e="continue_button">
{t('onboarding:finish.openAppButton')} {t('onboarding:finish.openAppButton')}
</Button> </Button>
</Box> </Box>

34
src/components/QRCodeExporter.js

@ -1,31 +1,21 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { createSelector } from 'reselect'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import type { State } from 'reducers'
import { accountsSelector } from 'reducers/accounts' import { accountsSelector } from 'reducers/accounts'
import { makeChunks } from '@ledgerhq/live-common/lib/bridgestream/exporter'
import QRCode from './base/QRCode' import QRCode from './base/QRCode'
// encode the app state to export into an array of chunks for the mobile app to understand. const mapStateToProps = createSelector(accountsSelector, accounts => ({
// returned data frames are json stringified array with format: [ datalength, index, type, ...rest ] chunks: makeChunks({
// NB as soon as we have common types we'll move this in a ledgerhq/common project accounts,
function makeChunks(state: State): Array<string> { exporterName: 'desktop',
const chunksFormatVersion = 1 exporterVersion: __APP_VERSION__,
const desktopVersion = __APP_VERSION__ pad: true,
const data = [ }),
['meta', chunksFormatVersion, 'desktop', desktopVersion], }))
...accountsSelector(state).map(account => [
'account',
account.id,
account.name,
account.currency.id,
]),
]
return data.map((arr, i) => JSON.stringify([data.length, i, ...arr]))
}
const mapStateToProps = (state: State) => ({ chunks: makeChunks(state) })
class QRCodeExporter extends PureComponent< class QRCodeExporter extends PureComponent<
{ {
@ -38,7 +28,7 @@ class QRCodeExporter extends PureComponent<
}, },
> { > {
static defaultProps = { static defaultProps = {
fps: 10, fps: 4,
size: 480, size: 480,
} }

3
src/components/RecipientAddress/index.js

@ -101,9 +101,10 @@ class RecipientAddress extends PureComponent<Props, State> {
</Right> </Right>
) : null ) : null
const preOnChange = text => onChange((text && text.replace(/\s/g, '')) || '')
return ( return (
<Box relative justifyContent="center"> <Box relative justifyContent="center">
<Input {...rest} value={value} onChange={onChange} renderRight={renderRight} /> <Input {...rest} value={value} onChange={preOnChange} renderRight={renderRight} />
</Box> </Box>
) )
} }

2
src/components/RenderError.js

@ -8,7 +8,7 @@ import { translate } from 'react-i18next'
import { urls } from 'config/urls' import { urls } from 'config/urls'
import { i } from 'helpers/staticPath' import { i } from 'helpers/staticPath'
import hardReset from 'helpers/hardReset' import { hardReset } from 'helpers/reset'
import type { T } from 'types/common' import type { T } from 'types/common'

20
src/components/SettingsPage/CleanButton.js

@ -4,12 +4,10 @@ import React, { Fragment, PureComponent } from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import type { T } from 'types/common' import type { T } from 'types/common'
import { remote } from 'electron'
import { cleanAccountsCache } from 'actions/accounts' import { cleanAccountsCache } from 'actions/accounts'
import db from 'helpers/db'
import { delay } from 'helpers/promise'
import Button from 'components/base/Button' import Button from 'components/base/Button'
import { ConfirmModal } from 'components/base/Modal' import { ConfirmModal } from 'components/base/Modal'
import { softReset } from 'helpers/reset'
const mapDispatchToProps = { const mapDispatchToProps = {
cleanAccountsCache, cleanAccountsCache,
@ -22,11 +20,13 @@ type Props = {
type State = { type State = {
opened: boolean, opened: boolean,
isLoading: boolean,
} }
class CleanButton extends PureComponent<Props, State> { class CleanButton extends PureComponent<Props, State> {
state = { state = {
opened: false, opened: false,
isLoading: false,
} }
open = () => this.setState({ opened: true }) open = () => this.setState({ opened: true })
@ -34,15 +34,18 @@ class CleanButton extends PureComponent<Props, State> {
close = () => this.setState({ opened: false }) close = () => this.setState({ opened: false })
action = async () => { action = async () => {
this.props.cleanAccountsCache() if (this.state.isLoading) return
await delay(500) try {
db.cleanCache() this.setState({ isLoading: true })
remote.getCurrentWindow().webContents.reload() await softReset({ cleanAccountsCache: this.props.cleanAccountsCache })
} finally {
this.setState({ isLoading: false })
}
} }
render() { render() {
const { t } = this.props const { t } = this.props
const { opened } = this.state const { opened, isLoading } = this.state
return ( return (
<Fragment> <Fragment>
<Button small primary onClick={this.open} event="ClearCacheIntent"> <Button small primary onClick={this.open} event="ClearCacheIntent">
@ -55,6 +58,7 @@ class CleanButton extends PureComponent<Props, State> {
onClose={this.close} onClose={this.close}
onReject={this.close} onReject={this.close}
onConfirm={this.action} onConfirm={this.action}
isLoading={isLoading}
title={t('app:settings.softResetModal.title')} title={t('app:settings.softResetModal.title')}
subTitle={t('app:common.areYouSure')} subTitle={t('app:common.areYouSure')}
desc={t('app:settings.softResetModal.desc')} desc={t('app:settings.softResetModal.desc')}

2
src/components/SettingsPage/DevModeButton.js

@ -27,7 +27,7 @@ class DevModeButton extends PureComponent<Props> {
return ( return (
<Fragment> <Fragment>
<Track onUpdate event={developerMode ? 'DevModeEnabled' : 'DevModeDisabled'} /> <Track onUpdate event={developerMode ? 'DevModeEnabled' : 'DevModeDisabled'} />
<Switch isChecked={developerMode} onChange={setDeveloperMode} /> <Switch isChecked={developerMode} onChange={setDeveloperMode} data-e2e="devMode_button" />
</Fragment> </Fragment>
) )
} }

4
src/components/SettingsPage/DisablePasswordModal.js

@ -1,7 +1,7 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { createCustomErrorClass } from 'helpers/errors' import { PasswordIncorrectError } from 'config/errors'
import db from 'helpers/db' import db from 'helpers/db'
import Box from 'components/base/Box' import Box from 'components/base/Box'
@ -12,8 +12,6 @@ import { Modal, ModalContent, ModalBody, ModalTitle, ModalFooter } from 'compone
import type { T } from 'types/common' import type { T } from 'types/common'
const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect')
type Props = { type Props = {
t: T, t: T,
onClose: Function, onClose: Function,

4
src/components/SettingsPage/PasswordForm.js

@ -6,12 +6,10 @@ import Box from 'components/base/Box'
import InputPassword from 'components/base/InputPassword' import InputPassword from 'components/base/InputPassword'
import Label from 'components/base/Label' import Label from 'components/base/Label'
import { createCustomErrorClass } from 'helpers/errors' import { PasswordsDontMatchError } from 'config/errors'
import type { T } from 'types/common' import type { T } from 'types/common'
const PasswordsDontMatchError = createCustomErrorClass('PasswordsDontMatch')
type Props = { type Props = {
t: T, t: T,
hasPassword: boolean, hasPassword: boolean,

4
src/components/SettingsPage/PasswordModal.js

@ -5,15 +5,13 @@ import React, { PureComponent } from 'react'
import type { T } from 'types/common' import type { T } from 'types/common'
import db from 'helpers/db' import db from 'helpers/db'
import { createCustomErrorClass } from 'helpers/errors' import { PasswordIncorrectError } from 'config/errors'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Button from 'components/base/Button' import Button from 'components/base/Button'
import { Modal, ModalContent, ModalBody, ModalTitle, ModalFooter } from 'components/base/Modal' import { Modal, ModalContent, ModalBody, ModalTitle, ModalFooter } from 'components/base/Modal'
import PasswordForm from './PasswordForm' import PasswordForm from './PasswordForm'
const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect')
type Props = { type Props = {
t: T, t: T,
onClose: () => void, onClose: () => void,

2
src/components/SettingsPage/ResetButton.js

@ -5,7 +5,7 @@ import styled from 'styled-components'
import { remote } from 'electron' import { remote } from 'electron'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import type { T } from 'types/common' import type { T } from 'types/common'
import hardReset from 'helpers/hardReset' import { hardReset } from 'helpers/reset'
import Box from 'components/base/Box' import Box from 'components/base/Box'
import Button from 'components/base/Button' import Button from 'components/base/Button'
import { ConfirmModal } from 'components/base/Modal' import { ConfirmModal } from 'components/base/Modal'

2
src/components/SettingsPage/index.js

@ -106,7 +106,7 @@ class SettingsPage extends PureComponent<Props, State> {
return ( return (
<Box pb={4} selectable> <Box pb={4} selectable>
<Box ff="Museo Sans|Regular" color="dark" fontSize={7} mb={5}> <Box ff="Museo Sans|Regular" color="dark" fontSize={7} mb={5} data-e2e="settings_title">
{t('app:settings.title')} {t('app:settings.title')}
</Box> </Box>
<Pills mb={4} items={items} activeKey={tab.key} onChange={this.handleChangeTab} /> <Pills mb={4} items={items} activeKey={tab.key} onChange={this.handleChangeTab} />

2
src/components/TopBar/index.js

@ -109,7 +109,7 @@ class TopBar extends PureComponent<Props> {
</Box> </Box>
</Fragment> </Fragment>
)} )}
<Tooltip render={() => t('app:settings.title')}> <Tooltip render={() => t('app:settings.title')} data-e2e="setting_button">
<ItemContainer isInteractive onClick={this.navigateToSettings}> <ItemContainer isInteractive onClick={this.navigateToSettings}>
<IconSettings size={16} /> <IconSettings size={16} />
</ItemContainer> </ItemContainer>

5
src/components/base/InputCurrency/index.js

@ -172,7 +172,7 @@ class InputCurrency extends PureComponent<Props, State> {
renderListUnits = () => { renderListUnits = () => {
const { units, onChangeUnit, unit } = this.props const { units, onChangeUnit, unit } = this.props
const { isFocused } = this.state const { isFocused } = this.state
const avoidEmptyValue = value => value && onChangeUnit(value)
if (units.length <= 1) { if (units.length <= 1) {
return null return null
} }
@ -180,13 +180,14 @@ class InputCurrency extends PureComponent<Props, State> {
return ( return (
<Currencies onClick={stopPropagation}> <Currencies onClick={stopPropagation}>
<Select <Select
onChange={onChangeUnit} onChange={avoidEmptyValue}
options={units} options={units}
value={unit} value={unit}
getOptionValue={unitGetOptionValue} getOptionValue={unitGetOptionValue}
renderOption={this.renderOption} renderOption={this.renderOption}
renderValue={this.renderValue} renderValue={this.renderValue}
fakeFocusRight={isFocused} fakeFocusRight={isFocused}
isRight
/> />
</Currencies> </Currencies>
) )

1
src/components/base/QRCode/index.js

@ -28,6 +28,7 @@ class QRCode extends PureComponent<Props> {
qrcode.toCanvas(this._canvas, data, { qrcode.toCanvas(this._canvas, data, {
width: size, width: size,
margin: 0, margin: 0,
errorCorrectionLevel: 'Q',
color: { color: {
light: '#ffffff00', // transparent background light: '#ffffff00', // transparent background
}, },

6
src/components/base/Select/createStyles.js

@ -7,10 +7,14 @@ export default ({
width, width,
minWidth, minWidth,
small, small,
isRight,
isLeft,
}: { }: {
width: number, width: number,
minWidth: number, minWidth: number,
small: boolean, small: boolean,
isRight: boolean,
isLeft: boolean,
}) => ({ }) => ({
control: (styles: Object, { isFocused }: Object) => ({ control: (styles: Object, { isFocused }: Object) => ({
...styles, ...styles,
@ -19,6 +23,8 @@ export default ({
...ff('Open Sans|SemiBold'), ...ff('Open Sans|SemiBold'),
height: small ? 34 : 40, height: small ? 34 : 40,
minHeight: 'unset', minHeight: 'unset',
borderRadius: isRight ? '0 4px 4px 0' : isLeft ? '4px 0 0 4px' : 4,
borderColor: colors.fog,
backgroundColor: 'white', backgroundColor: 'white',
...(isFocused ...(isFocused

6
src/components/base/Select/index.js

@ -21,6 +21,8 @@ type Props = {
placeholder: string, placeholder: string,
isClearable: boolean, isClearable: boolean,
isDisabled: boolean, isDisabled: boolean,
isRight: boolean,
isLeft: boolean,
isLoading: boolean, isLoading: boolean,
isSearchable: boolean, isSearchable: boolean,
small: boolean, small: boolean,
@ -52,6 +54,8 @@ class Select extends PureComponent<Props> {
isSearchable, isSearchable,
isDisabled, isDisabled,
isLoading, isLoading,
isRight,
isLeft,
placeholder, placeholder,
options, options,
renderOption, renderOption,
@ -69,7 +73,7 @@ class Select extends PureComponent<Props> {
classNamePrefix="select" classNamePrefix="select"
options={options} options={options}
components={createRenderers({ renderOption, renderValue })} components={createRenderers({ renderOption, renderValue })}
styles={createStyles({ width, minWidth, small })} styles={createStyles({ width, minWidth, small, isRight, isLeft })}
placeholder={placeholder} placeholder={placeholder}
isDisabled={isDisabled} isDisabled={isDisabled}
isLoading={isLoading} isLoading={isLoading}

5
src/components/modals/AccountSettingRenderBody.js

@ -17,7 +17,7 @@ import { setDataModal } from 'reducers/modals'
import { getBridgeForCurrency } from 'bridge' import { getBridgeForCurrency } from 'bridge'
import { createCustomErrorClass } from 'helpers/errors' import { AccountNameRequiredError, EnpointConfigError } from 'config/errors'
import TrackPage from 'analytics/TrackPage' import TrackPage from 'analytics/TrackPage'
import Spoiler from 'components/base/Spoiler' import Spoiler from 'components/base/Spoiler'
@ -36,9 +36,6 @@ import {
ConfirmModal, ConfirmModal,
} from 'components/base/Modal' } from 'components/base/Modal'
const AccountNameRequiredError = createCustomErrorClass('AccountNameRequired')
const EnpointConfigError = createCustomErrorClass('EnpointConfig')
type State = { type State = {
accountName: ?string, accountName: ?string,
accountUnit: ?Unit, accountUnit: ?Unit,

4
src/components/modals/Disclaimer.js

@ -25,7 +25,7 @@ class DisclaimerModal extends PureComponent<Props> {
name={MODAL_DISCLAIMER} name={MODAL_DISCLAIMER}
render={({ onClose }) => ( render={({ onClose }) => (
<ModalBody onClose={onClose}> <ModalBody onClose={onClose}>
<ModalTitle>{t('app:disclaimerModal.title')}</ModalTitle> <ModalTitle data-e2e="disclaimer_title">{t('app:disclaimerModal.title')}</ModalTitle>
<ModalContent flow={4} ff="Open Sans|Regular" fontSize={4} color="smoke"> <ModalContent flow={4} ff="Open Sans|Regular" fontSize={4} color="smoke">
<Box align="center" mt={4} pb={4}> <Box align="center" mt={4} pb={4}>
<HandShield size={55} /> <HandShield size={55} />
@ -34,7 +34,7 @@ class DisclaimerModal extends PureComponent<Props> {
<p>{t('app:disclaimerModal.desc_2')}</p> <p>{t('app:disclaimerModal.desc_2')}</p>
</ModalContent> </ModalContent>
<ModalFooter horizontal justifyContent="flex-end"> <ModalFooter horizontal justifyContent="flex-end">
<Button onClick={onClose} primary> <Button data-e2e="continue_button" onClick={onClose} primary>
{t('app:disclaimerModal.cta')} {t('app:disclaimerModal.cta')}
</Button> </Button>
</ModalFooter> </ModalFooter>

4
src/components/modals/UpdateFirmware/index.js

@ -10,7 +10,7 @@ import SyncSkipUnderPriority from 'components/SyncSkipUnderPriority'
import type { StepProps as DefaultStepProps, Step } from 'components/base/Stepper' import type { StepProps as DefaultStepProps, Step } from 'components/base/Stepper'
import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate' import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate'
import type { LedgerScriptParams } from 'helpers/types' import type { OsuFirmware } from 'helpers/types'
import { FreezeDeviceChangeEvents } from '../../ManagerPage/HookDeviceChange' import { FreezeDeviceChangeEvents } from '../../ManagerPage/HookDeviceChange'
import StepFullFirmwareInstall from './steps/01-step-install-full-firmware' import StepFullFirmwareInstall from './steps/01-step-install-full-firmware'
@ -56,7 +56,7 @@ const createSteps = ({ t, shouldFlashMcu }: { t: T, shouldFlashMcu: boolean }):
return steps return steps
} }
export type Firmware = LedgerScriptParams & { shouldFlashMcu: boolean } export type Firmware = OsuFirmware & { shouldFlashMcu: boolean }
export type StepProps = DefaultStepProps & { export type StepProps = DefaultStepProps & {
firmware: Firmware, firmware: Firmware,

36
src/config/errors.js

@ -4,15 +4,41 @@
import { createCustomErrorClass } from 'helpers/errors' import { createCustomErrorClass } from 'helpers/errors'
export const DisconnectedDevice = createCustomErrorClass('DisconnectedDevice') export const AccountNameRequiredError = createCustomErrorClass('AccountNameRequired')
export const UserRefusedOnDevice = createCustomErrorClass('UserRefusedOnDevice') // TODO rename because it's just for transaction refusal export const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp')
export const CantOpenDevice = createCustomErrorClass('CantOpenDevice') export const CantOpenDevice = createCustomErrorClass('CantOpenDevice')
export const DeviceAppVerifyNotSupported = createCustomErrorClass('DeviceAppVerifyNotSupported') export const DeviceAppVerifyNotSupported = createCustomErrorClass('DeviceAppVerifyNotSupported')
export const UserRefusedAddress = createCustomErrorClass('UserRefusedAddress')
export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount')
export const DeviceNotGenuineError = createCustomErrorClass('DeviceNotGenuine')
export const DeviceGenuineSocketEarlyClose = createCustomErrorClass('DeviceGenuineSocketEarlyClose') export const DeviceGenuineSocketEarlyClose = createCustomErrorClass('DeviceGenuineSocketEarlyClose')
export const DeviceNotGenuineError = createCustomErrorClass('DeviceNotGenuine')
export const DeviceSocketFail = createCustomErrorClass('DeviceSocketFail')
export const DeviceSocketNoBulkStatus = createCustomErrorClass('DeviceSocketNoBulkStatus')
export const DeviceSocketNoHandler = createCustomErrorClass('DeviceSocketNoHandler')
export const DisconnectedDevice = createCustomErrorClass('DisconnectedDevice')
export const EnpointConfigError = createCustomErrorClass('EnpointConfig')
export const FeeEstimationFailed = createCustomErrorClass('FeeEstimationFailed')
export const HardResetFail = createCustomErrorClass('HardResetFail')
export const InvalidAddress = createCustomErrorClass('InvalidAddress')
export const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError')
export const LedgerAPIError = createCustomErrorClass('LedgerAPIError')
export const LedgerAPIErrorWithMessage = createCustomErrorClass('LedgerAPIErrorWithMessage')
export const LedgerAPINotAvailable = createCustomErrorClass('LedgerAPINotAvailable')
export const ManagerAppAlreadyInstalledError = createCustomErrorClass('ManagerAppAlreadyInstalled')
export const ManagerAppRelyOnBTCError = createCustomErrorClass('ManagerAppRelyOnBTC')
export const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked')
export const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace')
export const ManagerUninstallBTCDep = createCustomErrorClass('ManagerUninstallBTCDep')
export const NetworkDown = createCustomErrorClass('NetworkDown')
export const NoAddressesFound = createCustomErrorClass('NoAddressesFound')
export const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
export const PasswordsDontMatchError = createCustomErrorClass('PasswordsDontMatch')
export const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect')
export const TimeoutTagged = createCustomErrorClass('TimeoutTagged') export const TimeoutTagged = createCustomErrorClass('TimeoutTagged')
export const UserRefusedAddress = createCustomErrorClass('UserRefusedAddress')
export const UserRefusedFirmwareUpdate = createCustomErrorClass('UserRefusedFirmwareUpdate')
export const UserRefusedOnDevice = createCustomErrorClass('UserRefusedOnDevice') // TODO rename because it's just for transaction refusal
export const WebsocketConnectionError = createCustomErrorClass('WebsocketConnectionError')
export const WebsocketConnectionFailed = createCustomErrorClass('WebsocketConnectionFailed')
export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount')
export const ETHAddressNonEIP = createCustomErrorClass('ETHAddressNonEIP') export const ETHAddressNonEIP = createCustomErrorClass('ETHAddressNonEIP')
export const CantScanQRCode = createCustomErrorClass('CantScanQRCode') export const CantScanQRCode = createCustomErrorClass('CantScanQRCode')

26
src/helpers/apps/installApp.js

@ -1,18 +1,17 @@
// @flow // @flow
import qs from 'qs'
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { BASE_SOCKET_URL } from 'config/constants'
import { createDeviceSocket } from 'helpers/socket' import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/types' import type { ApplicationVersion } from 'helpers/types'
import { WS_INSTALL } from 'helpers/urls'
import { createCustomErrorClass } from 'helpers/errors' import {
ManagerNotEnoughSpaceError,
const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace') ManagerDeviceLockedError,
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') ManagerAppAlreadyInstalledError,
const ManagerAppAlreadyInstalledError = createCustomErrorClass('ManagerAppAlreadyInstalled') ManagerAppRelyOnBTCError,
const ManagerAppRelyOnBTCError = createCustomErrorClass('ManagerAppRelyOnBTC') } from 'config/errors'
function remapError(promise) { function remapError(promise) {
return promise.catch((e: Error) => { return promise.catch((e: Error) => {
@ -37,8 +36,8 @@ function remapError(promise) {
export default async function installApp( export default async function installApp(
transport: Transport<*>, transport: Transport<*>,
targetId: string | number, targetId: string | number,
{ app }: { app: LedgerScriptParams }, { app }: { app: ApplicationVersion },
): Promise<*> { ): Promise<void> {
const params = { const params = {
targetId, targetId,
perso: app.perso, perso: app.perso,
@ -47,6 +46,7 @@ export default async function installApp(
firmwareKey: app.firmware_key, firmwareKey: app.firmware_key,
hash: app.hash, hash: app.hash,
} }
const url = `${BASE_SOCKET_URL}/install?${qs.stringify(params)}`
return remapError(createDeviceSocket(transport, url).toPromise()) const url = WS_INSTALL(params)
await remapError(createDeviceSocket(transport, url).toPromise())
} }

15
src/helpers/apps/listAppVersions.js

@ -1,14 +1,19 @@
// @flow // @flow
import network from 'api/network' import network from 'api/network'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo, DeviceVersion, FinalFirmware, ApplicationVersion } from 'helpers/types'
import { APPLICATIONS_BY_DEVICE } from 'helpers/urls' import { APPLICATIONS_BY_DEVICE } from 'helpers/urls'
import getDeviceVersion from 'helpers/devices/getDeviceVersion' import getDeviceVersion from 'helpers/devices/getDeviceVersion'
import getCurrentFirmware from 'helpers/devices/getCurrentFirmware' import getCurrentFirmware from 'helpers/devices/getCurrentFirmware'
export default async (deviceInfo: DeviceInfo) => { type NetworkResponse = { data: { application_versions: Array<ApplicationVersion> } }
const deviceData = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId)
const firmwareData = await getCurrentFirmware({ export default async (deviceInfo: DeviceInfo): Promise<Array<ApplicationVersion>> => {
const deviceData: DeviceVersion = await getDeviceVersion(
deviceInfo.targetId,
deviceInfo.providerId,
)
const firmwareData: FinalFirmware = await getCurrentFirmware({
deviceId: deviceData.id, deviceId: deviceData.id,
fullVersion: deviceInfo.fullVersion, fullVersion: deviceInfo.fullVersion,
provider: deviceInfo.providerId, provider: deviceInfo.providerId,
@ -20,6 +25,6 @@ export default async (deviceInfo: DeviceInfo) => {
} }
const { const {
data: { application_versions }, data: { application_versions },
} = await network({ method: 'POST', url: APPLICATIONS_BY_DEVICE, data: params }) }: NetworkResponse = await network({ method: 'POST', url: APPLICATIONS_BY_DEVICE, data: params })
return application_versions.length > 0 ? application_versions : [] return application_versions.length > 0 ? application_versions : []
} }

3
src/helpers/apps/listApps.js

@ -2,8 +2,9 @@
import network from 'api/network' import network from 'api/network'
import { GET_APPLICATIONS } from 'helpers/urls' import { GET_APPLICATIONS } from 'helpers/urls'
import type { Application } from 'helpers/types'
export default async () => { export default async (): Promise<Array<Application>> => {
const { data } = await network({ method: 'GET', url: GET_APPLICATIONS }) const { data } = await network({ method: 'GET', url: GET_APPLICATIONS })
return data.length > 0 ? data : [] return data.length > 0 ? data : []
} }

5
src/helpers/apps/listCategories.js

@ -2,8 +2,9 @@
import network from 'api/network' import network from 'api/network'
import { GET_CATEGORIES } from 'helpers/urls' import { GET_CATEGORIES } from 'helpers/urls'
import type { Category } from 'helpers/types'
export default async () => { export default async (): Promise<Array<Category>> => {
const { data } = await network({ method: 'GET', url: GET_CATEGORIES }) const { data }: { data: Array<Category> } = await network({ method: 'GET', url: GET_CATEGORIES })
return data.length > 0 ? data : [] return data.length > 0 ? data : []
} }

18
src/helpers/apps/uninstallApp.js

@ -1,15 +1,11 @@
// @flow // @flow
import qs from 'qs'
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { BASE_SOCKET_URL } from 'config/constants'
import { createDeviceSocket } from 'helpers/socket' import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/types' import type { ApplicationVersion } from 'helpers/types'
import { createCustomErrorClass } from '../errors' import { ManagerDeviceLockedError, ManagerUninstallBTCDep } from 'config/errors'
import { WS_INSTALL } from 'helpers/urls'
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked')
const ManagerUninstallBTCDep = createCustomErrorClass('ManagerUninstallBTCDep')
function remapError(promise) { function remapError(promise) {
return promise.catch((e: Error) => { return promise.catch((e: Error) => {
@ -30,8 +26,8 @@ function remapError(promise) {
export default async function uninstallApp( export default async function uninstallApp(
transport: Transport<*>, transport: Transport<*>,
targetId: string | number, targetId: string | number,
{ app }: { app: LedgerScriptParams }, { app }: { app: ApplicationVersion },
): Promise<*> { ): Promise<void> {
const params = { const params = {
targetId, targetId,
perso: app.perso, perso: app.perso,
@ -40,6 +36,6 @@ export default async function uninstallApp(
firmwareKey: app.delete_key, firmwareKey: app.delete_key,
hash: app.hash, hash: app.hash,
} }
const url = `${BASE_SOCKET_URL}/install?${qs.stringify(params)}` const url = WS_INSTALL(params)
return remapError(createDeviceSocket(transport, url).toPromise()) await remapError(createDeviceSocket(transport, url).toPromise())
} }

3
src/helpers/debugAppInfosForCurrency/btc.js

@ -1,9 +1,6 @@
// @flow // @flow
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { createCustomErrorClass } from '../errors'
export const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp')
export default async (transport: Transport<*>) => { export default async (transport: Transport<*>) => {
const r = await transport.send(0xe0, 0xc4, 0, 0) const r = await transport.send(0xe0, 0xc4, 0, 0)

5
src/helpers/devices/getCurrentFirmware.js

@ -2,6 +2,7 @@
import network from 'api/network' import network from 'api/network'
import { GET_CURRENT_FIRMWARE } from 'helpers/urls' import { GET_CURRENT_FIRMWARE } from 'helpers/urls'
import type { FinalFirmware } from 'helpers/types'
type Input = { type Input = {
fullVersion: string, fullVersion: string,
@ -9,8 +10,8 @@ type Input = {
provider: number, provider: number,
} }
export default async (input: Input): Promise<*> => { export default async (input: Input): Promise<FinalFirmware> => {
const { data } = await network({ const { data }: { data: FinalFirmware } = await network({
method: 'POST', method: 'POST',
url: GET_CURRENT_FIRMWARE, url: GET_CURRENT_FIRMWARE,
data: { data: {

12
src/helpers/devices/getDeviceInfo.js

@ -5,17 +5,7 @@ import type Transport from '@ledgerhq/hw-transport'
import getFirmwareInfo from 'helpers/firmware/getFirmwareInfo' import getFirmwareInfo from 'helpers/firmware/getFirmwareInfo'
import { FORCE_PROVIDER } from 'config/constants' import { FORCE_PROVIDER } from 'config/constants'
export type DeviceInfo = { import type { DeviceInfo } from 'helpers/types'
targetId: string | number,
seVersion: string,
isBootloader: boolean,
flags: string,
mcuVersion: string,
isOSU: boolean,
providerName: string,
providerId: number,
fullVersion: string,
}
const PROVIDERS = { const PROVIDERS = {
'': 1, '': 1,

6
src/helpers/devices/getDeviceVersion.js

@ -2,8 +2,10 @@
import { GET_DEVICE_VERSION } from 'helpers/urls' import { GET_DEVICE_VERSION } from 'helpers/urls'
import network from 'api/network' import network from 'api/network'
export default async (targetId: string | number, provider: number): Promise<*> => { import type { DeviceVersion } from 'helpers/types'
const { data } = await network({
export default async (targetId: string | number, provider: number): Promise<DeviceVersion> => {
const { data }: { data: DeviceVersion } = await network({
method: 'POST', method: 'POST',
url: GET_DEVICE_VERSION, url: GET_DEVICE_VERSION,
data: { data: {

12
src/helpers/devices/getIsGenuine.js

@ -2,23 +2,29 @@
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { SKIP_GENUINE } from 'config/constants' import { SKIP_GENUINE } from 'config/constants'
import { WS_GENUINE } from 'helpers/urls' import { WS_GENUINE } from 'helpers/urls'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo, FinalFirmware, DeviceVersion } from 'helpers/types'
import { createDeviceSocket } from 'helpers/socket' import { createDeviceSocket } from 'helpers/socket'
import getCurrentFirmware from './getCurrentFirmware' import getCurrentFirmware from './getCurrentFirmware'
import getDeviceVersion from './getDeviceVersion' import getDeviceVersion from './getDeviceVersion'
export default async (transport: Transport<*>, deviceInfo: DeviceInfo): Promise<string> => { export default async (transport: Transport<*>, deviceInfo: DeviceInfo): Promise<string> => {
const deviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) const deviceVersion: DeviceVersion = await getDeviceVersion(
const firmware = await getCurrentFirmware({ deviceInfo.targetId,
deviceInfo.providerId,
)
const firmware: FinalFirmware = await getCurrentFirmware({
deviceId: deviceVersion.id, deviceId: deviceVersion.id,
fullVersion: deviceInfo.fullVersion, fullVersion: deviceInfo.fullVersion,
provider: deviceInfo.providerId, provider: deviceInfo.providerId,
}) })
const params = { const params = {
targetId: deviceInfo.targetId, targetId: deviceInfo.targetId,
perso: firmware.perso, perso: firmware.perso,
} }
const url = WS_GENUINE(params) const url = WS_GENUINE(params)
return SKIP_GENUINE return SKIP_GENUINE
? new Promise(resolve => setTimeout(() => resolve('0000'), 1000)) ? new Promise(resolve => setTimeout(() => resolve('0000'), 1000))

36
src/helpers/devices/getLatestFirmwareForDevice.js

@ -1,7 +1,13 @@
// @flow // @flow
import network from 'api/network' import network from 'api/network'
import { GET_LATEST_FIRMWARE } from 'helpers/urls' import { GET_LATEST_FIRMWARE } from 'helpers/urls'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type {
DeviceInfo,
DeviceVersion,
FinalFirmware,
OsuFirmware,
McuVersion,
} from 'helpers/types'
import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById' import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById'
import getMcus from 'helpers/firmware/getMcus' import getMcus from 'helpers/firmware/getMcus'
@ -9,19 +15,31 @@ import getMcus from 'helpers/firmware/getMcus'
import getCurrentFirmware from './getCurrentFirmware' import getCurrentFirmware from './getCurrentFirmware'
import getDeviceVersion from './getDeviceVersion' import getDeviceVersion from './getDeviceVersion'
export default async (deviceInfo: DeviceInfo) => { type NetworkResponse = {
data: {
result: string,
se_firmware_osu_version: OsuFirmware,
},
}
type Result = ?(OsuFirmware & { shouldFlashMcu: boolean })
export default async (deviceInfo: DeviceInfo): Promise<Result> => {
// Get device infos from targetId // Get device infos from targetId
const deviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) const deviceVersion: DeviceVersion = await getDeviceVersion(
deviceInfo.targetId,
deviceInfo.providerId,
)
// Get firmware infos with firmware name and device version // Get firmware infos with firmware name and device version
const seFirmwareVersion = await getCurrentFirmware({ const seFirmwareVersion: FinalFirmware = await getCurrentFirmware({
fullVersion: deviceInfo.fullVersion, fullVersion: deviceInfo.fullVersion,
deviceId: deviceVersion.id, deviceId: deviceVersion.id,
provider: deviceInfo.providerId, provider: deviceInfo.providerId,
}) })
// Fetch next possible firmware // Fetch next possible firmware
const { data } = await network({ const { data }: NetworkResponse = await network({
method: 'POST', method: 'POST',
url: GET_LATEST_FIRMWARE, url: GET_LATEST_FIRMWARE,
data: { data: {
@ -37,11 +55,13 @@ export default async (deviceInfo: DeviceInfo) => {
const { se_firmware_osu_version } = data const { se_firmware_osu_version } = data
const { next_se_firmware_final_version } = se_firmware_osu_version const { next_se_firmware_final_version } = se_firmware_osu_version
const seFirmwareFinalVersion = await getFinalFirmwareById(next_se_firmware_final_version) const seFirmwareFinalVersion: FinalFirmware = await getFinalFirmwareById(
next_se_firmware_final_version,
)
const mcus = await getMcus() const mcus: Array<McuVersion> = await getMcus()
const currentMcuVersionId = mcus const currentMcuVersionId: Array<number> = mcus
.filter(mcu => mcu.name === deviceInfo.mcuVersion) .filter(mcu => mcu.name === deviceInfo.mcuVersion)
.map(mcu => mcu.id) .map(mcu => mcu.id)

2
src/helpers/devices/shouldFlashMcu.js

@ -1,7 +1,7 @@
// @flow // @flow
import network from 'api/network' import network from 'api/network'
import { GET_LATEST_FIRMWARE } from 'helpers/urls' import { GET_LATEST_FIRMWARE } from 'helpers/urls'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo } from 'helpers/types'
import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById' import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById'
import getMcus from 'helpers/firmware/getMcus' import getMcus from 'helpers/firmware/getMcus'

3
src/helpers/firmware/getFirmwareInfo.js

@ -1,6 +1,7 @@
// @flow // @flow
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import type { FirmwareInfo } from 'helpers/types'
const APDUS = { const APDUS = {
GET_FIRMWARE: [0xe0, 0x01, 0x00, 0x00], GET_FIRMWARE: [0xe0, 0x01, 0x00, 0x00],
@ -12,7 +13,7 @@ const APDUS = {
/** /**
* Retrieve targetId and firmware version from device * Retrieve targetId and firmware version from device
*/ */
export default async function getFirmwareInfo(transport: Transport<*>) { export default async function getFirmwareInfo(transport: Transport<*>): Promise<FirmwareInfo> {
const res = await transport.send(...APDUS.GET_FIRMWARE) const res = await transport.send(...APDUS.GET_FIRMWARE)
const byteArray = [...res] const byteArray = [...res]
const data = byteArray.slice(0, byteArray.length - 2) const data = byteArray.slice(0, byteArray.length - 2)

7
src/helpers/firmware/getNextMCU.js

@ -2,12 +2,13 @@
import network from 'api/network' import network from 'api/network'
import { GET_NEXT_MCU } from 'helpers/urls' import { GET_NEXT_MCU } from 'helpers/urls'
import { createCustomErrorClass } from 'helpers/errors' import type { OsuFirmware } from 'helpers/types'
import { LatestMCUInstalledError } from 'config/errors'
const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError') type NetworkResponse = { data: OsuFirmware | 'default' }
export default async (bootloaderVersion: string): Promise<*> => { export default async (bootloaderVersion: string): Promise<*> => {
const { data } = await network({ const { data }: NetworkResponse = await network({
method: 'POST', method: 'POST',
url: GET_NEXT_MCU, url: GET_NEXT_MCU,
data: { data: {

15
src/helpers/firmware/installFinalFirmware.js

@ -1,16 +1,15 @@
// @flow // @flow
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import type { DeviceInfo, DeviceVersion, OsuFirmware, FinalFirmware } from 'helpers/types'
import { WS_INSTALL } from 'helpers/urls' import { WS_INSTALL } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket' import { createDeviceSocket } from 'helpers/socket'
import { createCustomErrorClass } from 'helpers/errors'
import getDeviceVersion from 'helpers/devices/getDeviceVersion' import getDeviceVersion from 'helpers/devices/getDeviceVersion'
import getOsuFirmware from 'helpers/devices/getOsuFirmware' import getOsuFirmware from 'helpers/devices/getOsuFirmware'
import getDeviceInfo from 'helpers/devices/getDeviceInfo' import getDeviceInfo from 'helpers/devices/getDeviceInfo'
import getFinalFirmwareById from './getFinalFirmwareById' import { ManagerDeviceLockedError } from 'config/errors'
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') import getFinalFirmwareById from './getFinalFirmwareById'
function remapSocketError(promise) { function remapSocketError(promise) {
return promise.catch((e: Error) => { return promise.catch((e: Error) => {
@ -23,19 +22,19 @@ function remapSocketError(promise) {
}) })
} }
type Result = Promise<{ success: boolean, error?: string }> type Result = Promise<{ success: boolean }>
export default async (transport: Transport<*>): Result => { export default async (transport: Transport<*>): Result => {
try { try {
const deviceInfo: DeviceInfo = await getDeviceInfo(transport) const deviceInfo: DeviceInfo = await getDeviceInfo(transport)
const device = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) const device: DeviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId)
const firmware = await getOsuFirmware({ const firmware: OsuFirmware = await getOsuFirmware({
deviceId: device.id, deviceId: device.id,
version: deviceInfo.fullVersion, version: deviceInfo.fullVersion,
provider: deviceInfo.providerId, provider: deviceInfo.providerId,
}) })
const { next_se_firmware_final_version } = firmware const { next_se_firmware_final_version } = firmware
const nextFirmware = await getFinalFirmwareById(next_se_firmware_final_version) const nextFirmware: FinalFirmware = await getFinalFirmwareById(next_se_firmware_final_version)
const params = { const params = {
targetId: deviceInfo.targetId, targetId: deviceInfo.targetId,

11
src/helpers/firmware/installMcu.js

@ -5,9 +5,9 @@ import { WS_MCU } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket' import { createDeviceSocket } from 'helpers/socket'
import getNextMCU from 'helpers/firmware/getNextMCU' import getNextMCU from 'helpers/firmware/getNextMCU'
import getDeviceInfo from 'helpers/devices/getDeviceInfo' import getDeviceInfo from 'helpers/devices/getDeviceInfo'
import { createCustomErrorClass } from 'helpers/errors' import { ManagerDeviceLockedError } from 'config/errors'
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') import type { DeviceInfo } from 'helpers/types'
function remapSocketError(promise) { function remapSocketError(promise) {
return promise.catch((e: Error) => { return promise.catch((e: Error) => {
@ -20,16 +20,15 @@ function remapSocketError(promise) {
}) })
} }
type Result = Promise<*> type Result = Promise<void>
export default async (transport: Transport<*>): Result => { export default async (transport: Transport<*>): Result => {
const deviceInfo = await getDeviceInfo(transport) const { seVersion: version, targetId }: DeviceInfo = await getDeviceInfo(transport)
const { seVersion: version, targetId } = deviceInfo
const nextVersion = await getNextMCU(version) const nextVersion = await getNextMCU(version)
const params = { const params = {
targetId, targetId,
version: nextVersion.name, version: nextVersion.name,
} }
const url = WS_MCU(params) const url = WS_MCU(params)
return remapSocketError(createDeviceSocket(transport, url).toPromise()) await remapSocketError(createDeviceSocket(transport, url).toPromise())
} }

12
src/helpers/firmware/installOsuFirmware.js

@ -6,11 +6,11 @@ import { createDeviceSocket } from 'helpers/socket'
import type { Firmware } from 'components/modals/UpdateFirmware' import type { Firmware } from 'components/modals/UpdateFirmware'
import { createCustomErrorClass } from '../errors' import {
ManagerNotEnoughSpaceError,
const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace') ManagerDeviceLockedError,
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') UserRefusedFirmwareUpdate,
const UserRefusedFirmwareUpdate = createCustomErrorClass('UserRefusedFirmwareUpdate') } from 'config/errors'
function remapError(promise) { function remapError(promise) {
return promise.catch((e: Error) => { return promise.catch((e: Error) => {
@ -27,7 +27,7 @@ function remapError(promise) {
}) })
} }
type Result = Promise<{ success: boolean, error?: any }> type Result = Promise<{ success: boolean }>
export default async ( export default async (
transport: Transport<*>, transport: Transport<*>,

4
src/helpers/getAddressForCurrency/btc.js

@ -3,10 +3,8 @@
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import Btc from '@ledgerhq/hw-app-btc' import Btc from '@ledgerhq/hw-app-btc'
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { BtcUnmatchedApp } from 'config/errors'
import getBitcoinLikeInfo from '../devices/getBitcoinLikeInfo' import getBitcoinLikeInfo from '../devices/getBitcoinLikeInfo'
import { createCustomErrorClass } from '../errors'
export const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp')
export default async ( export default async (
transport: Transport<*>, transport: Transport<*>,

13
src/helpers/hardReset.js

@ -1,13 +0,0 @@
import libcoreHardReset from 'commands/libcoreHardReset'
import { disable as disableDBMiddleware } from 'middlewares/db'
import db from 'helpers/db'
import { delay } from 'helpers/promise'
export default async function hardReset() {
await libcoreHardReset.send()
disableDBMiddleware()
db.resetAll()
await delay(500)
window.location.href = ''
}

9
src/helpers/libcore.js

@ -14,12 +14,11 @@ import type { NJSAccount, NJSOperation } from '@ledgerhq/ledger-core/src/ledgerc
import { isSegwitPath, isUnsplitPath } from 'helpers/bip32' import { isSegwitPath, isUnsplitPath } from 'helpers/bip32'
import * as accountIdHelper from 'helpers/accountId' import * as accountIdHelper from 'helpers/accountId'
import { createCustomErrorClass, deserializeError } from './errors' import { NoAddressesFound } from 'config/errors'
import { deserializeError } from './errors'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName' import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName'
import { timeoutTagged } from './promise' import { timeoutTagged } from './promise'
const NoAddressesFound = createCustomErrorClass('NoAddressesFound')
// TODO: put that info inside currency itself // TODO: put that info inside currency itself
const SPLITTED_CURRENCIES = { const SPLITTED_CURRENCIES = {
bitcoin_cash: { bitcoin_cash: {
@ -272,7 +271,7 @@ async function scanNextAccount(props: {
const shouldSyncAccount = true // TODO: let's sync everytime. maybe in the future we can optimize. const shouldSyncAccount = true // TODO: let's sync everytime. maybe in the future we can optimize.
if (shouldSyncAccount) { if (shouldSyncAccount) {
await timeoutTagged('coreSyncAccount', 30000, coreSyncAccount(core, njsAccount)) await coreSyncAccount(core, njsAccount)
} }
if (isUnsubscribed()) return [] if (isUnsubscribed()) return []
@ -550,7 +549,7 @@ export async function syncAccount({
) )
} }
const unsub = await timeoutTagged('coreSyncAccount', 30000, coreSyncAccount(core, njsAccount)) const unsub = await coreSyncAccount(core, njsAccount)
unsub() unsub()
const query = njsAccount.queryOperations() const query = njsAccount.queryOperations()

35
src/helpers/reset.js

@ -0,0 +1,35 @@
// @flow
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'
function resetLibcoreDatabase() {
const dbpath = path.resolve(resolveUserDataDirectory(), 'sqlite/')
rimraf.sync(dbpath, { glob: false })
}
function reload() {
require('electron')
.remote.getCurrentWindow()
.webContents.reload()
}
export async function hardReset() {
resetLibcoreDatabase()
disableDBMiddleware()
db.resetAll()
await delay(500)
reload()
}
export async function softReset({ cleanAccountsCache }: *) {
resetLibcoreDatabase()
cleanAccountsCache()
await delay(500)
db.cleanCache()
reload()
}

14
src/helpers/socket.js

@ -5,13 +5,13 @@ import logger from 'logger'
import Websocket from 'ws' import Websocket from 'ws'
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { Observable } from 'rxjs' import { Observable } from 'rxjs'
import { createCustomErrorClass } from './errors' import {
WebsocketConnectionError,
const WebsocketConnectionError = createCustomErrorClass('WebsocketConnectionError') WebsocketConnectionFailed,
const WebsocketConnectionFailed = createCustomErrorClass('WebsocketConnectionFailed') DeviceSocketFail,
const DeviceSocketFail = createCustomErrorClass('DeviceSocketFail') DeviceSocketNoBulkStatus,
const DeviceSocketNoBulkStatus = createCustomErrorClass('DeviceSocketNoBulkStatus') DeviceSocketNoHandler,
const DeviceSocketNoHandler = createCustomErrorClass('DeviceSocketNoHandler') } from 'config/errors'
/** /**
* use Ledger WebSocket API to exchange data with the device * use Ledger WebSocket API to exchange data with the device

132
src/helpers/types.js

@ -1,14 +1,134 @@
// @flow // @flow
type Id = number
export type LedgerScriptParams = { export type LedgerScriptParams = {
firmware?: string, firmware: string,
firmware_key?: string, firmwareKey: string,
delete?: string, delete?: string,
delete_key?: string, deleteKey?: string,
targetId?: string | number, targetId?: string | number,
hash: string,
perso: string,
}
export type DeviceInfo = {
targetId: string | number,
seVersion: string,
isBootloader: boolean,
flags: string,
mcuVersion: string,
isOSU: boolean,
providerName: string,
providerId: number,
fullVersion: string,
}
export type DeviceVersion = {
id: Id,
name: string,
display_name: string,
target_id: string,
description: string,
device: Id,
providers: Array<Id>,
mcu_versions: Array<Id>,
se_firmware_final_versions: Array<Id>,
osu_versions: Array<Id>,
application_versions: Array<Id>,
date_creation: string,
date_last_modified: string,
}
export type McuVersion = {
id: Id,
mcu: Id,
name: string,
description: ?string,
providers: Array<Id>,
from_bootloader_version: string,
device_versions: Array<Id>,
se_firmware_final_versions: Array<Id>,
date_creation: string,
date_last_modified: string,
}
export type FirmwareInfo = {
targetId: Id,
seVersion: string,
flags: string,
mcuVersion: string,
}
type BaseFirmware = {
id: Id,
name: string,
description: ?string,
display_name: ?string,
notes: ?string,
perso: string,
firmware: string,
firmware_key: string,
hash: string,
date_creation: string,
date_last_modified: string,
device_versions: Array<Id>,
providers: Array<Id>,
}
export type OsuFirmware = BaseFirmware & {
next_se_firmware_final_version: Id,
previous_se_firmware_final_version: Array<Id>,
}
export type FinalFirmware = BaseFirmware & {
version: string,
se_firmware: Id,
osu_versions: Array<OsuFirmware>,
mcu_versions: Array<Id>,
application_versions: Array<Id>,
}
export type ApplicationVersion = {
id: Id,
name: string, name: string,
version: string, version: string,
app: Id,
description: ?string,
display_name: string,
icon: string, icon: string,
app?: number, picture: Id,
hash?: string, notes: ?string,
perso?: string, perso: string,
hash: string,
firmware: string,
firmware_key: string,
delete: string,
delete_key: string,
device_versions: Array<Id>,
se_firmware_final_versions: Array<Id>,
providers: Array<Id>,
date_creation: string,
date_last_modified: string,
}
export type Application = {
id: Id,
name: string,
description: ?string,
application_versions: Array<ApplicationVersion>,
providers: Array<Id>,
category: Id,
publisher: ?Id,
date_creation: string,
date_last_modified: string,
}
export type Category = {
id: Id,
name: string,
description: ?string,
providers: Array<Id>,
applications: Array<Id>,
date_creation: string,
date_last_modified: string,
} }

4
static/i18n/en/errors.json

@ -72,8 +72,8 @@
"description": "Check your device to see which apps are already installed." "description": "Check your device to see which apps are already installed."
}, },
"ManagerAppRelyOnBTC": { "ManagerAppRelyOnBTC": {
"title": "Bitcoin or Ethereum app required", "title": "Bitcoin and Ethereum apps required",
"description": "Either install the latest Ethereum app (for ETC/UBIQ/EXP/RSK/WAN/kUSD/POA), or the latest Bitcoin app." "description": "Install the latest Bitcoin and Ethereum apps first."
}, },
"ManagerDeviceLocked": { "ManagerDeviceLocked": {
"title": "Please unlock your device", "title": "Please unlock your device",

64
test-e2e/nav_to_settings.spec.js

@ -0,0 +1,64 @@
const Application = require('spectron').Application
let app
const TIMEOUT = 50 * 1000
describe('Application launch', () => {
beforeEach(async () => {
app = new Application({
path: './dist/ledger-live-desktop-1.1.0-linux-x86_64.AppImage',
env: {
SKIP_ONBOARDING: '1',
},
})
await app.start()
}, TIMEOUT)
afterEach(async () => {
if (app && app.isRunning()) {
await app.stop()
}
}, TIMEOUT)
test(
'Start app and set developper mode ',
async () => {
const title = await app.client.getTitle()
expect(title).toEqual('Ledger Live')
await app.client.waitUntilWindowLoaded()
await app.client.pause(2000)
// Post Onboarding
const title_onboarding = await app.client.getText('[data-e2e=onboarding_title]')
expect(title_onboarding).toEqual('Analytics and bug reports')
await app.client.click('[data-e2e=continue_button]')
await app.client.pause(1000)
const title_finish = await app.client.getText('[data-e2e=finish_title]')
expect(title_finish).toEqual('Your device is ready!')
await app.client.click('[data-e2e=continue_button]')
await app.client.pause(1000)
const title_disclaimer = await app.client.getText('[data-e2e=disclaimer_title]')
expect(title_disclaimer).toEqual('Trade safely')
await app.client.click('[data-e2e=continue_button]')
await app.client.pause(1000)
// Dashboard EmptyState
const title_dashboard_empty = await app.client.getText('[data-e2e=dashboard_empty_title]')
expect(title_dashboard_empty).toEqual('Add accounts to your portfolio')
// Open Settings
await app.client.click('[data-e2e=setting_button]')
await app.client.pause(1000)
const title_settings = await app.client.getText('[data-e2e=settings_title]')
expect(title_settings).toEqual('Settings')
// DevMode ON
await app.client.click('[data-e2e=devMode_button]')
await app.client.pause(500)
},
TIMEOUT,
)
})

306
yarn.lock

@ -1474,6 +1474,13 @@
version "0.7.1" version "0.7.1"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.7.1.tgz#e44e596d03c9f16ba3b127ad333a8a072bcb5a0a" resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.7.1.tgz#e44e596d03c9f16ba3b127ad333a8a072bcb5a0a"
"@gimenete/type-writer@^0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@gimenete/type-writer/-/type-writer-0.1.3.tgz#2d4f26118b18d71f5b34ca24fdd6d1fd455c05b6"
dependencies:
camelcase "^5.0.0"
prettier "^1.13.7"
"@ledgerhq/hw-app-btc@4.21.0": "@ledgerhq/hw-app-btc@4.21.0":
version "4.21.0" version "4.21.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-btc/-/hw-app-btc-4.21.0.tgz#4f94571bb3d63cd785e31a7e1f77ce597c344516" resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-btc/-/hw-app-btc-4.21.0.tgz#4f94571bb3d63cd785e31a7e1f77ce597c344516"
@ -1542,9 +1549,9 @@
npm "^5.7.1" npm "^5.7.1"
prebuild-install "^2.2.2" prebuild-install "^2.2.2"
"@ledgerhq/live-common@3.0.2": "@ledgerhq/live-common@^3.3.0":
version "3.0.2" version "3.3.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-3.0.2.tgz#1ee5fcc6044c5a049c067978d81892f79789863c" resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-3.3.0.tgz#e4e798f5bfee8e788094fab8dc11fe957a750544"
dependencies: dependencies:
axios "^0.18.0" axios "^0.18.0"
bignumber.js "^7.2.1" bignumber.js "^7.2.1"
@ -1568,6 +1575,20 @@
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a"
"@octokit/rest@^15.10.0":
version "15.10.0"
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-15.10.0.tgz#9baf7430e55edf1a1024c35ae72ed2f5fc6e90e9"
dependencies:
"@gimenete/type-writer" "^0.1.3"
before-after-hook "^1.1.0"
btoa-lite "^1.0.0"
debug "^3.1.0"
http-proxy-agent "^2.1.0"
https-proxy-agent "^2.2.0"
lodash "^4.17.4"
node-fetch "^2.1.1"
url-template "^2.0.8"
"@posthtml/esm@^1.0.0": "@posthtml/esm@^1.0.0":
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/@posthtml/esm/-/esm-1.0.0.tgz#09bcb28a02438dcee22ad1970ca1d85a000ae0cf" resolved "https://registry.yarnpkg.com/@posthtml/esm/-/esm-1.0.0.tgz#09bcb28a02438dcee22ad1970ca1d85a000ae0cf"
@ -2213,6 +2234,30 @@ aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2, aproba@~1.2.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
archiver-utils@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174"
dependencies:
glob "^7.0.0"
graceful-fs "^4.1.0"
lazystream "^1.0.0"
lodash "^4.8.0"
normalize-path "^2.0.0"
readable-stream "^2.0.0"
archiver@~2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/archiver/-/archiver-2.1.1.tgz#ff662b4a78201494a3ee544d3a33fe7496509ebc"
dependencies:
archiver-utils "^1.3.0"
async "^2.0.0"
buffer-crc32 "^0.2.1"
glob "^7.0.0"
lodash "^4.8.0"
readable-stream "^2.0.0"
tar-stream "^1.5.0"
zip-stream "^1.2.0"
archy@~1.0.0: archy@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
@ -2414,7 +2459,7 @@ async@^1.4.0, async@^1.5.0, async@^1.5.2:
version "1.5.2" version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@^2.1.2, async@^2.1.4, async@^2.6.0, async@^2.6.1: async@^2.0.0, async@^2.1.2, async@^2.1.4, async@^2.6.0, async@^2.6.1:
version "2.6.1" version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
dependencies: dependencies:
@ -3560,6 +3605,10 @@ bech32@^1.1.2:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.3.tgz#bd47a8986bbb3eec34a56a097a84b8d3e9a2dfcd" resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.3.tgz#bd47a8986bbb3eec34a56a097a84b8d3e9a2dfcd"
before-after-hook@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.1.0.tgz#83165e15a59460d13702cb8febd6a1807896db5a"
bfj-node4@^5.2.0: bfj-node4@^5.2.0:
version "5.3.1" version "5.3.1"
resolved "https://registry.yarnpkg.com/bfj-node4/-/bfj-node4-5.3.1.tgz#e23d8b27057f1d0214fc561142ad9db998f26830" resolved "https://registry.yarnpkg.com/bfj-node4/-/bfj-node4-5.3.1.tgz#e23d8b27057f1d0214fc561142ad9db998f26830"
@ -3878,6 +3927,10 @@ bser@^2.0.0:
dependencies: dependencies:
node-int64 "^0.4.0" node-int64 "^0.4.0"
btoa-lite@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337"
buffer-alloc-unsafe@^1.1.0: buffer-alloc-unsafe@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
@ -3889,6 +3942,10 @@ buffer-alloc@^1.1.0:
buffer-alloc-unsafe "^1.1.0" buffer-alloc-unsafe "^1.1.0"
buffer-fill "^1.0.0" buffer-fill "^1.0.0"
buffer-crc32@^0.2.1:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
buffer-fill@^1.0.0: buffer-fill@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
@ -3928,6 +3985,13 @@ buffer@^5.0.3:
base64-js "^1.0.2" base64-js "^1.0.2"
ieee754 "^1.1.4" ieee754 "^1.1.4"
buffer@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.0.tgz#53cf98241100099e9eeae20ee6d51d21b16e541e"
dependencies:
base64-js "^1.0.2"
ieee754 "^1.1.4"
buffers@~0.1.1: buffers@~0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb"
@ -4127,6 +4191,10 @@ camelcase@^4.0.0, camelcase@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
camelcase@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
can-promise@^0.0.1: can-promise@^0.0.1:
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/can-promise/-/can-promise-0.0.1.tgz#7a7597ad801fb14c8b22341dfec314b6bd6ad8d3" resolved "https://registry.yarnpkg.com/can-promise/-/can-promise-0.0.1.tgz#7a7597ad801fb14c8b22341dfec314b6bd6ad8d3"
@ -4612,6 +4680,15 @@ component-emitter@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
compress-commons@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f"
dependencies:
buffer-crc32 "^0.2.1"
crc32-stream "^2.0.0"
normalize-path "^2.0.0"
readable-stream "^2.0.0"
compressible@~2.0.13: compressible@~2.0.13:
version "2.0.14" version "2.0.14"
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7"
@ -4774,6 +4851,19 @@ cosmiconfig@^4.0.0:
parse-json "^4.0.0" parse-json "^4.0.0"
require-from-string "^2.0.1" require-from-string "^2.0.1"
crc32-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4"
dependencies:
crc "^3.4.4"
readable-stream "^2.0.0"
crc@^3.4.4:
version "3.8.0"
resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
dependencies:
buffer "^5.1.0"
create-ecdh@^4.0.0: create-ecdh@^4.0.0:
version "4.0.3" version "4.0.3"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
@ -4935,6 +5025,12 @@ css-loader@^0.28.11:
postcss-value-parser "^3.3.0" postcss-value-parser "^3.3.0"
source-list-map "^2.0.0" source-list-map "^2.0.0"
css-parse@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4"
dependencies:
css "^2.0.0"
css-select-base-adapter@~0.1.0: css-select-base-adapter@~0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz#0102b3d14630df86c3eb9fa9f5456270106cf990" resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz#0102b3d14630df86c3eb9fa9f5456270106cf990"
@ -4991,10 +5087,23 @@ css-url-regex@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec" resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec"
css-value@~0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea"
css-what@2.1: css-what@2.1:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd"
css@^2.0.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/css/-/css-2.2.3.tgz#f861f4ba61e79bedc962aa548e5780fd95cbc6be"
dependencies:
inherits "^2.0.1"
source-map "^0.1.38"
source-map-resolve "^0.5.1"
urix "^0.1.0"
cssesc@^0.1.0: cssesc@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@ -5383,6 +5492,10 @@ deep-is@~0.1.3:
version "0.1.3" version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
deepmerge@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.0.1.tgz#25c1c24f110fb914f80001b925264dd77f3f4312"
default-require-extensions@^2.0.0: default-require-extensions@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7"
@ -5508,6 +5621,10 @@ detect-port-alt@1.1.6:
address "^1.0.1" address "^1.0.1"
debug "^2.6.0" debug "^2.6.0"
dev-null@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dev-null/-/dev-null-0.1.1.tgz#5a205ce3c2b2ef77b6238d6ba179eb74c6a0e818"
dezalgo@^1.0.0, dezalgo@~1.0.3: dezalgo@^1.0.0, dezalgo@~1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
@ -5754,6 +5871,10 @@ ejs@^2.5.7, ejs@^2.5.9, ejs@^2.6.1:
version "2.6.1" version "2.6.1"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0"
ejs@~2.5.6:
version "2.5.9"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5"
electron-builder-lib@20.14.7, electron-builder-lib@~20.14.6: electron-builder-lib@20.14.7, electron-builder-lib@~20.14.6:
version "20.14.7" version "20.14.7"
resolved "https://registry.yarnpkg.com/electron-builder-lib/-/electron-builder-lib-20.14.7.tgz#db91977dd13b0a288e1da5629183807a9847de21" resolved "https://registry.yarnpkg.com/electron-builder-lib/-/electron-builder-lib-20.14.7.tgz#db91977dd13b0a288e1da5629183807a9847de21"
@ -5803,6 +5924,13 @@ electron-builder@20.14.7:
update-notifier "^2.5.0" update-notifier "^2.5.0"
yargs "^11.0.0" yargs "^11.0.0"
electron-chromedriver@~1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-1.8.0.tgz#901714133cf6f6093d365e1f44a52d99624d8241"
dependencies:
electron-download "^4.1.0"
extract-zip "^1.6.5"
electron-context-menu@^0.10.0: electron-context-menu@^0.10.0:
version "0.10.0" version "0.10.0"
resolved "https://registry.yarnpkg.com/electron-context-menu/-/electron-context-menu-0.10.0.tgz#97fce2b805e03ac2b1dae11eb6a68b064b78d633" resolved "https://registry.yarnpkg.com/electron-context-menu/-/electron-context-menu-0.10.0.tgz#97fce2b805e03ac2b1dae11eb6a68b064b78d633"
@ -5855,6 +5983,20 @@ electron-download@^3.0.1:
semver "^5.3.0" semver "^5.3.0"
sumchecker "^1.2.0" sumchecker "^1.2.0"
electron-download@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845"
dependencies:
debug "^2.2.0"
env-paths "^1.0.0"
fs-extra "^2.0.0"
minimist "^1.2.0"
nugget "^2.0.0"
path-exists "^3.0.0"
rc "^1.1.2"
semver "^5.3.0"
sumchecker "^2.0.1"
electron-is-dev@^0.3.0: electron-is-dev@^0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-0.3.0.tgz#14e6fda5c68e9e4ecbeff9ccf037cbd7c05c5afe" resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-0.3.0.tgz#14e6fda5c68e9e4ecbeff9ccf037cbd7c05c5afe"
@ -5963,9 +6105,9 @@ electron-webpack@^2.1.0:
webpack-merge "^4.1.2" webpack-merge "^4.1.2"
yargs "^11.1.0" yargs "^11.1.0"
electron@1.8.7: electron@1.8.8:
version "1.8.7" version "1.8.8"
resolved "https://registry.yarnpkg.com/electron/-/electron-1.8.7.tgz#373c1dc4589d7ab4acd49aff8db4a1c0a6c3bcc1" resolved "https://registry.yarnpkg.com/electron/-/electron-1.8.8.tgz#a90cddb075291f49576993e6f5c8bb4439301cae"
dependencies: dependencies:
"@types/node" "^8.0.24" "@types/node" "^8.0.24"
electron-download "^3.0.1" electron-download "^3.0.1"
@ -6632,7 +6774,7 @@ extglob@^2.0.4:
snapdragon "^0.8.1" snapdragon "^0.8.1"
to-regex "^3.0.1" to-regex "^3.0.1"
extract-zip@^1.0.3: extract-zip@^1.0.3, extract-zip@^1.6.5:
version "1.6.7" version "1.6.7"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
dependencies: dependencies:
@ -6994,6 +7136,13 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
rimraf "^2.2.8" rimraf "^2.2.8"
fs-extra@^2.0.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^2.1.0"
fs-extra@^3.0.1: fs-extra@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291"
@ -7102,6 +7251,12 @@ gauge@~2.7.3:
strip-ansi "^3.0.1" strip-ansi "^3.0.1"
wide-align "^1.1.0" wide-align "^1.1.0"
gaze@~1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
dependencies:
globule "^1.0.0"
genfun@^4.0.1: genfun@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1" resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1"
@ -7222,7 +7377,7 @@ glob-to-regexp@^0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2: glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1, glob@~7.1.2:
version "7.1.2" version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies: dependencies:
@ -7305,6 +7460,14 @@ globby@^8.0.0, globby@^8.0.1:
pify "^3.0.0" pify "^3.0.0"
slash "^1.0.0" slash "^1.0.0"
globule@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
dependencies:
glob "~7.1.1"
lodash "~4.17.10"
minimatch "~3.0.2"
got@^6.7.1: got@^6.7.1:
version "6.7.1" version "6.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@ -7362,7 +7525,7 @@ got@^8.3.1:
url-parse-lax "^3.0.0" url-parse-lax "^3.0.0"
url-to-options "^1.0.1" url-to-options "^1.0.1"
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.11: graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.11:
version "4.1.11" version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@ -7949,7 +8112,7 @@ inline-style-prefixer@^3.0.6:
bowser "^1.7.3" bowser "^1.7.3"
css-in-js-utils "^2.0.0" css-in-js-utils "^2.0.0"
inquirer@3.3.0, inquirer@^3.0.6: inquirer@3.3.0, inquirer@^3.0.6, inquirer@~3.3.0:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
dependencies: dependencies:
@ -9075,6 +9238,12 @@ lazy-val@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc"
lazystream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
dependencies:
readable-stream "^2.0.5"
lcid@^1.0.0: lcid@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
@ -9354,7 +9523,7 @@ lodash@^3.10.1:
version "3.10.1" version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1: lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.8.0, lodash@~4.17.10:
version "4.17.10" version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
@ -9767,7 +9936,7 @@ minimatch@3.0.3:
dependencies: dependencies:
brace-expansion "^1.0.0" brace-expansion "^1.0.0"
minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies: dependencies:
@ -9996,6 +10165,10 @@ node-fetch@^1.0.1:
encoding "^0.1.11" encoding "^0.1.11"
is-stream "^1.0.1" is-stream "^1.0.1"
node-fetch@^2.1.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.2.0.tgz#4ee79bde909262f9775f731e3656d0db55ced5b5"
node-forge@0.7.5: node-forge@0.7.5:
version "0.7.5" version "0.7.5"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
@ -10136,7 +10309,7 @@ normalize-path@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379"
normalize-path@^2.0.1, normalize-path@^2.1.1: normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
dependencies: dependencies:
@ -10184,6 +10357,10 @@ npm-install-checks@~3.0.0:
dependencies: dependencies:
semver "^2.3.0 || 3.x || 4 || 5" semver "^2.3.0 || 3.x || 4 || 5"
npm-install-package@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125"
npm-lifecycle@^2.0.1, npm-lifecycle@^2.0.3: npm-lifecycle@^2.0.1, npm-lifecycle@^2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.0.3.tgz#696bedf1143371163e9cc16fe872357e25d8d90e" resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.0.3.tgz#696bedf1143371163e9cc16fe872357e25d8d90e"
@ -10556,7 +10733,7 @@ opn@^5.1.0:
dependencies: dependencies:
is-wsl "^1.1.0" is-wsl "^1.1.0"
optimist@^0.6.1: optimist@^0.6.1, optimist@~0.6.1:
version "0.6.1" version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
dependencies: dependencies:
@ -11381,6 +11558,10 @@ prettier@^1.12.1, prettier@^1.13.5:
version "1.13.7" version "1.13.7"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281"
prettier@^1.13.7:
version "1.14.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.2.tgz#0ac1c6e1a90baa22a62925f41963c841983282f9"
pretty-bytes@^1.0.2: pretty-bytes@^1.0.2:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84"
@ -11565,7 +11746,7 @@ pushdata-bitcoin@^1.0.1:
dependencies: dependencies:
bitcoin-ops "^1.3.0" bitcoin-ops "^1.3.0"
q@^1.1.2: q@^1.1.2, q@~1.5.0:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
@ -12140,7 +12321,7 @@ read@1, read@~1.0.1, read@~1.0.7:
dependencies: dependencies:
mute-stream "~0.0.4" mute-stream "~0.0.4"
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6:
version "2.3.6" version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
dependencies: dependencies:
@ -12516,7 +12697,7 @@ request-promise-native@^1.0.5:
tunnel-agent "^0.6.0" tunnel-agent "^0.6.0"
uuid "^3.0.0" uuid "^3.0.0"
request@^2.45.0, request@^2.74.0, request@^2.83.0, request@^2.85.0: request@^2.45.0, request@^2.74.0, request@^2.81.0, request@^2.83.0, request@^2.85.0:
version "2.87.0" version "2.87.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e"
dependencies: dependencies:
@ -12647,6 +12828,10 @@ retry@^0.12.0:
version "0.12.0" version "0.12.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
rgb2hex@~0.1.4:
version "0.1.9"
resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.9.tgz#5d3e0e14b0177b568e6f0d5b43e34fbfdb670346"
right-align@^0.1.1: right-align@^0.1.1:
version "0.1.3" version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
@ -13233,7 +13418,7 @@ source-list-map@~0.1.7:
version "0.1.8" version "0.1.8"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
source-map-resolve@^0.5.0: source-map-resolve@^0.5.0, source-map-resolve@^0.5.1:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
dependencies: dependencies:
@ -13268,6 +13453,12 @@ source-map@0.7.3, source-map@^0.7.2:
version "0.7.3" version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
source-map@^0.1.38:
version "0.1.43"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
dependencies:
amdefine ">=0.0.4"
source-map@^0.4.4, source-map@~0.4.1: source-map@^0.4.4, source-map@~0.4.1:
version "0.4.4" version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
@ -13335,6 +13526,16 @@ spdy@^3.4.1:
select-hose "^2.0.0" select-hose "^2.0.0"
spdy-transport "^2.0.18" spdy-transport "^2.0.18"
spectron@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/spectron/-/spectron-3.8.0.tgz#122c3562fd7e92b7cdf6f94094aa495b150dfa51"
dependencies:
dev-null "^0.1.1"
electron-chromedriver "~1.8.0"
request "^2.81.0"
split "^1.0.0"
webdriverio "^4.8.0"
speedometer@~0.1.2: speedometer@~0.1.2:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d"
@ -13345,6 +13546,12 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies: dependencies:
extend-shallow "^3.0.0" extend-shallow "^3.0.0"
split@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
dependencies:
through "2"
sprintf-js@~1.0.2: sprintf-js@~1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
@ -13641,7 +13848,7 @@ sumchecker@^1.2.0:
debug "^2.2.0" debug "^2.2.0"
es6-promise "^4.0.5" es6-promise "^4.0.5"
sumchecker@^2.0.2: sumchecker@^2.0.1, sumchecker@^2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e"
dependencies: dependencies:
@ -13673,6 +13880,12 @@ supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0:
dependencies: dependencies:
has-flag "^3.0.0" has-flag "^3.0.0"
supports-color@~5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.0.1.tgz#1c5331f22250c84202805b2f17adf16699f3a39a"
dependencies:
has-flag "^2.0.0"
svg-tag-names@^1.1.0: svg-tag-names@^1.1.0:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/svg-tag-names/-/svg-tag-names-1.1.1.tgz#9641b29ef71025ee094c7043f7cdde7d99fbd50a" resolved "https://registry.yarnpkg.com/svg-tag-names/-/svg-tag-names-1.1.1.tgz#9641b29ef71025ee094c7043f7cdde7d99fbd50a"
@ -13765,7 +13978,7 @@ tar-fs@^1.13.0:
pump "^1.0.0" pump "^1.0.0"
tar-stream "^1.1.2" tar-stream "^1.1.2"
tar-stream@^1.1.2: tar-stream@^1.1.2, tar-stream@^1.5.0:
version "1.6.1" version "1.6.1"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395"
dependencies: dependencies:
@ -13863,7 +14076,7 @@ through2@~0.2.3:
readable-stream "~1.1.9" readable-stream "~1.1.9"
xtend "~2.1.1" xtend "~2.1.1"
"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, through@~2.3.6: through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, through@~2.3.6:
version "2.3.8" version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@ -14343,11 +14556,15 @@ url-parse@^1.1.8, url-parse@~1.4.0:
querystringify "^2.0.0" querystringify "^2.0.0"
requires-port "^1.0.0" requires-port "^1.0.0"
url-template@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
url-to-options@^1.0.1: url-to-options@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
url@^0.11.0: url@^0.11.0, url@~0.11.0:
version "0.11.0" version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
dependencies: dependencies:
@ -14584,6 +14801,36 @@ wcwidth@^1.0.0:
dependencies: dependencies:
defaults "^1.0.3" defaults "^1.0.3"
wdio-dot-reporter@~0.0.8:
version "0.0.10"
resolved "https://registry.yarnpkg.com/wdio-dot-reporter/-/wdio-dot-reporter-0.0.10.tgz#facfb7c9c5984149951f59cbc3cd0752101cf0e0"
webdriverio@^4.8.0:
version "4.13.1"
resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.13.1.tgz#624ef4ca569f3c9a5e8e9b11302b4431eda1fb8a"
dependencies:
archiver "~2.1.0"
babel-runtime "^6.26.0"
css-parse "^2.0.0"
css-value "~0.0.1"
deepmerge "~2.0.1"
ejs "~2.5.6"
gaze "~1.1.2"
glob "~7.1.1"
inquirer "~3.3.0"
json-stringify-safe "~5.0.1"
mkdirp "~0.5.1"
npm-install-package "~2.1.0"
optimist "~0.6.1"
q "~1.5.0"
request "^2.83.0"
rgb2hex "~0.1.4"
safe-buffer "~5.1.1"
supports-color "~5.0.0"
url "~0.11.0"
wdio-dot-reporter "~0.0.8"
wgxpath "~1.0.0"
webidl-conversions@^4.0.2: webidl-conversions@^4.0.2:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
@ -14810,6 +15057,10 @@ websocket-extensions@>=0.1.1:
version "0.1.3" version "0.1.3"
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
wgxpath@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690"
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3"
@ -15280,6 +15531,15 @@ yeoman-generator@^2.0.5:
through2 "^2.0.0" through2 "^2.0.0"
yeoman-environment "^2.0.5" yeoman-environment "^2.0.5"
zip-stream@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04"
dependencies:
archiver-utils "^1.3.0"
compress-commons "^1.2.0"
lodash "^4.8.0"
readable-stream "^2.0.0"
zxcvbn@^4.4.2: zxcvbn@^4.4.2:
version "4.4.2" version "4.4.2"
resolved "https://registry.yarnpkg.com/zxcvbn/-/zxcvbn-4.4.2.tgz#28ec17cf09743edcab056ddd8b1b06262cc73c30" resolved "https://registry.yarnpkg.com/zxcvbn/-/zxcvbn-4.4.2.tgz#28ec17cf09743edcab056ddd8b1b06262cc73c30"

Loading…
Cancel
Save