Skip to content

Commit

Permalink
working with version 2 of ledger cosmos lib
Browse files Browse the repository at this point in the history
  • Loading branch information
faboweb committed Jun 5, 2019
1 parent b9a4727 commit 534802a
Show file tree
Hide file tree
Showing 10 changed files with 2,468 additions and 601 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -5,7 +5,7 @@ coverage
*.log
.vscode
.idea
dist
lib
compiled
.awcache
.rpt2_cache
Expand Down
30 changes: 14 additions & 16 deletions package.json
Expand Up @@ -12,11 +12,10 @@
"cosmos sdk",
"cosmos-sdk"
],
"main": "dist/ledger.umd.js",
"module": "dist/ledger.es5.js",
"typings": "dist/types/ledger.d.ts",
"main": "lib/cosmos-ledger.js",
"typings": "lib/types/cosmos-ledger.d.ts",
"files": [
"dist"
"lib"
],
"author": "Fabian Weber <fabian@tendermint.com>",
"repository": {
Expand All @@ -29,15 +28,14 @@
},
"scripts": {
"lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'",
"prebuild": "rimraf dist",
"build": "tsc --module commonjs && rollup -c rollup.config.ts && typedoc --out docs --target es6 --theme minimal --mode file src",
"start": "rollup -c rollup.config.ts -w",
"prebuild": "rimraf lib",
"build": "webpack",
"test": "jest --coverage",
"test:watch": "jest --coverage --watch",
"test:prod": "npm run lint && npm run test -- --no-cache",
"report-coverage": "cat ./coverage/lcov.info | coveralls",
"prepublishOnly": "npm run build",
"precommit": "lint-staged",
"prepublishOnly": "git checkout master && npm run build",
"log": "simsala log",
"release": "git checkout develop & git pull & git push origin develop:release"
},
Expand Down Expand Up @@ -92,22 +90,22 @@
"lodash.camelcase": "^4.3.0",
"prettier": "^1.14.3",
"rimraf": "^2.6.2",
"rollup": "^0.67.0",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-json": "^3.1.0",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-sourcemaps": "^0.4.2",
"rollup-plugin-typescript2": "^0.18.0",
"ts-jest": "^23.10.2",
"ts-loader": "^6.0.2",
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"tslint-config-standard": "^8.0.1",
"typedoc": "^0.12.0",
"typescript": "^3.0.3"
"typescript": "^3.0.3",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2"
},
"dependencies": {
"ledger-cosmos-js": "^1.0.0",
"@ledgerhq/hw-transport-u2f": "^4.61.0",
"@ledgerhq/hw-transport-webusb": "^4.61.0",
"@lunie/cosmos-keys": "^0.0.9",
"ledger-cosmos-js": "^2.0.2",
"secp256k1": "^3.7.0",
"semver": "^6.1.0"
}
Expand Down
38 changes: 0 additions & 38 deletions rollup.config.ts

This file was deleted.

26 changes: 0 additions & 26 deletions src/@types/ledger-cosmos-js/index.d.ts

This file was deleted.

41 changes: 41 additions & 0 deletions src/cosmos-ledger.d.ts
@@ -0,0 +1,41 @@
declare module 'ledger-cosmos-js' {
interface CommunicationMethod {}

export class App {
constructor(communicationMethod: CommunicationMethod)

getVersion: () => {
major: Number
minor: Number
patch: Number
test_mode: Boolean
error_message: string
device_locked: Boolean
}
publicKey: (
hdPath: Array<Number>
) => {
compressed_pk: Buffer
error_message: string
}
getAddressAndPubKey: (
bech32Prefix: string,
hdPath: Array<Number>
) => {
compressed_pk: Buffer
address: string
error_message: string
}
appInfo: () => {
appName: string
error_message: string
}
sign: (
hdPath: Array<Number>,
signMessage: string
) => {
signature: Buffer
error_message: string
}
}
}
90 changes: 70 additions & 20 deletions src/ledger.ts → src/cosmos-ledger.ts
@@ -1,12 +1,22 @@
import { App, comm_u2f } from "ledger-cosmos-js"
import { getCosmosAddress } from "@lunie/js-cosmos-wallet/src/js-cosmos-wallet"
import { signatureImport } from "secp256k1"
const semver = require("semver")
import App from 'ledger-cosmos-js'
import { getCosmosAddress } from '@lunie/cosmos-keys'
import { signatureImport } from 'secp256k1'
import TransportU2F from '@ledgerhq/hw-transport-u2f'
import TransportWebUSB from '@ledgerhq/hw-transport-webusb'
import TransportWebBLE from '@ledgerhq/hw-transport-web-ble'
const semver = require('semver')

const INTERACTION_TIMEOUT = 120 // seconds to wait for user action on Ledger, currently is always limited to 60
const REQUIRED_COSMOS_APP_VERSION = "1.5.0"
const REQUIRED_COSMOS_APP_VERSION = '1.5.0'
//const REQUIRED_LEDGER_FIRMWARE = "1.1.1"

declare global {
interface Window {
chrome: any
opr: any
}
}

/*
HD wallet derivation path (BIP44)
DerivationPath{44, 118, account, 0, index}
Expand Down Expand Up @@ -37,7 +47,7 @@ export default class Ledger {
// check if the device is connected or on screensaver mode
const response = await this.cosmosApp.publicKey(HDPATH)
this.checkLedgerErrors(response, {
timeoutMessag: "Could not find a connected and unlocked Ledger device"
timeoutMessag: 'Could not find a connected and unlocked Ledger device'
})
}

Expand All @@ -62,8 +72,16 @@ export default class Ledger {
// assume well connection if connected once
if (this.cosmosApp) return this

const communicationMethod = await comm_u2f.create_async(timeout, false)
const cosmosLedgerApp = new App(communicationMethod)
const browser = getBrowser()

let transport
if (browser === 'chrome') {
transport = await TransportWebUSB.create(timeout * 1000)
} else {
transport = await TransportU2F.create(timeout * 1000)
}

const cosmosLedgerApp = new App(transport)

this.cosmosApp = cosmosLedgerApp

Expand All @@ -77,7 +95,7 @@ export default class Ledger {
async getCosmosAppVersion() {
await this.connect()

const response = await this.cosmosApp.get_version()
const response = await this.cosmosApp.getVersion()
this.checkLedgerErrors(response)
const { major, minor, patch, test_mode } = response
checkAppMode(this.testModeAllowed, test_mode)
Expand Down Expand Up @@ -127,12 +145,9 @@ export default class Ledger {
return
}

const response = await this.cosmosApp.getAddressAndPubKey(
BECH32PREFIX,
HDPATH
)
const response = await this.cosmosApp.getAddressAndPubKey(BECH32PREFIX, HDPATH)
this.checkLedgerErrors(response, {
rejectionMessage: "Displayed address was rejected"
rejectionMessage: 'Displayed address was rejected'
})
}

Expand All @@ -152,10 +167,10 @@ export default class Ledger {
// parse Ledger errors in a more user friendly format
/* istanbul ignore next: maps a bunch of errors */
private checkLedgerErrors(
{ error_message, device_locked }: { error_message: string, device_locked: Boolean },
{ error_message, device_locked }: { error_message: string; device_locked: Boolean },
{
timeoutMessag = "Connection timed out. Please try again.",
rejectionMessage = "User rejected the transaction"
timeoutMessag = 'Connection timed out. Please try again.',
rejectionMessage = 'User rejected the transaction'
} = {}
) {
if (device_locked) {
Expand All @@ -170,12 +185,12 @@ export default class Ledger {
throw new Error(`Transaction rejected`)
case `Transaction rejected`:
throw new Error(rejectionMessage)
case `Unknown error code`:
case `Unknown Status Code: 26628`:
throw new Error(`Ledger's screensaver mode is on`)
case `Instruction not supported`:
throw new Error(
`Your Cosmos Ledger App is not up to date. ` +
`Please update to version ${REQUIRED_COSMOS_APP_VERSION}.`
`Please update to version ${REQUIRED_COSMOS_APP_VERSION}.`
)
case `No errors`:
// do nothing
Expand All @@ -187,7 +202,7 @@ export default class Ledger {
}

// stiched version string from Ledger app version object
function versionString({ major, minor, patch }: { major: Number, minor: Number, patch: Number }) {
function versionString({ major, minor, patch }: { major: Number; minor: Number; patch: Number }) {
return `${major}.${minor}.${patch}`
}

Expand All @@ -199,3 +214,38 @@ export const checkAppMode = (testModeAllowed: Boolean, testMode: Boolean) => {
)
}
}

function getBrowser() {
// please note,
// that IE11 now returns undefined again for window.chrome
// and new Opera 30 outputs true for window.chrome
// but needs to check if window.opr is not undefined
// and new IE Edge outputs to true now for window.chrome
// and if not iOS Chrome check
// so use the below updated condition
// tslint:disable-next-line
var isChromium = window.chrome
var winNav = window.navigator
var vendorName = winNav.vendor
// tslint:disable-next-line
var isOpera = typeof window.opr !== 'undefined'
var isIEedge = winNav.userAgent.indexOf('Edge') > -1
var isIOSChrome = winNav.userAgent.match('CriOS')

if (isIOSChrome) {
// is Google Chrome on IOS
return 'chrome'
} else if (
isChromium !== null &&
typeof isChromium !== 'undefined' &&
vendorName === 'Google Inc.' &&
isOpera === false &&
isIEedge === false
) {
// is Google Chrome
return 'chrome'
} else {
// not Google Chrome
if (isOpera) return 'opera'
}
}

0 comments on commit 534802a

Please sign in to comment.