diff --git a/.env b/.env new file mode 100644 index 0000000..ba7cc18 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +GENERATE_SOURCEMAP=false diff --git a/.gitattributes b/.gitattributes index db7b0bc..a179d0c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,4 @@ *.bin filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.tar.gz filter=lfs diff=lfs merge=lfs -text +*.AppImage filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index 2028e0a..ae03ae8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,25 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. - -# dependencies -/node_modules - -# testing -/coverage - -# production -/build -/dist - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* +* +!/.circleci/ +!/.circleci/** +!/.env +!/.gitattributes +!/.gitignore +!/.nvmrc +!/assets/ +!/assets/** +!/deploy_ipns.sh +!/firmware/ +!/firmware/** +!/infra/ +!/infra/** +!/package.json +!/public/ +!/public/** +!/README.md +!/scripts/ +!/scripts/** +!/src/ +!/src/** +!/uml/ +!/uml/** +!/yarn.lock diff --git a/.nvmrc b/.nvmrc index 48082f7..b6a7d89 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12 +16 diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e2f628 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# KeepKey Updater + +## Setup +install deps and run: + +``` +yarn +yarn electron-dev +``` + +Changes to the display process (the things in `src/`) will automatically trigger a reload. Changes +to the main process (the things in `public/`) will require a manual restart to be reflected. + +## Build + +### Versions + +There are three versions of the updater: Mac OS, Linux, and Windows. You must build on the host OS for the app you're packaging. + +#### Mac OS + +The `macos` build requires that the app be signed. As of 10.14.5, the app must also be notarized by Apple. The build process will do this automatically but you must configure the build machine with the following: + + 1. A Developer ID signing certificate must be added to the key store. This is typically done by signing into your developer account via the Xcode GUI. + 2. You must set the following environment variables where XXXXX is the your developer ID and YYYYY is an app-specific password. + + export APPLEID="XXXXX" + export APPLEIDPW= "YYYYY" + +#### Windows + +Build the app on a Windows machine. + +#### Linux + +Build the app on a Linux machine. + + +### Build Process + +``` +nvm use +rm -rf build dist node_modules +yarn install --frozen-lockfile +yarn electron-pack +``` + +This will create installer and app images for the host OS you're on in `/dist`. + +## Adding New Firmware/Bootloader Versions + +The KeepKey Updater will automatically grab what's in the `latest` parameter block in `releases.json`. To release a new version of either of these: + +1) Get hashes for the firmware and/or signed bootloader: + + - Firmware: Use the SHA-256 hash of firmware.keepkey.bin +``` +openssl dgst -sha256 -r firmware.keepkey.bin | cut -d ' ' -f 1 +``` + + - Bootloader: Use the double-SHA-256 of bootloader.bin (*not* blupdater.bin). + +``` +openssl dgst -sha256 -binary bootloader.bin | openssl dgst -sha256 -r | cut -d ' ' -f 1 +``` + +2) Drop a hash+version keypair in `releases.json`, following the existing pattern. Update `latest` version as appropriate. + +3) Commit changes to `releases.json`, plus new binary image files in a subdirectory of `firmware`. + +4) Run `firmware/ipns-deploy.sh`, providing an IPNS keyfile and a web3.storage API key. + +5) Done. diff --git a/deploy_ipns.sh b/deploy_ipns.sh new file mode 100755 index 0000000..0a890d4 --- /dev/null +++ b/deploy_ipns.sh @@ -0,0 +1,30 @@ +#!/bin/bash -e +KEYPATH="$1" +JWT="$2" + +if [ ! -f "$KEYPATH" ] || [ -z "$JWT" ]; then + printf 'Usage: %s \n' "$(basename "$0")" 1>&2 + exit 1 +fi + +echo "Adding directory to local IPFS node..." +CID="$(ipfs add -Qr "$(dirname "$0")/firmware")" +echo "Directory added, CID: $CID" + +KEYNAME="keepkey-updater-$RANDOM-$RANDOM-$RANDOM" +echo "Importing IPNS key..." +ipfs key import "$KEYNAME" "$1" 1>/dev/null +echo "Publishing IPNS name..." +ipfs name publish "--key=$KEYNAME" "/ipfs/$CID" || { + echo "IPNS update failed!" 1>&2 + echo "Removing IPNS key..." + ipfs key rm "$KEYNAME" 1>/dev/null + exit 1 +} +echo "Removing IPNS key..." +ipfs key rm "$KEYNAME" 1>/dev/null + +echo "Uploading to web3.storage..." +ipfs dag export "$CID" | curl --progress-bar -X POST -H "Content-Type: application/car" -H "Authorization: Bearer $JWT" --data-binary '@-' https://api.web3.storage/car | jq '.' + +echo "Done." diff --git a/firmware/bl_v1.1.0/blupdater.bin b/firmware/bl_v1.1.0/blupdater.bin new file mode 100644 index 0000000..eeedec8 --- /dev/null +++ b/firmware/bl_v1.1.0/blupdater.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7ce979601d2473fac7fbe35093edecf04fe9a1ef2fb8f8e94f1c6f762d9ae88 +size 223120 diff --git a/firmware/bl_v1.1.0/keepkey-firmware-bl_v1.1.0.tar.gz b/firmware/bl_v1.1.0/keepkey-firmware-bl_v1.1.0.tar.gz new file mode 100644 index 0000000..44d3c84 --- /dev/null +++ b/firmware/bl_v1.1.0/keepkey-firmware-bl_v1.1.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2b098188565b4a4405703391cfb4450c86411bb65e1d8c57c256eac6932a813 +size 836762 diff --git a/firmware/bl_v1.1.0/keepkey-firmware-bl_v1.1.0.zip b/firmware/bl_v1.1.0/keepkey-firmware-bl_v1.1.0.zip new file mode 100644 index 0000000..3f00234 --- /dev/null +++ b/firmware/bl_v1.1.0/keepkey-firmware-bl_v1.1.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68a88847c3bf2866e222bb494e7207678890221c63122c7e5bf7931fe38005fe +size 978405 diff --git a/firmware/bl_v2.0.0/blupdater.bin b/firmware/bl_v2.0.0/blupdater.bin new file mode 100644 index 0000000..b735579 --- /dev/null +++ b/firmware/bl_v2.0.0/blupdater.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4e420756648d45ef804410f2a9e373c23bb88b0cf725ae04b6dcc68f0b9ed04 +size 315732 diff --git a/firmware/bl_v2.0.0/keepkey-firmware-bl_v2.0.0.tar.gz b/firmware/bl_v2.0.0/keepkey-firmware-bl_v2.0.0.tar.gz new file mode 100644 index 0000000..bf318f8 --- /dev/null +++ b/firmware/bl_v2.0.0/keepkey-firmware-bl_v2.0.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:347817360e9bb9d67c311c45948045063731c46d5be7c02b6cc02ee798060cf9 +size 302871 diff --git a/firmware/bl_v2.0.0/keepkey-firmware-bl_v2.0.0.zip b/firmware/bl_v2.0.0/keepkey-firmware-bl_v2.0.0.zip new file mode 100644 index 0000000..8d17821 --- /dev/null +++ b/firmware/bl_v2.0.0/keepkey-firmware-bl_v2.0.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca68447eb310582a617cd7a313486768ad7e6c7b155a11592cf37cd97712add9 +size 459345 diff --git a/firmware/bl_v2.1.4/blupdater.bin b/firmware/bl_v2.1.4/blupdater.bin new file mode 100644 index 0000000..c658f55 --- /dev/null +++ b/firmware/bl_v2.1.4/blupdater.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bb7cfd28262fcd61c450fdc3f6932650bdf16a134ab6c1bc6f90b0d1578e620 +size 314860 diff --git a/firmware/releases.json b/firmware/releases.json new file mode 100644 index 0000000..9d8c69a --- /dev/null +++ b/firmware/releases.json @@ -0,0 +1,79 @@ +{ + "latest": { + "firmware": { + "version": "v7.3.2", + "url": "v7.3.2/firmware.keepkey.bin", + "hash": "efcdcb32f199110e9a38010bc48d2acc66da89d41fb30c7d0b64c1ef74c90359" + }, + "bootloader": { + "version": "v2.1.4", + "url": "bl_v2.1.4/blupdater.bin", + "hash": "6bb7cfd28262fcd61c450fdc3f6932650bdf16a134ab6c1bc6f90b0d1578e620" + }, + "updater": { + "version": "v2.1.2" + } + }, + "hashes": { + "bootloader": { + "6397c446f6b9002a8b150bf4b9b4e0bb66800ed099b881ca49700139b0559f10": "v1.0.0", + "f13ce228c0bb2bdbc56bdcb5f4569367f8e3011074ccc63331348deb498f2d8f": "v1.0.0", + "d544b5e06b0c355d68b868ac7580e9bab2d224a1e2440881cc1bca2b816752d5": "v1.0.1", + "ec618836f86423dbd3114c37d6e3e4ffdfb87d9e4c6199cf3e163a67b27498a2": "v1.0.1", + "cd702b91028a2cfa55af43d3407ba0f6f752a4a2be0583a172983b303ab1032e": "v1.0.2", + "bcafb38cd0fbd6e2bdbea89fb90235559fdda360765b74e4a8758b4eff2d4921": "v1.0.2", + "cb222548a39ff6cbe2ae2f02c8d431c9ae0df850f814444911f521b95ab02f4c": "v1.0.3", + "917d1952260c9b89f3a96bea07eea4074afdcc0e8cdd5d064e36868bdd68ba7d": "v1.0.3", + "6465bc505586700a8111c4bf7db6f40af73e720f9e488d20db56135e5a690c4f": "v1.0.3", + "db4bc389335e876e942ae3b12558cecd202b745903e79b34dd2c32532708860e": "v1.0.3", + "2e38950143cf350345a6ddada4c0c4f21eb2ed337309f39c5dbc70b6c091ae00": "v1.0.3", + "83d14cb6c7c48af2a83bc326353ee6b9abdd74cfe47ba567de1cb564da65e8e9": "v1.0.3", + "770b30aaa0be884ee8621859f5d055437f894a5c9c7ca22635e7024e059857b7": "v1.0.4", + "fc4e5c4dc2e5127b6814a3f69424c936f1dc241d1daf2c5a2d8f0728eb69d20d": "v1.0.4", + "e45f587fb07533d832548402d0e71d8e8234881da54d86c4b699c28a6482b0ee": "v1.1.0", + "9bf1580d1b21250f922b68794cdadd6c8e166ae5b15ce160a42f8c44a2f05936": "v2.0.0", + "e1ad2667d1924e4ddbeb623bd6939e94114d8471b84f8fb056e0c9abf0c4e4f4": "v2.1.0", + "a3f8c745ff33cd92a7e95d37c76c65523d258a70352ea44a232038ec4ec38dea": "v2.1.1", + "3b97596ed612aa29a74a7f51f33ea85fd6e0cfe7340dfbb96f0c17077b363498": "v2.1.2", + "e6685ab14844d0a381d658d77e13d6145fe7ae80469e5a5360210ae9c3447a77": "v2.1.3", + "fe98454e7ebd4aef4a6db5bd4c60f52cf3f58b974283a7c1e1fcc5fea02cf3eb": "v2.1.4" + }, + "firmware": { + "efcdcb32f199110e9a38010bc48d2acc66da89d41fb30c7d0b64c1ef74c90359": "v7.3.2", + "47f3ead32f7be5926018163a2324f7dd1c47ef0b4cebec9bd8ae380d0a803314": "v7.3.1", + "28932f4ee19f88936c76fb5179e3d680443fede2fa782da0e674988963190a96": "v7.3.0", + "c6cf79e7c2cc1b9cf7eca57aacaab5310b4dd0eff1559cda307295d753251eff": "v7.2.1", + "72838adfe3762760dbbbadd74c8914b783660ea0ef3b8fe340e4a663442c5549": "v7.1.8", + "2b7edd319536076e0a00058d0cfd1b1863c8d616ba5851668796d04966df8594": "v7.1.7", + "53adf5693f7c23bc30c8cad8acc6ea939b063e205a4f4201eb9bd24fdc8285f0": "v7.1.5", + "7a52fa75be2e3e9794c4a01e74fc2a68cd502aace13fca1f272d5296156f1499": "v7.1.4", + "aa5834bb591c40dffd5e083797fe25e6d5591199a781220025fa469a965d0279": "v7.1.2", + "eb3d8853d549671dee532b51363cffdfa2038bc7730117e72dc17bb1452de4db": "v7.1.1", + "d8b2b43eada45ded399f347289750a7083081186b37158b85eab41a38cbc6e50": "v7.1.0", + "6a5e2bcf98aeafbb2faa98ea425ac066a7b4733e5b9edb29e544bad659cb3766": "v7.0.3", + "24071db7596f0824e51ce971c1ec39ac5a07e7a5bcaf5f1b33313de844e25580": "v6.7.0", + "85a44f1872b4b4ed0d5ff062711cfd4d4d69d9274312c9e3780b7db8da9072e8": "v6.6.0", + "89d1b5230bbca2e02901b091cbd77207d0636e6f1956f6f27a0ecb10c43cce3d": "v6.5.1", + "0ef1b51a450fafd8e0586103bda38526c5d012fc260618b8df5437cba7682c5b": "v6.4.0", + "0e2463b777f39dc8b450aca78f55b3355e906c69d19b59e84052786c5fa8f78c": "v6.3.0", + "5bcbeecea0a1c78cbd11344bb31c809072a01cb775f1e42368ef275888012208": "v6.2.2", + "0158073bb527b3b14148641722e77346ecec66a12fc4a5b4457dc0559c63169e": "v6.2.0", + "f9dfd903e6d4d8189409a72b9d31897ca1753a4000a24cc1c9217f4b8141403c": "v6.1.1", + "4246ff0e1b71a2a6b3e89e2cfd0882dc207f96b2516640d6c5fff406c02097bf": "v6.1.0", + "61c157a7fbc22f4d9825909ac067277a94e44c174e77db419fbb78b361fbf4ea": "v6.0.4", + "14cf71b0872a5c3cda1af2007aafd9bd0d5401be927e08e5b226fe764334d515": "v6.0.2", + "699f75ae5936977bf4f9df0478afe40106ea21bc2d94746bbe244a7832d4c5ca": "v6.0.1", + "d380357b7403064d7b1ea963dc56032239541a21ef0b7e08082fb36ed470de82": "v6.0.0", + "a05b992c1cadb151117704a03af8b7020482061200ce7bc72f90e8e4aba01a4f": "v5.11.0" + } + }, + "links": { + "app": "https://app.shapeshift.com", + "support": "https://shapeshift.zendesk.com", + "updater": "https://beta.shapeshift.com/updater-download" + }, + "strings": { + "goToApp": "Head over to ShapeShift!", + "updateUpdater": "Update Available" + } +} diff --git a/firmware/v6.0.0/firmware.keepkey.bin b/firmware/v6.0.0/firmware.keepkey.bin new file mode 100644 index 0000000..5d3b7d6 --- /dev/null +++ b/firmware/v6.0.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d380357b7403064d7b1ea963dc56032239541a21ef0b7e08082fb36ed470de82 +size 558256 diff --git a/firmware/v6.0.0/keepkey-firmware-6.0.0.tar.gz b/firmware/v6.0.0/keepkey-firmware-6.0.0.tar.gz new file mode 100644 index 0000000..aef4b79 --- /dev/null +++ b/firmware/v6.0.0/keepkey-firmware-6.0.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fc411f0b5a1b94f3648c402e8f30fa2f577c397c3d72589ddfd9ecfb2344e8a +size 657782 diff --git a/firmware/v6.0.0/keepkey-firmware-6.0.0.zip b/firmware/v6.0.0/keepkey-firmware-6.0.0.zip new file mode 100644 index 0000000..e21f32f --- /dev/null +++ b/firmware/v6.0.0/keepkey-firmware-6.0.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3231ed72765c4c1925c61491ffd21df5a8a487fe573ed279354ea46bef4c9aa2 +size 789695 diff --git a/firmware/v6.0.1/firmware.keepkey.bin b/firmware/v6.0.1/firmware.keepkey.bin new file mode 100644 index 0000000..da4b35e --- /dev/null +++ b/firmware/v6.0.1/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:699f75ae5936977bf4f9df0478afe40106ea21bc2d94746bbe244a7832d4c5ca +size 553176 diff --git a/firmware/v6.0.1/keepkey-firmware-6.0.1.tar.gz b/firmware/v6.0.1/keepkey-firmware-6.0.1.tar.gz new file mode 100644 index 0000000..ef896ef --- /dev/null +++ b/firmware/v6.0.1/keepkey-firmware-6.0.1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bde9ff0475a68671226598fe7cd6c2c9ea1bbad826408059fd99f28140103d0 +size 658290 diff --git a/firmware/v6.0.1/keepkey-firmware-6.0.1.zip b/firmware/v6.0.1/keepkey-firmware-6.0.1.zip new file mode 100644 index 0000000..c73207a --- /dev/null +++ b/firmware/v6.0.1/keepkey-firmware-6.0.1.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a8485a3a5485fd90e15b70acc563fa9198439ab534b8f3bc4f188b3f7e1f0fd +size 790394 diff --git a/firmware/v6.0.2/firmware.keepkey.bin b/firmware/v6.0.2/firmware.keepkey.bin new file mode 100644 index 0000000..beca31e --- /dev/null +++ b/firmware/v6.0.2/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14cf71b0872a5c3cda1af2007aafd9bd0d5401be927e08e5b226fe764334d515 +size 596400 diff --git a/firmware/v6.0.2/keepkey-firmware-6.0.2.tar.gz b/firmware/v6.0.2/keepkey-firmware-6.0.2.tar.gz new file mode 100644 index 0000000..9865891 --- /dev/null +++ b/firmware/v6.0.2/keepkey-firmware-6.0.2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:154831c1eccbe1459d54212f3b2a3a293ed8f2e066edcaf5e15985a8e672547d +size 634080 diff --git a/firmware/v6.0.2/keepkey-firmware-6.0.2.zip b/firmware/v6.0.2/keepkey-firmware-6.0.2.zip new file mode 100644 index 0000000..9384f3d --- /dev/null +++ b/firmware/v6.0.2/keepkey-firmware-6.0.2.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2422c2ef4b4cbd4f66a0447b6f21ce53dff10408440c86f91c784b5c461d1264 +size 779338 diff --git a/firmware/v6.0.4/firmware.keepkey.bin b/firmware/v6.0.4/firmware.keepkey.bin new file mode 100644 index 0000000..45ddd09 --- /dev/null +++ b/firmware/v6.0.4/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61c157a7fbc22f4d9825909ac067277a94e44c174e77db419fbb78b361fbf4ea +size 597508 diff --git a/firmware/v6.0.4/keepkey-firmware-6.0.4.tar.gz b/firmware/v6.0.4/keepkey-firmware-6.0.4.tar.gz new file mode 100644 index 0000000..cd31ed2 --- /dev/null +++ b/firmware/v6.0.4/keepkey-firmware-6.0.4.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0302a26070aeee8aab4301d74b4c19eb97e3fead4703b6de6ef9dfc01b8cbbb +size 634594 diff --git a/firmware/v6.0.4/keepkey-firmware-6.0.4.zip b/firmware/v6.0.4/keepkey-firmware-6.0.4.zip new file mode 100644 index 0000000..f45c571 --- /dev/null +++ b/firmware/v6.0.4/keepkey-firmware-6.0.4.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f36c8f9639402ae0b2640d0e54fe393af91867e8dd1a4becfdb9e83051d49281 +size 779978 diff --git a/firmware/v6.1.0/firmware.keepkey.bin b/firmware/v6.1.0/firmware.keepkey.bin new file mode 100644 index 0000000..ca48435 --- /dev/null +++ b/firmware/v6.1.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4246ff0e1b71a2a6b3e89e2cfd0882dc207f96b2516640d6c5fff406c02097bf +size 612068 diff --git a/firmware/v6.1.0/keepkey-firmware-6.1.0.tar.gz b/firmware/v6.1.0/keepkey-firmware-6.1.0.tar.gz new file mode 100644 index 0000000..7c307b4 --- /dev/null +++ b/firmware/v6.1.0/keepkey-firmware-6.1.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9166207741c317fa76cadf7b242b57caaa4c296006fbee13adf94b6f8b206c55 +size 302903 diff --git a/firmware/v6.1.0/keepkey-firmware-6.1.0.zip b/firmware/v6.1.0/keepkey-firmware-6.1.0.zip new file mode 100644 index 0000000..fda93bc --- /dev/null +++ b/firmware/v6.1.0/keepkey-firmware-6.1.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfe7ed03434c889b3d67af17a854483c5c8a3fcb3050be978bf416d303599692 +size 456545 diff --git a/firmware/v6.1.1/firmware.keepkey.bin b/firmware/v6.1.1/firmware.keepkey.bin new file mode 100644 index 0000000..d155d48 --- /dev/null +++ b/firmware/v6.1.1/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9dfd903e6d4d8189409a72b9d31897ca1753a4000a24cc1c9217f4b8141403c +size 613988 diff --git a/firmware/v6.1.1/keepkey-firmware-6.1.1.tar.gz b/firmware/v6.1.1/keepkey-firmware-6.1.1.tar.gz new file mode 100644 index 0000000..6b1ac6e --- /dev/null +++ b/firmware/v6.1.1/keepkey-firmware-6.1.1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d8a56263487f91b8441a96ab2fa8a3b101e78de3b8b852f8ad4e578f79b6a0a +size 310598 diff --git a/firmware/v6.1.1/keepkey-firmware-6.1.1.zip b/firmware/v6.1.1/keepkey-firmware-6.1.1.zip new file mode 100644 index 0000000..d829e12 --- /dev/null +++ b/firmware/v6.1.1/keepkey-firmware-6.1.1.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e2b4cbab9a8eeb32c74e20f21a8750a42d9618548d75429425d6b5822e3e036 +size 464150 diff --git a/firmware/v6.2.0/firmware.keepkey.bin b/firmware/v6.2.0/firmware.keepkey.bin new file mode 100644 index 0000000..6c6ecc2 --- /dev/null +++ b/firmware/v6.2.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0158073bb527b3b14148641722e77346ecec66a12fc4a5b4457dc0559c63169e +size 629076 diff --git a/firmware/v6.2.0/keepkey-firmware-6.2.0.tar.gz b/firmware/v6.2.0/keepkey-firmware-6.2.0.tar.gz new file mode 100644 index 0000000..f75ecde --- /dev/null +++ b/firmware/v6.2.0/keepkey-firmware-6.2.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b83a9ae27c85df8ae4aea277edc9e0608ca2924fae8abd314e80aa1851d98e93 +size 314084 diff --git a/firmware/v6.2.0/keepkey-firmware-6.2.0.zip b/firmware/v6.2.0/keepkey-firmware-6.2.0.zip new file mode 100644 index 0000000..5ab6842 --- /dev/null +++ b/firmware/v6.2.0/keepkey-firmware-6.2.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da8405c188f8b06c53f52c852f5ea12b50143d2b37961d8754e0ddd54fc5e86e +size 471308 diff --git a/firmware/v6.2.2/firmware.keepkey.bin b/firmware/v6.2.2/firmware.keepkey.bin new file mode 100644 index 0000000..302b07c --- /dev/null +++ b/firmware/v6.2.2/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bcbeecea0a1c78cbd11344bb31c809072a01cb775f1e42368ef275888012208 +size 640260 diff --git a/firmware/v6.2.2/keepkey-firmware-6.2.2.tar.gz b/firmware/v6.2.2/keepkey-firmware-6.2.2.tar.gz new file mode 100644 index 0000000..e7eb3e9 --- /dev/null +++ b/firmware/v6.2.2/keepkey-firmware-6.2.2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:80cf5aa1c8b8bac81246d267b0f5908deaf84dae4c94b34bd2111a0413274372 +size 315400 diff --git a/firmware/v6.2.2/keepkey-firmware-6.2.2.zip b/firmware/v6.2.2/keepkey-firmware-6.2.2.zip new file mode 100644 index 0000000..0a4356c --- /dev/null +++ b/firmware/v6.2.2/keepkey-firmware-6.2.2.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bfa76e069e6d4c67849e9c7c2d4a1517745ed8117a2ea6a8d001839aae8067f +size 472814 diff --git a/firmware/v6.3.0/firmware.keepkey.bin b/firmware/v6.3.0/firmware.keepkey.bin new file mode 100644 index 0000000..5129a63 --- /dev/null +++ b/firmware/v6.3.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e2463b777f39dc8b450aca78f55b3355e906c69d19b59e84052786c5fa8f78c +size 503708 diff --git a/firmware/v6.3.0/keepkey-firmware-6.3.0.tar.gz b/firmware/v6.3.0/keepkey-firmware-6.3.0.tar.gz new file mode 100644 index 0000000..b765570 --- /dev/null +++ b/firmware/v6.3.0/keepkey-firmware-6.3.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3073fdc3ed4e37a62a513a01832c72a39c0134d356bb2b4fc88379560de300e5 +size 318552 diff --git a/firmware/v6.3.0/keepkey-firmware-6.3.0.zip b/firmware/v6.3.0/keepkey-firmware-6.3.0.zip new file mode 100644 index 0000000..4c92760 --- /dev/null +++ b/firmware/v6.3.0/keepkey-firmware-6.3.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:34fe196f2394b966e3fd163b8446d26aed92565d2f3a47f1953704cd54f646e2 +size 476488 diff --git a/firmware/v6.4.0/firmware.keepkey.bin b/firmware/v6.4.0/firmware.keepkey.bin new file mode 100755 index 0000000..8765160 --- /dev/null +++ b/firmware/v6.4.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ef1b51a450fafd8e0586103bda38526c5d012fc260618b8df5437cba7682c5b +size 478868 diff --git a/firmware/v6.4.0/keepkey-firmware-6.4.0.tar.gz b/firmware/v6.4.0/keepkey-firmware-6.4.0.tar.gz new file mode 100644 index 0000000..3cc062a --- /dev/null +++ b/firmware/v6.4.0/keepkey-firmware-6.4.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:607b3702e1a85db18cca2c2731c1b09c4205eae58938ef138b290e1b3294736c +size 275676 diff --git a/firmware/v6.4.0/keepkey-firmware-6.4.0.zip b/firmware/v6.4.0/keepkey-firmware-6.4.0.zip new file mode 100644 index 0000000..a6ec864 --- /dev/null +++ b/firmware/v6.4.0/keepkey-firmware-6.4.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c9f2f269b72aff9d540db7faae5b7947e81f8c25c5f466f372d70014339664a +size 275971 diff --git a/firmware/v6.5.1/firmware.keepkey.bin b/firmware/v6.5.1/firmware.keepkey.bin new file mode 100644 index 0000000..98de84a --- /dev/null +++ b/firmware/v6.5.1/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89d1b5230bbca2e02901b091cbd77207d0636e6f1956f6f27a0ecb10c43cce3d +size 482548 diff --git a/firmware/v6.5.1/keepkey-firmware-6.5.1.tar.gz b/firmware/v6.5.1/keepkey-firmware-6.5.1.tar.gz new file mode 100644 index 0000000..53c0e28 --- /dev/null +++ b/firmware/v6.5.1/keepkey-firmware-6.5.1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9c516fa91c98cccb6b4fba33bc1d5872aae01bfcda7d2847376d5b7298c6e2e +size 277562 diff --git a/firmware/v6.5.1/keepkey-firmware-6.5.1.zip b/firmware/v6.5.1/keepkey-firmware-6.5.1.zip new file mode 100644 index 0000000..c7ee408 --- /dev/null +++ b/firmware/v6.5.1/keepkey-firmware-6.5.1.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f414e4ce408505dad2ff2a7dc6349d64714d3bf431ef074a8ed40ba215fc8c1e +size 278290 diff --git a/firmware/v6.6.0/firmware.keepkey.bin b/firmware/v6.6.0/firmware.keepkey.bin new file mode 100644 index 0000000..ba65259 --- /dev/null +++ b/firmware/v6.6.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85a44f1872b4b4ed0d5ff062711cfd4d4d69d9274312c9e3780b7db8da9072e8 +size 482516 diff --git a/firmware/v6.6.0/keepkey-firmware-6.6.0.tar.gz b/firmware/v6.6.0/keepkey-firmware-6.6.0.tar.gz new file mode 100644 index 0000000..f2d90ff --- /dev/null +++ b/firmware/v6.6.0/keepkey-firmware-6.6.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ae3fe56cb319ca7678cfbe97a602f62efa39a484a7394be779e56309b2ec04d +size 357020 diff --git a/firmware/v6.6.0/keepkey-firmware-6.6.0.zip b/firmware/v6.6.0/keepkey-firmware-6.6.0.zip new file mode 100644 index 0000000..6bbe3a5 --- /dev/null +++ b/firmware/v6.6.0/keepkey-firmware-6.6.0.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d239fa1298b316a301334613c45da9829858cd39f0a7b130a895f8c3a24075aa +size 529781 diff --git a/firmware/v6.7.0/firmware.keepkey.bin b/firmware/v6.7.0/firmware.keepkey.bin new file mode 100644 index 0000000..0248fdb --- /dev/null +++ b/firmware/v6.7.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:24071db7596f0824e51ce971c1ec39ac5a07e7a5bcaf5f1b33313de844e25580 +size 497796 diff --git a/firmware/v7.0.3/firmware.keepkey.bin b/firmware/v7.0.3/firmware.keepkey.bin new file mode 100644 index 0000000..5e9f917 --- /dev/null +++ b/firmware/v7.0.3/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a5e2bcf98aeafbb2faa98ea425ac066a7b4733e5b9edb29e544bad659cb3766 +size 502092 diff --git a/firmware/v7.1.0/firmware.keepkey.bin b/firmware/v7.1.0/firmware.keepkey.bin new file mode 100644 index 0000000..fb2b74f --- /dev/null +++ b/firmware/v7.1.0/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8b2b43eada45ded399f347289750a7083081186b37158b85eab41a38cbc6e50 +size 513364 diff --git a/firmware/v7.1.1/firmware.keepkey.bin b/firmware/v7.1.1/firmware.keepkey.bin new file mode 100644 index 0000000..217b234 --- /dev/null +++ b/firmware/v7.1.1/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb3d8853d549671dee532b51363cffdfa2038bc7730117e72dc17bb1452de4db +size 515268 diff --git a/firmware/v7.1.2/firmware.keepkey.bin b/firmware/v7.1.2/firmware.keepkey.bin new file mode 100644 index 0000000..8b95c69 --- /dev/null +++ b/firmware/v7.1.2/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa5834bb591c40dffd5e083797fe25e6d5591199a781220025fa469a965d0279 +size 525244 diff --git a/firmware/v7.1.4/firmware.keepkey.bin b/firmware/v7.1.4/firmware.keepkey.bin new file mode 100644 index 0000000..4e0f8b6 --- /dev/null +++ b/firmware/v7.1.4/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a52fa75be2e3e9794c4a01e74fc2a68cd502aace13fca1f272d5296156f1499 +size 525836 diff --git a/firmware/v7.1.7/firmware.keepkey.bin b/firmware/v7.1.7/firmware.keepkey.bin new file mode 100644 index 0000000..d8de6de --- /dev/null +++ b/firmware/v7.1.7/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b7edd319536076e0a00058d0cfd1b1863c8d616ba5851668796d04966df8594 +size 527004 diff --git a/firmware/v7.1.8/firmware.keepkey.bin b/firmware/v7.1.8/firmware.keepkey.bin new file mode 100644 index 0000000..1114a76 --- /dev/null +++ b/firmware/v7.1.8/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:72838adfe3762760dbbbadd74c8914b783660ea0ef3b8fe340e4a663442c5549 +size 523164 diff --git a/firmware/v7.2.1/firmware.keepkey.bin b/firmware/v7.2.1/firmware.keepkey.bin new file mode 100644 index 0000000..3a32a2c --- /dev/null +++ b/firmware/v7.2.1/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6cf79e7c2cc1b9cf7eca57aacaab5310b4dd0eff1559cda307295d753251eff +size 523468 diff --git a/firmware/v7.3.2/firmware.keepkey.bin b/firmware/v7.3.2/firmware.keepkey.bin new file mode 100644 index 0000000..709468e --- /dev/null +++ b/firmware/v7.3.2/firmware.keepkey.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efcdcb32f199110e9a38010bc48d2acc66da89d41fb30c7d0b64c1ef74c90359 +size 528828 diff --git a/package.json b/package.json index 6b0dbaf..cb2cfe3 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,24 @@ { - "name": "kk-updater", - "version": "2.0.0", + "name": "keepkey-updater", + "version": "2.1.2", "private": true, "main": "public/electron.js", - "author": "keepkey", + "author": "KeepKey", "homepage": "./", "dependencies": { - "@shapeshiftoss/hdwallet-keepkey-nodehid": "^0.11.0", - "@shapeshiftoss/hdwallet-keepkey-nodewebusb": "^1.16.3", - "electron-is-dev": "^0.3.0", - "electron-notarize": "^1.0.0", - "react": "^16.5.1", - "react-dom": "^16.5.1", - "react-scripts": "1.1.5", - "request": "^2.88.0", + "@shapeshiftoss/hdwallet-core": "1.20.1", + "@shapeshiftoss/hdwallet-keepkey-nodehid": "1.20.1", + "@shapeshiftoss/hdwallet-keepkey-nodewebusb": "1.20.1", + "electron-is-dev": "^2.0.0", + "electron-notarize": "^1.0.1", + "node-fetch": "^2.6.7", + "node-hid": "^2.1.1", + "react": "^16.8.6", + "react-dom": "^16.8.6", + "react-scripts": "^5.0.1", "semantic-ui-react": "^0.84.0", - "serialport": "^7.0.2", - "usb-detection": "^4.10.0", - "webusb": "^2.2.0" + "semver-compare": "^1.0.0", + "usb": "^2.3.1" }, "build": { "appId": "KeepKeyUpdater", @@ -38,9 +39,9 @@ "entitlementsInherit": "assets/build/entitlements.mac.plist" }, "win": { - "icon": "build/icon.png" - }, - "afterSign": "scripts/afterSignHook.js" + "icon": "build/icon.png", + "target": "portable" + } }, "scripts": { "start": "react-scripts start", @@ -51,17 +52,26 @@ "electron-dev": "concurrently \"BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron .\"", "pack": "electron-builder --dir", "dist": "electron-builder", - "electron-pack": "build --c.extraMetadata.main=build/electron.js", - "notarize": "scripts/notarize.js", + "electron-pack": "yarn run dist --c.extraMetadata.main=build/electron.js", "preelectron-pack": "yarn build", "postinstall": "electron-builder install-app-deps" }, "devDependencies": { - "concurrently": "^4.0.1", - "electron": "^2.0.9", - "electron-builder": "^20.42.0", - "electron-packager": "^12.1.2", - "electron-rebuild": "^1.8.2", - "wait-on": "^3.0.1" + "concurrently": "^6.2.0", + "electron": "^18.1.0", + "electron-builder": "^23.0.3", + "wait-on": "^6.0.0" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] } } diff --git a/public/bootloader-profiles.json b/public/bootloader-profiles.json deleted file mode 100644 index dd7a3e6..0000000 --- a/public/bootloader-profiles.json +++ /dev/null @@ -1,92 +0,0 @@ -[ - { - "hash": "6397c446f6b9002a8b150bf4b9b4e0bb66800ed099b881ca49700139b0559f10", - "tag": "v1.0.0", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "f13ce228c0bb2bdbc56bdcb5f4569367f8e3011074ccc63331348deb498f2d8f", - "tag": "v1.0.0-patched", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "d544b5e06b0c355d68b868ac7580e9bab2d224a1e2440881cc1bca2b816752d5", - "tag": "v1.0.1", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "ec618836f86423dbd3114c37d6e3e4ffdfb87d9e4c6199cf3e163a67b27498a2", - "tag": "v1.0.1-patched", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "cd702b91028a2cfa55af43d3407ba0f6f752a4a2be0583a172983b303ab1032e", - "tag": "v1.0.2", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "bcafb38cd0fbd6e2bdbea89fb90235559fdda360765b74e4a8758b4eff2d4921", - "tag": "v1.0.2-patched", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "cb222548a39ff6cbe2ae2f02c8d431c9ae0df850f814444911f521b95ab02f4c", - "tag": "v1.0.3", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "917d1952260c9b89f3a96bea07eea4074afdcc0e8cdd5d064e36868bdd68ba7d", - "tag": "v1.0.3-patched", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "6465bc505586700a8111c4bf7db6f40af73e720f9e488d20db56135e5a690c4f", - "tag": "v1.0.3v2", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "db4bc389335e876e942ae3b12558cecd202b745903e79b34dd2c32532708860e", - "tag": "v1.0.3v2-patched", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "2e38950143cf350345a6ddada4c0c4f21eb2ed337309f39c5dbc70b6c091ae00", - "tag": "v1.0.3v3", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "83d14cb6c7c48af2a83bc326353ee6b9abdd74cfe47ba567de1cb564da65e8e9", - "tag": "v1.0.3v3-patched", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "770b30aaa0be884ee8621859f5d055437f894a5c9c7ca22635e7024e059857b7", - "tag": "v1.0.4", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "fc4e5c4dc2e5127b6814a3f69424c936f1dc241d1daf2c5a2d8f0728eb69d20d", - "tag": "v1.0.4-patched", - "upgradable": true, - "upgradeSkipable": false - }, - { - "hash": "e45f587fb07533d832548402d0e71d8e8234881da54d86c4b699c28a6482b0ee", - "tag": "v1.1.0", - "upgradable": false, - "upgradeSkipable": true - } -] diff --git a/public/electron.js b/public/electron.js index e8afdfc..1ef7a5f 100644 --- a/public/electron.js +++ b/public/electron.js @@ -1,20 +1,39 @@ const electron = require('electron'); const app = electron.app; +const dialog = electron.dialog; +const ipcMain = electron.ipcMain; const BrowserWindow = electron.BrowserWindow; const path = require('path'); -const url = require('url'); const isDev = require('electron-is-dev'); -const usbDetect = require('usb-detection'); +const { WebUSB } = require('usb'); const { NodeWebUSBKeepKeyAdapter } = require('@shapeshiftoss/hdwallet-keepkey-nodewebusb') const { HIDKeepKeyAdapter } = require('@shapeshiftoss/hdwallet-keepkey-nodehid') const { Keyring } = require('@shapeshiftoss/hdwallet-core') -const request = require('request') +const url = require('url') +const crypto = require('crypto') +const fetch = require('./node-fetch-file-url'); -const FIRMWARE_BASE_URL = "https://static.shapeshift.com/firmware/" +const DEFAULT_MANIFEST_URL = 'https://ipfs.io/ipns/k51qzi5uqu5dlbggjzdpw8ya206zkcdmd1gmg77oqdmuhs899bgfv43lzhd5er/releases.json'; +const DEFAULT_SUPPORT_LINK = 'https://shapeshift.zendesk.com'; + +const normalizeManifestUrl = (x) => { + try { + return new URL(x); + } catch { + if (process.env.PORTABLE_EXECUTABLE_DIR) x = path.resolve(process.env.PORTABLE_EXECUTABLE_DIR, x) + return url.pathToFileURL(x); + } +} + +const FIRMWARE_MANIFEST_URL = (() => { + if (process.argv[1] === "--manifest") return normalizeManifestUrl(process.argv[2]); + if (process.env.KEEPKEY_FIRMWARE_MANIFEST) return normalizeManifestUrl(process.env.KEEPKEY_FIRMWARE_MANIFEST); + return new URL(DEFAULT_MANIFEST_URL); +})() let mainWindow; -usbDetect.startMonitoring(); +const webusb = new WebUSB({ allowAllDevices: true }) // ======================================================================================= // talking to KeepKey @@ -22,25 +41,6 @@ usbDetect.startMonitoring(); const keyring = new Keyring let webUsbAdapter, hidAdapter -const bootloaderHashToVersion = { - '6397c446f6b9002a8b150bf4b9b4e0bb66800ed099b881ca49700139b0559f10': 'v1.0.0', - 'f13ce228c0bb2bdbc56bdcb5f4569367f8e3011074ccc63331348deb498f2d8f': 'v1.0.0', - 'd544b5e06b0c355d68b868ac7580e9bab2d224a1e2440881cc1bca2b816752d5': 'v1.0.1', - 'ec618836f86423dbd3114c37d6e3e4ffdfb87d9e4c6199cf3e163a67b27498a2': 'v1.0.1', - 'cd702b91028a2cfa55af43d3407ba0f6f752a4a2be0583a172983b303ab1032e': 'v1.0.2', - 'bcafb38cd0fbd6e2bdbea89fb90235559fdda360765b74e4a8758b4eff2d4921': 'v1.0.2', - 'cb222548a39ff6cbe2ae2f02c8d431c9ae0df850f814444911f521b95ab02f4c': 'v1.0.3', - '917d1952260c9b89f3a96bea07eea4074afdcc0e8cdd5d064e36868bdd68ba7d': 'v1.0.3', - '6465bc505586700a8111c4bf7db6f40af73e720f9e488d20db56135e5a690c4f': 'v1.0.3', - 'db4bc389335e876e942ae3b12558cecd202b745903e79b34dd2c32532708860e': 'v1.0.3', - '2e38950143cf350345a6ddada4c0c4f21eb2ed337309f39c5dbc70b6c091ae00': 'v1.0.3', - '83d14cb6c7c48af2a83bc326353ee6b9abdd74cfe47ba567de1cb564da65e8e9': 'v1.0.3', - '770b30aaa0be884ee8621859f5d055437f894a5c9c7ca22635e7024e059857b7': 'v1.0.4', - 'fc4e5c4dc2e5127b6814a3f69424c936f1dc241d1daf2c5a2d8f0728eb69d20d': 'v1.0.4', - 'e45f587fb07533d832548402d0e71d8e8234881da54d86c4b699c28a6482b0ee': 'v1.1.0', - '9bf1580d1b21250f922b68794cdadd6c8e166ae5b15ce160a42f8c44a2f05936': 'v2.0.0', -} - const atob = str => Buffer.from(str, 'base64').toString('binary'); const base64toHEX = (base64) => { @@ -60,30 +60,17 @@ const sleep = (millis) => (new Promise((resolve, reject) => { setTimeout(resolve, millis) })) -const normalizeWebUsbFeatures = (features) => { +const normalizeFeatures = async (features) => { if (!features) return null - const { majorVersion, minorVersion, patchVersion, bootloaderHash } = features - const decodedHash = base64toHEX(bootloaderHash) + const { bootloaderHash, firmwareHash } = features + const decodedBootloaderHash = bootloaderHash && base64toHEX(bootloaderHash) + const decodedFirmwareHash = firmwareHash && base64toHEX(firmwareHash) + const hashes = (await getFirmwareData().catch(() => undefined)).hashes return { ...features, - firmwareVersion: `v${majorVersion}.${minorVersion}.${patchVersion}`, - bootloaderVersion: bootloaderHashToVersion[decodedHash] - } -} - -const normalizeHidFeatures = (features) => { - if (!features) return null - const { bootloaderHash, bootloaderMode } = features - const decodedHash = base64toHEX(bootloaderHash) - const normedFeatures = { - ...features, - bootloaderVersion: bootloaderHashToVersion[decodedHash] + firmwareVersion: hashes?.firmware?.[decodedFirmwareHash] ?? "Unknown", + bootloaderVersion: hashes?.bootloader?.[decodedBootloaderHash] ?? "Unknown" } - if (!bootloaderMode) { - const { majorVersion, minorVersion, patchVersion, bootloaderHash } = features - normedFeatures.firmwareVersion = `v${majorVersion}.${minorVersion}.${patchVersion}` - } - return normedFeatures } const createWebUsbWallet = async (attempts = 0) => { @@ -104,9 +91,7 @@ const createWebUsbWallet = async (attempts = 0) => { const createHidWallet = async (attempts = 0) => { try { hidAdapter = await HIDKeepKeyAdapter.useKeyring(keyring) - await hidAdapter.initialize() - const wallet = keyring.get() - if (!wallet) throw 'No wallet in the keyring' + const wallet = await hidAdapter.pairDevice() return wallet } catch (error) { if (attempts < 10) { @@ -122,9 +107,11 @@ const uploadToDevice = async (binary) => { try { const wallet = Object.values(keyring.wallets)[0] if (!wallet) return null + if (!firmwareIsValid(binary)) throw new Error("firmware binary not valid"); await wallet.firmwareErase() - const uploadResult = await wallet.firmwareUpload(binary) - return uploadResult + mainWindow.webContents.send("update-status", "UPLOAD_IN_PROGRESS") + await wallet.firmwareUpload(binary) + return true } catch (error) { console.log('error uploading to device: ', error) return false @@ -138,7 +125,7 @@ const wipeDevice = async () => { const result = await wallet.wipe() return result } catch (error) { - console.log('error uploading to device: ', error) + console.log('error wiping device: ', error) return false } } @@ -146,92 +133,111 @@ const wipeDevice = async () => { // ======================================================================================= // talking to S3 Bucket -let latestFirmwareData, firmwareBinary, blupdaterBinary +let firmwareDataPromise, firmwareBinaryPromise, blupdaterBinaryPromise -const getLatestFirmwareData = async () => { - return new Promise((resolve, reject) => { - request(`${FIRMWARE_BASE_URL}releases.json`, (err, response, body) => { - if(err) return reject(err) - resolve(JSON.parse(body).latest) - }) - }) +const getFirmwareData = async () => { + if (!firmwareDataPromise) { + firmwareDataPromise = fetch(FIRMWARE_MANIFEST_URL).then(x => x.json()) + firmwareDataPromise.then(() => console.log('firmware data loaded')) + } + return await firmwareDataPromise } -const setTempFirmware = async () => { - if(!latestFirmwareData) return - const path = latestFirmwareData.firmware.url - try { - firmwareBinary = await getBinary(path) - } catch (err) { - console.log({ err }) - mainWindow.webContents.send('error', 'ERROR FETCHING FIRMWARE'); +const getFirmwareBinary = async () => { + if (!firmwareBinaryPromise) { + firmwareBinaryPromise = (async () => { + try { + const fwData = await getFirmwareData() + const path = fwData.latest.firmware.url + const hash = fwData.latest.firmware.hash + const firmwareBinary = await getBinary(path) + if (hash && crypto.createHash("sha256").update(firmwareBinary).digest().toString("hex") !== hash) { + throw new Error("hash mismatch"); + } + return firmwareBinary + } catch (err) { + console.log({ err }) + mainWindow.webContents.send('error', 'ERROR FETCHING FIRMWARE'); + throw err + } + })(); + firmwareBinaryPromise.then(() => console.log('firmware binary loaded')) } + return await firmwareBinaryPromise } -const setTempBlupdater = async () => { - if(!latestFirmwareData) return - const path = latestFirmwareData.bootloader.url - try { - blupdaterBinary = await getBinary(path) - } catch (err) { - console.log({ err }) - mainWindow.webContents.send('error', 'ERROR FETCHING BOOTLOADER'); +const getBlupdaterBinary = async () => { + if (!blupdaterBinaryPromise) { + blupdaterBinaryPromise = (async () => { + try { + const fwData = await getFirmwareData() + const path = fwData.latest.bootloader.url + const hash = fwData.latest.bootloader.hash + const blupdaterBinary = await getBinary(path) + if (hash && crypto.createHash("sha256").update(blupdaterBinary).digest().toString("hex") !== hash) { + throw new Error("hash mismatch"); + } + return blupdaterBinary + } catch (err) { + console.log({ err }) + mainWindow.webContents.send('error', 'ERROR FETCHING BOOTLOADER'); + throw err + } + })() + blupdaterBinaryPromise.then(() => console.log('blupdater binary loaded')) } + return await blupdaterBinaryPromise +} + +const firmwareIsValid = (buf) => { + return !!buf + && buf.slice(0x0000, 0x0004).toString() === 'KPKY' // check for 'magic' bytes + && buf.slice(0x0004, 0x0008).readUInt32LE() === buf.length - 256 // check firmware length - metadata + && buf.slice(0x000B, 0x000C).readUInt8() & 0x01 // check that flag is not set to wipe device } const getBinary = async (path) => { - return new Promise((resolve, reject) => { - request({ - url: FIRMWARE_BASE_URL + path, - headers: { - accept: 'application/octet-stream', - }, - encoding: null - }, (err, response, body) => { - if(err) return reject(err) - if(response.statusCode !== 200) return reject('Unable to fetch latest firmware') - const firmwareIsValid = !!body - && body.slice(0x0000, 0x0004).toString() === 'KPKY' // check for 'magic' bytes - && body.slice(0x0004, 0x0008).readUInt32LE() === body.length - 256 // check firmware length - metadata - && body.slice(0x000B, 0x000C).readUInt8() & 0x01 // check that flag is not set to wipe device - if(!firmwareIsValid) return reject('Fetched data is not valid firmware') - resolve(body) - }) + const res = await fetch(new URL(path, FIRMWARE_MANIFEST_URL), { + headers: { + accept: 'application/octet-stream' + } }) + if (!res.ok) throw new Error('Unable to fetch latest firmware') + const body = Buffer.from(await res.arrayBuffer()) + if(!firmwareIsValid(body)) throw new Error('Fetched data is not valid firmware') + return body } // ======================================================================================= // usb dis/connect listeners -usbDetect.on('add:11044:1', async function(device) { - mainWindow.webContents.send('connecting', true) - const wallet = await createHidWallet() - const features = wallet ? wallet.features : null - mainWindow.webContents.send('features', normalizeHidFeatures(features)) - mainWindow.webContents.send('connecting', false) -}); - -usbDetect.on('remove:11044:1', function(device) { - keyring.removeAll() - mainWindow.webContents.send('features', null); - mainWindow.webContents.send('connecting', false); -}); - -usbDetect.on('add:11044:2', async function(device) { - mainWindow.webContents.send('connecting', true) - const wallet = await createWebUsbWallet() - mainWindow.webContents.send('connecting', false) - const features = wallet ? wallet.features : null - mainWindow.webContents.send('features', normalizeWebUsbFeatures(features)) -}); +webusb.addEventListener("connect", async (ev) => { + try { + const device = ev.device + if (device.vendorId !== 0x2b24) return + if (![0x0001, 0x0002].includes(device.productId)) return + mainWindow.webContents.send('connecting', true) + const wallet = (device.productId === 0x0001 ? await createHidWallet() : await createWebUsbWallet()); + const features = wallet ? wallet.features : null + mainWindow.webContents.send('features', await normalizeFeatures(features)) + mainWindow.webContents.send('connecting', false) + } catch (e) { + console.error("USB connection handler error", e) + mainWindow.webContents.send('update-status', 'FAILED'); + } +}) -usbDetect.on('remove:11044:2', async function(device) { - const wallet = Object.values(keyring.wallets)[0] - if (!!wallet) wallet.transport.disconnect() - await keyring.removeAll() - webUsbAdapter.clearDevices() - mainWindow.webContents.send('features', null) - mainWindow.webContents.send('connecting', false) +webusb.addEventListener("disconnect", async (ev) => { + try { + const wallet = Object.values(keyring.wallets)[0] + if (!!wallet) wallet.transport.disconnect() + await keyring.removeAll() + mainWindow.webContents.send('features', null); + mainWindow.webContents.send('connecting', false); + } catch (e) { + console.error("USB disconnection handler error", e) + mainWindow.webContents.send('update-status', 'FAILED'); + } }); // ======================================================================================= @@ -239,19 +245,24 @@ usbDetect.on('remove:11044:2', async function(device) { electron.ipcMain.on('app-start', async (event, arg) => { try { - latestFirmwareData = await getLatestFirmwareData(); - mainWindow.webContents.send('latest', latestFirmwareData); - let connectedDeviceProductId - await usbDetect.find(0x2b24, function(err, foundDevices) { connectedDeviceProductId = foundDevices.length ? foundDevices[0].productId : null }) + mainWindow.webContents.send('app-version', `v${app.getVersion()}`); + const [ firmwareData ] = await Promise.all([getFirmwareData(), getFirmwareBinary(), getBlupdaterBinary()]) + mainWindow.webContents.send('firmware-data', firmwareData); + const connectedDeviceProductId = await webusb.requestDevice({ + filters: [ + { vendorId: 0x2b24, productId: 0x0001 }, + { vendorId: 0x2b24, productId: 0x0002 }, + ] + }).then(x => x.productId, () => null) let features, wallet switch (connectedDeviceProductId) { case 1: wallet = await createHidWallet() - features = wallet ? normalizeHidFeatures(wallet.features) : null + features = wallet ? await normalizeFeatures(wallet.features) : null break case 2: wallet = await createWebUsbWallet() - features = wallet ? normalizeWebUsbFeatures(wallet.features) : null + features = wallet ? await normalizeFeatures(wallet.features) : null break default: features = null @@ -260,13 +271,14 @@ electron.ipcMain.on('app-start', async (event, arg) => { } catch (error) { console.log('failed to fetch firmware info or binaries: ', error) mainWindow.webContents.send('error', 'ERROR FETCHING RELEASE DATA'); + mainWindow.webContents.send('firmware-data', {}); } mainWindow.webContents.send('connecting', false) }); electron.ipcMain.on('update-required', async (event, updateRequired) => { - if (updateRequired.bootloader && !blupdaterBinary) await setTempBlupdater() - if (updateRequired.firmware && !firmwareBinary) await setTempFirmware() + if (updateRequired.bootloader) await getBlupdaterBinary().catch(() => undefined) + if (updateRequired.firmware) await getFirmwareBinary().catch(() => undefined) }) electron.ipcMain.on('wipe-keepkey', async (event, updateRequired) => { @@ -275,17 +287,20 @@ electron.ipcMain.on('wipe-keepkey', async (event, updateRequired) => { type: 'question', buttons: ['cancel', 'wipe device'], defaultId: 2, - title: 'Question', - message: 'To reset your device\'s pin, you must wipe and continue.', + title: 'Reset Device', + message: 'To remove your PIN, you must reset your device to factory settings.', detail: 'This will WIPE your device!', checkboxLabel: 'I have my recovery phrase', - checkboxChecked: true, + checkboxChecked: false, }; - electron.dialog.showMessageBox(null, options, (response, checkboxChecked) => { - if(response === 1 && checkboxChecked){ - wipeDevice() + const msgBoxResp = await electron.dialog.showMessageBox(null, options) + if (msgBoxResp.response === 1){ + if (msgBoxResp.checkboxChecked) { + await wipeDevice() + } else { + electron.dialog.showErrorBox('Reset Device', 'Confirm that you have your recovery phrase available before wiping your device.') } - }); + } } catch(err) { console.error('failed to wipe device: ', err); mainWindow.webContents.send('update-status', 'FAILED'); @@ -294,73 +309,129 @@ electron.ipcMain.on('wipe-keepkey', async (event, updateRequired) => { electron.ipcMain.on('update-firmware', async (event, arg) => { try { - if(!firmwareBinary) await setTempFirmware() + const firmwareBinary = await getFirmwareBinary() const updateResponse = await uploadToDevice(firmwareBinary) if(updateResponse) { mainWindow.webContents.send('update-status', 'FIRMWARE_UPDATE_SUCCESS'); } else { - mainWindow.webContents.send('update-status', 'FIRMWARE_UPDATE_SUCCESS'); - // mainWindow.webContents.send('update-status', 'FAILED'); + mainWindow.webContents.send('update-status', 'FAILED'); } } catch(err) { - console.log('failed to upload binary to device: ', err); + console.error('failed to upload firmware to device: ', err); mainWindow.webContents.send('update-status', 'FAILED'); } }); electron.ipcMain.on('update-bootloader', async (event, arg) => { try { - if(!blupdaterBinary) await setTempBlupdater() + const blupdaterBinary = await getBlupdaterBinary() const updateResponse = await uploadToDevice(blupdaterBinary) if(updateResponse) { mainWindow.webContents.send('update-status', 'BOOTLOADER_UPDATE_SUCCESS'); } else { - // mainWindow.webContents.send('update-status', 'FAILED'); - mainWindow.webContents.send('update-status', 'BOOTLOADER_UPDATE_SUCCESS'); + mainWindow.webContents.send('update-status', 'FAILED'); } - } catch(err) { + } catch (err) { + console.error('failed to upload bootloader to device: ', err); mainWindow.webContents.send('update-status', 'FAILED'); } }); +electron.ipcMain.on('update-custom', async (event, arg) => { + try { + const { filePaths: customBinaryPaths } = await dialog.showOpenDialog({ + filters: [{ name: "Firmware Images", extensions: ["bin"] }], + properties: ["openFile", "dontAddToRecent"], + }); + const customBinaryPath = customBinaryPaths[0]; + if (!customBinaryPath) throw new Error("no file selected"); + const customBinary = Buffer.from(await (await fetch(url.pathToFileURL(customBinaryPath))).arrayBuffer()); + if (!firmwareIsValid(customBinary)) throw new Error("the selected file is not a valid firmware image"); + const updateResponse = await uploadToDevice(customBinary) + if (updateResponse) { + mainWindow.webContents.send('update-status', 'CUSTOM_UPDATE_SUCCESS'); + } else { + mainWindow.webContents.send('update-status', 'FAILED'); + } + } catch (err) { + console.error('failed to upload custom binary to device: ', err); + mainWindow.webContents.send('update-status', 'FAILED'); + } +}); -electron.ipcMain.on('close-application', async (event, arg) => { +const closeApp = async () => { try { const wallet = Object.values(keyring.wallets)[0] if (!!wallet) wallet.transport.disconnect() await keyring.removeAll() - webUsbAdapter.clearDevices() app.quit() } catch(err) { console.log('Error closing application: ', err) } +} + +electron.ipcMain.on('close-application', async (event, arg) => { + await closeApp() +}); + +electron.ipcMain.on('go-to-app', async (event, arg) => { + const link = (await getFirmwareData())?.links?.app + if (link && link.startsWith('https://')) await electron.shell.openExternal(link) + await closeApp() +}); + +electron.ipcMain.on('get-help', async (event, arg) => { + const link = (await getFirmwareData().catch(() => undefined))?.links?.support ?? DEFAULT_SUPPORT_LINK + if (link && link.startsWith('https://')) await electron.shell.openExternal(link) +}); + +electron.ipcMain.on('update-updater', async (event, arg) => { + const link = (await getFirmwareData().catch(() => undefined))?.links?.updater + if (link && link.startsWith('https://')) { + await electron.shell.openExternal(link) + await closeApp() + } }); // ======================================================================================= // app creation async function createWindow() { - mainWindow = new BrowserWindow({ width: 407, height: 525, title: '', resizable: isDev }); - mainWindow.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}`); + if (!isDev) electron.Menu.setApplicationMenu(electron.Menu.buildFromTemplate([])); + mainWindow = new BrowserWindow({ + width: 407, + height: 525, + title: 'KeepKey Updater', + resizable: isDev, + autoHideMenuBar: true, + show: false, + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + enableRemoteModule: false, + webSecurity: true, + }, + }); + if (!isDev) { + mainWindow.removeMenu(); + } + const bundledIndexPath = `file://${path.join(__dirname, '../build/index.html')}`; mainWindow.on('closed', () => mainWindow = null); + mainWindow.on('ready-to-show', () => mainWindow.show()); + await mainWindow.loadURL(isDev ? 'http://localhost:3000' : bundledIndexPath).catch(() => mainWindow.loadURL(bundledIndexPath)); } app.on('ready', createWindow); app.on('before-quit', () => { - usbDetect.stopMonitoring(); - webUsbAdapter.clearDevices() - const { ipcMain } = electron; ipcMain.removeAllListeners('app-start'); ipcMain.removeAllListeners('update-firmware'); ipcMain.removeAllListeners('update-bootloader'); - ipcMain.removeAllListeners('set-policy'); + ipcMain.removeAllListeners('update-custom'); }); app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit(); - } + app.quit(); }); app.on('activate', () => { diff --git a/public/fonts/Open+Sans_300_normal.ttf b/public/fonts/Open+Sans_300_normal.ttf new file mode 100644 index 0000000..7b2527f Binary files /dev/null and b/public/fonts/Open+Sans_300_normal.ttf differ diff --git a/public/fonts/Open+Sans_300_normal.woff b/public/fonts/Open+Sans_300_normal.woff new file mode 100644 index 0000000..a58383c Binary files /dev/null and b/public/fonts/Open+Sans_300_normal.woff differ diff --git a/public/fonts/Open+Sans_300_normal.woff2 b/public/fonts/Open+Sans_300_normal.woff2 new file mode 100644 index 0000000..b7c278a Binary files /dev/null and b/public/fonts/Open+Sans_300_normal.woff2 differ diff --git a/public/fonts/Open+Sans_400_italic.ttf b/public/fonts/Open+Sans_400_italic.ttf new file mode 100644 index 0000000..0280f59 Binary files /dev/null and b/public/fonts/Open+Sans_400_italic.ttf differ diff --git a/public/fonts/Open+Sans_400_italic.woff b/public/fonts/Open+Sans_400_italic.woff new file mode 100644 index 0000000..d0eed76 Binary files /dev/null and b/public/fonts/Open+Sans_400_italic.woff differ diff --git a/public/fonts/Open+Sans_400_italic.woff2 b/public/fonts/Open+Sans_400_italic.woff2 new file mode 100644 index 0000000..10a17f0 Binary files /dev/null and b/public/fonts/Open+Sans_400_italic.woff2 differ diff --git a/public/fonts/Open+Sans_400_normal.eot b/public/fonts/Open+Sans_400_normal.eot new file mode 100644 index 0000000..db23175 Binary files /dev/null and b/public/fonts/Open+Sans_400_normal.eot differ diff --git a/public/fonts/Open+Sans_400_normal.svg b/public/fonts/Open+Sans_400_normal.svg new file mode 100644 index 0000000..f6bfcca --- /dev/null +++ b/public/fonts/Open+Sans_400_normal.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/Open+Sans_400_normal.ttf b/public/fonts/Open+Sans_400_normal.ttf new file mode 100644 index 0000000..8c84a84 Binary files /dev/null and b/public/fonts/Open+Sans_400_normal.ttf differ diff --git a/public/fonts/Open+Sans_400_normal.woff b/public/fonts/Open+Sans_400_normal.woff new file mode 100644 index 0000000..796d9f3 Binary files /dev/null and b/public/fonts/Open+Sans_400_normal.woff differ diff --git a/public/fonts/Open+Sans_400_normal.woff2 b/public/fonts/Open+Sans_400_normal.woff2 new file mode 100644 index 0000000..6354811 Binary files /dev/null and b/public/fonts/Open+Sans_400_normal.woff2 differ diff --git a/public/fonts/Open+Sans_600_italic.ttf b/public/fonts/Open+Sans_600_italic.ttf new file mode 100644 index 0000000..2e8c8b3 Binary files /dev/null and b/public/fonts/Open+Sans_600_italic.ttf differ diff --git a/public/fonts/Open+Sans_600_italic.woff b/public/fonts/Open+Sans_600_italic.woff new file mode 100644 index 0000000..0edade0 Binary files /dev/null and b/public/fonts/Open+Sans_600_italic.woff differ diff --git a/public/fonts/Open+Sans_600_italic.woff2 b/public/fonts/Open+Sans_600_italic.woff2 new file mode 100644 index 0000000..72698e8 Binary files /dev/null and b/public/fonts/Open+Sans_600_italic.woff2 differ diff --git a/public/fonts/Open+Sans_600_normal.ttf b/public/fonts/Open+Sans_600_normal.ttf new file mode 100644 index 0000000..6e22df8 Binary files /dev/null and b/public/fonts/Open+Sans_600_normal.ttf differ diff --git a/public/fonts/Open+Sans_600_normal.woff b/public/fonts/Open+Sans_600_normal.woff new file mode 100644 index 0000000..6ad677a Binary files /dev/null and b/public/fonts/Open+Sans_600_normal.woff differ diff --git a/public/fonts/Open+Sans_600_normal.woff2 b/public/fonts/Open+Sans_600_normal.woff2 new file mode 100644 index 0000000..d3eaed3 Binary files /dev/null and b/public/fonts/Open+Sans_600_normal.woff2 differ diff --git a/public/fonts/Open+Sans_800_normal.ttf b/public/fonts/Open+Sans_800_normal.ttf new file mode 100644 index 0000000..a3fcf33 Binary files /dev/null and b/public/fonts/Open+Sans_800_normal.ttf differ diff --git a/public/fonts/Open+Sans_800_normal.woff b/public/fonts/Open+Sans_800_normal.woff new file mode 100644 index 0000000..21fcda1 Binary files /dev/null and b/public/fonts/Open+Sans_800_normal.woff differ diff --git a/public/fonts/Open+Sans_800_normal.woff2 b/public/fonts/Open+Sans_800_normal.woff2 new file mode 100644 index 0000000..1806943 Binary files /dev/null and b/public/fonts/Open+Sans_800_normal.woff2 differ diff --git a/public/fonts/fonts.css b/public/fonts/fonts.css new file mode 100644 index 0000000..8c09b50 --- /dev/null +++ b/public/fonts/fonts.css @@ -0,0 +1,72 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: url(Open+Sans_400_normal.eot); /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVY.eot */ + src: local('☺'), + url(Open+Sans_400_normal.eot?#iefix) format('embedded-opentype'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVY.eot */ + url(Open+Sans_400_normal.woff2) format('woff2'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVI.woff2 */ + url(Open+Sans_400_normal.woff) format('woff'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVQ.woff */ + url(Open+Sans_400_normal.ttf) format('truetype'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVcUwaEQXjM.ttf */ + url(Open+Sans_400_normal.svg#Open+Sans_400_normal) format('svg'); /* http://fonts.gstatic.com/l/font?kit=memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVU&skey=62c1cbfccc78b4b2&v=v28#OpenSans */ +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: url(Open+Sans_400_italic.eot); /* {{embedded-opentype-gf-url}} */ + src: local('☺'), + url(Open+Sans_400_italic.eot?#iefix) format('embedded-opentype'), /* {{embedded-opentype-gf-url}} */ + url(Open+Sans_400_italic.woff2) format('woff2'), /* http://fonts.gstatic.com/s/opensans/v28/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk8ZkWVAewA.woff2 */ + url(Open+Sans_400_italic.woff) format('woff'), /* http://fonts.gstatic.com/s/opensans/v28/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk8ZkWVAexg.woff */ + url(Open+Sans_400_italic.ttf) format('truetype'), /* http://fonts.gstatic.com/s/opensans/v28/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk8ZkWVAexYMUdjFnmg.ttf */ + url(Open+Sans_400_italic.svg#Open+Sans_400_italic) format('svg'); /* {{svg-gf-url}} */ +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 600; + src: url(Open+Sans_600_italic.eot); /* {{embedded-opentype-gf-url}} */ + src: local('☺'), + url(Open+Sans_600_italic.eot?#iefix) format('embedded-opentype'), /* {{embedded-opentype-gf-url}} */ + url(Open+Sans_600_italic.woff2) format('woff2'), /* http://fonts.gstatic.com/s/opensans/v28/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0RkxhjWVAewA.woff2 */ + url(Open+Sans_600_italic.woff) format('woff'), /* http://fonts.gstatic.com/s/opensans/v28/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0RkxhjWVAexg.woff */ + url(Open+Sans_600_italic.ttf) format('truetype'), /* http://fonts.gstatic.com/s/opensans/v28/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0RkxhjWVAexYMUdjFnmg.ttf */ + url(Open+Sans_600_italic.svg#Open+Sans_600_italic) format('svg'); /* {{svg-gf-url}} */ +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: url(Open+Sans_300_normal.eot); /* {{embedded-opentype-gf-url}} */ + src: local('☺'), + url(Open+Sans_300_normal.eot?#iefix) format('embedded-opentype'), /* {{embedded-opentype-gf-url}} */ + url(Open+Sans_300_normal.woff2) format('woff2'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0B4gaVI.woff2 */ + url(Open+Sans_300_normal.woff) format('woff'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0B4gaVQ.woff */ + url(Open+Sans_300_normal.ttf) format('truetype'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0B4gaVcUwaEQXjM.ttf */ + url(Open+Sans_300_normal.svg#Open+Sans_300_normal) format('svg'); /* {{svg-gf-url}} */ +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: url(Open+Sans_600_normal.eot); /* {{embedded-opentype-gf-url}} */ + src: local('☺'), + url(Open+Sans_600_normal.eot?#iefix) format('embedded-opentype'), /* {{embedded-opentype-gf-url}} */ + url(Open+Sans_600_normal.woff2) format('woff2'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsgH1x4gaVI.woff2 */ + url(Open+Sans_600_normal.woff) format('woff'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsgH1x4gaVQ.woff */ + url(Open+Sans_600_normal.ttf) format('truetype'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsgH1x4gaVcUwaEQXjM.ttf */ + url(Open+Sans_600_normal.svg#Open+Sans_600_normal) format('svg'); /* {{svg-gf-url}} */ +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: url(Open+Sans_800_normal.eot); /* {{embedded-opentype-gf-url}} */ + src: local('☺'), + url(Open+Sans_800_normal.eot?#iefix) format('embedded-opentype'), /* {{embedded-opentype-gf-url}} */ + url(Open+Sans_800_normal.woff2) format('woff2'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgshZ1x4gaVI.woff2 */ + url(Open+Sans_800_normal.woff) format('woff'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgshZ1x4gaVQ.woff */ + url(Open+Sans_800_normal.ttf) format('truetype'), /* http://fonts.gstatic.com/s/opensans/v28/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgshZ1x4gaVcUwaEQXjM.ttf */ + url(Open+Sans_800_normal.svg#Open+Sans_800_normal) format('svg'); /* {{svg-gf-url}} */ +} diff --git a/public/index.html b/public/index.html index caac468..20f97d5 100644 --- a/public/index.html +++ b/public/index.html @@ -19,7 +19,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - +