Merge pull request #615 from Hinton/hotfix/multiple-extensions

Native Messaging - Support multiple extensions concurrently
This commit is contained in:
Chad Scharf 2020-12-22 10:54:58 -05:00 committed by GitHub
commit 76c040aff9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 286 additions and 226 deletions

View File

@ -26,6 +26,18 @@ npm install
npm run electron
```
**Debug Native Messaging**
Native Messaging (communication with the browser extension) works by having the browser start a lightweight proxy application baked into our desktop binary. To setup an environment which allows
for easy debugging you will need to build the application for distribution, i.e. `npm run dist:<platform>`, start the dist version and enable desktop integration. This will write some manifests
to disk, Consult the [native manifests](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Manifest_location) documentation for more details of the manigest
format, and the exact locations for the different platforms. *Note* that disabling the desktop integration will delete the manifests, and the files will need to be updated again.
The generated manifests are pre-configured with the production ID for the browser extensions. In order to use them with the development builds, the browser extension ID of the development build
needs to be added to the `allowed_extensions` section of the manifest. These IDs are generated by the browser, and can be found in the extension settings within the browser.
It will then be possible to run the desktop application as usual using `npm run electron` and communicate with the browser.
# Contribute
Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [`CONTRIBUTING.md`](CONTRIBUTING.md) file.

2
jslib

@ -1 +1 @@
Subproject commit acdbc229533a4f5f57b83b882ce48037a8a17299
Subproject commit 12321e53b9199e1b4dd4653948b924f1a2b31efc

336
package-lock.json generated
View File

@ -11,9 +11,9 @@
"dev": true
},
"@angular-devkit/core": {
"version": "9.1.12",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.1.12.tgz",
"integrity": "sha512-D/GnBeSlmdgGn7EhuE32HuPuRAjvUuxi7Q6WywBI8PSsXKAGnrypghBwMATNnOA24//CgbW2533Y9VWHaeXdeA==",
"version": "9.1.13",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.1.13.tgz",
"integrity": "sha512-bwehVRsva9OWfh/yuEh9VU+0Gr1T7DHJLe8tpZk/VsIkGOD0IszEPZOIEK23bg32yiff9bh6qJEPMA7ZBYEQHg==",
"dev": true,
"requires": {
"ajv": "6.12.3",
@ -69,9 +69,9 @@
"dev": true
},
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
}
@ -100,9 +100,9 @@
"integrity": "sha512-suefk0OFkaJpUUKnV+phbL4T8fmVGHvzkereY5eqybQlumOez8NPL1PJcygAylh/E6OIAYm8SWookYwM6ZY9dg=="
},
"@angular/compiler-cli": {
"version": "9.1.12",
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.1.12.tgz",
"integrity": "sha512-bbqJ+fbY+aQejSYuHUjE1qYJCXkZBM5Hru9eN7m/j376u83MQ5jWdC290uYx+ipsXcPTa/YRZ44jpL+5cCzIrg==",
"version": "9.1.13",
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.1.13.tgz",
"integrity": "sha512-40jbfMr1FinOqUyG3k4Moiytjs/Z8zKBgP3S5Qfn80EBJItRdFXwNtvaOi/onaag4+Mv+vigShwsgCewLbt/kA==",
"dev": true,
"requires": {
"canonical-path": "1.0.0",
@ -116,7 +116,7 @@
"semver": "^6.3.0",
"source-map": "^0.6.1",
"sourcemap-codec": "^1.4.8",
"yargs": "15.3.0"
"yargs": "^16.1.1"
},
"dependencies": {
"ansi-regex": {
@ -126,30 +126,23 @@
"dev": true
},
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
"wrap-ansi": "^7.0.0"
}
},
"color-convert": {
@ -173,16 +166,6 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"fs-extra": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz",
@ -206,51 +189,6 @@
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@ -278,9 +216,9 @@
}
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
@ -288,34 +226,32 @@
"strip-ansi": "^6.0.0"
}
},
"y18n": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",
"integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==",
"dev": true
},
"yargs": {
"version": "15.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.0.tgz",
"integrity": "sha512-g/QCnmjgOl1YJjGsnUg2SatC7NUYEiLXJqxNOQU9qSpjzGtGXda9b+OKccr1kLTy8BN9yqEyqfq5lxlwdc13TA==",
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"requires": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.0"
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
},
"yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
"version": "20.2.4",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
"dev": true
}
}
},
@ -544,12 +480,12 @@
}
},
"@ngtools/webpack": {
"version": "9.1.12",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.1.12.tgz",
"integrity": "sha512-lypMXIq5oxBMsoDu/VOa1yUmmXthhxkCJa8LG0ZohfnbwhmZvz3SAW7omBGuVrb5cVIfLCkaRCSnQ1MNc6ULXw==",
"version": "9.1.13",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.1.13.tgz",
"integrity": "sha512-mTygcNgr58Mpv+WVrkXe3QXZJO5RKUEDcMoj0bscBp9G62MiMsRKnkDjb5GSXXnSGZb5GOlzdVwayib1O5y3uQ==",
"dev": true,
"requires": {
"@angular-devkit/core": "9.1.12",
"@angular-devkit/core": "9.1.13",
"enhanced-resolve": "4.1.1",
"rxjs": "6.5.4",
"webpack-sources": "1.4.3"
@ -586,9 +522,9 @@
}
},
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"webpack-sources": {
@ -661,9 +597,9 @@
"dev": true
},
"@types/node": {
"version": "10.17.35",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.35.tgz",
"integrity": "sha512-gXx7jAWpMddu0f7a+L+txMplp3FnHl53OhQIF9puXKq3hDGY/GjH+MF04oWnV/adPSCrbtHumDCFwzq2VhltWA==",
"version": "10.17.49",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.49.tgz",
"integrity": "sha512-PGaJNs5IZz5XgzwJvL/1zRfZB7iaJ5BydZ8/Picm+lUNYoNO9iVTQkVy5eUh0dZDrx3rBOIs3GCbCRmMuYyqwg==",
"dev": true
},
"@types/node-forge": {
@ -1761,6 +1697,14 @@
"integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=",
"dev": true
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bl": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
@ -2400,9 +2344,9 @@
"dev": true
},
"chokidar": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz",
"integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==",
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
"dev": true,
"requires": {
"anymatch": "~3.1.1",
@ -2412,7 +2356,7 @@
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.4.0"
"readdirp": "~3.5.0"
},
"dependencies": {
"anymatch": {
@ -2449,13 +2393,6 @@
"to-regex-range": "^5.0.1"
}
},
"fsevents": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
"dev": true,
"optional": true
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
@ -2486,15 +2423,6 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
"readdirp": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
"integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
"dev": true,
"requires": {
"picomatch": "^2.2.1"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -3774,6 +3702,14 @@
"@types/node": "^10.12.18",
"electron-download": "^4.1.0",
"extract-zip": "^1.0.3"
},
"dependencies": {
"@types/node": {
"version": "10.17.49",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.49.tgz",
"integrity": "sha512-PGaJNs5IZz5XgzwJvL/1zRfZB7iaJ5BydZ8/Picm+lUNYoNO9iVTQkVy5eUh0dZDrx3rBOIs3GCbCRmMuYyqwg==",
"dev": true
}
}
},
"electron-builder": {
@ -4861,6 +4797,12 @@
"es6-symbol": "^3.1.1"
}
},
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"dev": true
},
"escape-goat": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
@ -5246,6 +5188,11 @@
}
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"filelist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz",
@ -5650,6 +5597,15 @@
"integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
"dev": true
},
"forcefocus": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/forcefocus/-/forcefocus-1.1.0.tgz",
"integrity": "sha512-bnY7rul5kBLyNoCn0FHNiFAF+GGUZx6TvxWhurUS4PlmOzF+FMixGIigHH5UcyM3w1gp2TxAtP6MOUSXA15Sgw==",
"requires": {
"bindings": "^1.3.0",
"prebuild-install": "^5.0.0"
}
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@ -5745,6 +5701,13 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"fsevents": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
"dev": true,
"optional": true
},
"fstream": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
@ -9343,34 +9306,6 @@
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz",
"integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw=="
},
"node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
"integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
"dev": true,
"requires": {
"fstream": "^1.0.0",
"glob": "^7.0.3",
"graceful-fs": "^4.1.2",
"mkdirp": "^0.5.0",
"nopt": "2 || 3",
"npmlog": "0 || 1 || 2 || 3 || 4",
"osenv": "0",
"request": "^2.87.0",
"rimraf": "2",
"semver": "~5.3.0",
"tar": "^2.0.0",
"which": "1"
},
"dependencies": {
"semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
"dev": true
}
}
},
"node-ipc": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz",
@ -9512,6 +9447,35 @@
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
"dev": true
},
"node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
"integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
"dev": true,
"requires": {
"fstream": "^1.0.0",
"glob": "^7.0.3",
"graceful-fs": "^4.1.2",
"mkdirp": "^0.5.0",
"nopt": "2 || 3",
"npmlog": "0 || 1 || 2 || 3 || 4",
"osenv": "0",
"request": "^2.87.0",
"rimraf": "2",
"semver": "~5.3.0",
"tar": "^2.0.0",
"which": "1"
}
},
"nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
"dev": true,
"requires": {
"abbrev": "1"
}
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@ -9546,12 +9510,29 @@
"uuid": "^3.3.2"
}
},
"semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
"dev": true
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
},
"tar": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
"integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
"dev": true,
"requires": {
"block-stream": "*",
"fstream": "^1.0.12",
"inherits": "2"
}
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
@ -9569,15 +9550,6 @@
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
"integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI="
},
"nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
"dev": true,
"requires": {
"abbrev": "1"
}
},
"nord": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/nord/-/nord-0.2.1.tgz",
@ -10763,6 +10735,15 @@
"util-deprecate": "~1.0.1"
}
},
"readdirp": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
"dev": true,
"requires": {
"picomatch": "^2.2.1"
}
},
"recast": {
"version": "0.11.23",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz",
@ -11186,9 +11167,9 @@
},
"dependencies": {
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
@ -12021,17 +12002,6 @@
"integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==",
"dev": true
},
"tar": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
"integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
"dev": true,
"requires": {
"block-stream": "*",
"fstream": "^1.0.12",
"inherits": "2"
}
},
"tar-fs": {
"version": "1.16.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz",

View File

@ -311,6 +311,7 @@
"electron-log": "2.2.17",
"electron-store": "1.3.0",
"electron-updater": "4.3.5",
"forcefocus": "^1.1.0",
"keytar": "4.13.0",
"lunr": "2.3.3",
"node-forge": "0.7.6",

View File

@ -98,6 +98,16 @@
</div>
<small class="help-block">{{'enableBrowserIntegrationDesc' | i18n}}</small>
</div>
<div class="form-group">
<div class="checkbox">
<label for="enableBrowserIntegrationFingerprint">
<input id="enableBrowserIntegrationFingerprint" type="checkbox" name="EnableBrowserIntegrationFingerprint"
[(ngModel)]="enableBrowserIntegrationFingerprint" (change)="saveBrowserIntegrationFingerprint()" [disabled]="!enableBrowserIntegration">
{{'enableBrowserIntegrationFingerprint' | i18n}}
</label>
</div>
<small class="help-block">{{'enableBrowserIntegrationFingerprintDesc' | i18n}}</small>
</div>
<div class="form-group">
<div class="checkbox">
<label for="enableTray">

View File

@ -34,6 +34,7 @@ export class SettingsComponent implements OnInit {
pin: boolean = null;
disableFavicons: boolean = false;
enableBrowserIntegration: boolean = false;
enableBrowserIntegrationFingerprint: boolean = false;
enableMinToTray: boolean = false;
enableCloseToTray: boolean = false;
enableTray: boolean = false;
@ -150,6 +151,7 @@ export class SettingsComponent implements OnInit {
this.disableFavicons = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
this.enableBrowserIntegration = await this.storageService.get<boolean>(
ElectronConstants.enableBrowserIntegration);
this.enableBrowserIntegrationFingerprint = await this.storageService.get<boolean>(ElectronConstants.enableBrowserIntegrationFingerprint);
this.enableMinToTray = await this.storageService.get<boolean>(ElectronConstants.enableMinimizeToTrayKey);
this.enableCloseToTray = await this.storageService.get<boolean>(ElectronConstants.enableCloseToTrayKey);
this.enableTray = await this.storageService.get<boolean>(ElectronConstants.enableTrayKey);
@ -348,9 +350,27 @@ export class SettingsComponent implements OnInit {
}
async saveBrowserIntegration() {
if (process.platform ==='darwin' && !this.platformUtilsService.isMacAppStore()) {
await this.platformUtilsService.showDialog(
this.i18nService.t('browserIntegrationMasOnlyDesc'),
this.i18nService.t('browserIntegrationMasOnlyTitle'),
this.i18nService.t('ok'), null, 'warning');
this.enableBrowserIntegration = false;
return;
}
await this.storageService.save(ElectronConstants.enableBrowserIntegration, this.enableBrowserIntegration);
this.messagingService.send(
this.enableBrowserIntegration ? 'enableBrowserIntegration' : 'disableBrowserIntegration');
this.messagingService.send(this.enableBrowserIntegration ? 'enableBrowserIntegration' : 'disableBrowserIntegration');
if (!this.enableBrowserIntegration) {
this.enableBrowserIntegrationFingerprint = false;
this.saveBrowserIntegrationFingerprint();
}
}
async saveBrowserIntegrationFingerprint() {
await this.storageService.save(ElectronConstants.enableBrowserIntegrationFingerprint, this.enableBrowserIntegrationFingerprint);
}
private callAnalytics(name: string, enabled: boolean) {

View File

@ -135,7 +135,7 @@ const eventService = new EventService(storageService, apiService, userService, c
const systemService = new SystemService(storageService, vaultTimeoutService, messagingService, platformUtilsService,
null);
const nativeMessagingService = new NativeMessagingService(cryptoFunctionService, cryptoService, platformUtilsService,
logService, i18nService, userService, messagingService);
logService, i18nService, userService, messagingService, vaultTimeoutService, storageService);
const analytics = new Analytics(window, () => isDev(), platformUtilsService, storageService, appIdService);
containerService.attachToGlobal(window);

View File

@ -1453,15 +1453,33 @@
"enableBrowserIntegrationDesc": {
"message": "Browser integration is used for biometrics in browser."
},
"browserIntegrationMasOnlyTitle": {
"message": "Browser integration not supported"
},
"browserIntegrationMasOnlyDesc": {
"message": "Unfortunately browser integration is only supported in the Mac App Store version for now."
},
"enableBrowserIntegrationFingerprint": {
"message": "Require verification for browser integration"
},
"enableBrowserIntegrationFingerprintDesc": {
"message": "Enable an additional layer of security by requiring fingerprint phrase validation when establishing a link between your desktop and browser. When enabled, this requires user intervention and verification each time a connection is established."
},
"approve": {
"message": "Approve"
},
"verifyBrowserTitle": {
"message": "Verify browser connection"
},
"verifyBrowserDescription": {
"verifyBrowserDesc": {
"message": "Please ensure the shown fingerprint is identical to the fingerprint showed in the browser extension."
},
"biometricsNotEnabledTitle": {
"message": "Biometrics not enabled"
},
"biometricsNotEnabledDesc": {
"message": "Browser biometrics requires desktop biometrics to be enabled in the settings first."
},
"personalOwnershipSubmitError": {
"message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections."
},

View File

@ -114,7 +114,7 @@ export class Main {
if (process.platform === 'win32') {
const BiometricWindowsMain = require('jslib/electron/biometric.windows.main').default;
this.biometricMain = new BiometricWindowsMain(this.storageService, this.i18nService);
this.biometricMain = new BiometricWindowsMain(this.storageService, this.i18nService, this.windowMain);
} else if (process.platform === 'darwin') {
const BiometricDarwinMain = require('jslib/electron/biometric.darwin.main').default;
this.biometricMain = new BiometricDarwinMain(this.storageService, this.i18nService);

View File

@ -10,6 +10,7 @@ import { WindowMain } from 'jslib/electron/window.main';
export class NativeMessagingMain {
private connected = false;
private socket: any;
constructor(private logService: LogService, private windowMain: WindowMain, private userPath: string, private appPath: string) {}
@ -19,15 +20,16 @@ export class NativeMessagingMain {
ipc.serve(() => {
ipc.server.on('message', (data: any, socket: any) => {
// This is a ugly hack until electron is updated 7.0.0 which supports ipcMain.invoke
this.socket = socket;
this.windowMain.win.webContents.send('nativeMessaging', data);
ipcMain.once('nativeMessagingReply', (event, msg) => {
if (msg != null) {
this.send(msg, socket);
}
});
});
ipcMain.on('nativeMessagingReply', (event, msg) => {
if (this.socket != null && msg != null) {
this.send(msg, this.socket);
}
})
ipc.server.on('connect', () => {
this.connected = true;
})
@ -36,6 +38,7 @@ export class NativeMessagingMain {
'socket.disconnected',
(socket: any, destroyedSocketID: any) => {
this.connected = false;
this.socket = null;
ipc.log(
'client ' + destroyedSocketID + ' has disconnected!'
);

View File

@ -83,7 +83,11 @@ export default class NativeMessage {
chunks.push(chunk);
}
processData();
try {
processData();
} catch(e) {
console.error(e);
}
});
}
}

View File

@ -8,57 +8,67 @@ import { LogService } from 'jslib/abstractions/log.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { Utils } from 'jslib/misc/utils';
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
import { StorageService } from 'jslib/abstractions';
import { ElectronConstants } from 'jslib/electron/electronConstants';
const MessageValidTimeout = 10 * 1000;
const EncryptionAlgorithm = 'sha1';
export class NativeMessagingService {
private sharedSecret: any;
private sharedSecrets = new Map<string, SymmetricCryptoKey>();
constructor(private cryptoFunctionService: CryptoFunctionService, private cryptoService: CryptoService,
private platformUtilService: PlatformUtilsService, private logService: LogService, private i18nService: I18nService,
private userService: UserService, private messagingService: MessagingService) {
private userService: UserService, private messagingService: MessagingService, private vaultTimeoutService: VaultTimeoutService, private storageService: StorageService) {
ipcRenderer.on('nativeMessaging', async (event: any, message: any) => {
this.messageHandler(message);
});
}
private async messageHandler(rawMessage: any) {
private async messageHandler(msg: any) {
const appId = msg.appId;
const rawMessage = msg.message;
// Request to setup secure encryption
if (rawMessage.command === 'setupEncryption') {
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
const fingerprint = (await this.cryptoService.getFingerprint(await this.userService.getUserId(), remotePublicKey)).join(' ');
this.messagingService.send('setFocus');
if (await this.storageService.get<boolean>(ElectronConstants.enableBrowserIntegrationFingerprint)) {
ipcRenderer.send('nativeMessagingReply', {command: 'verifyFingerprint', appId: appId});
// Await confirmation that fingerprint is correct
const submitted = await Swal.fire({
title: this.i18nService.t('verifyBrowserTitle'),
html: `${this.i18nService.t('verifyBrowserDescription')}<br><br><strong>${fingerprint}</strong>`,
showCancelButton: true,
cancelButtonText: this.i18nService.t('cancel'),
showConfirmButton: true,
confirmButtonText: this.i18nService.t('approve'),
allowOutsideClick: false,
});
const fingerprint = (await this.cryptoService.getFingerprint(await this.userService.getUserId(), remotePublicKey)).join(' ');
if (submitted.value !== true) {
return;
this.messagingService.send('setFocus');
// Await confirmation that fingerprint is correct
const submitted = await Swal.fire({
title: this.i18nService.t('verifyBrowserTitle'),
html: `${this.i18nService.t('verifyBrowserDesc')}<br><br><strong>${fingerprint}</strong>`,
showCancelButton: true,
cancelButtonText: this.i18nService.t('cancel'),
showConfirmButton: true,
confirmButtonText: this.i18nService.t('approve'),
allowOutsideClick: false,
});
if (submitted.value !== true) {
return;
}
}
this.secureCommunication(remotePublicKey);
this.secureCommunication(remotePublicKey, appId);
return;
}
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecret));
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecrets.get(appId)));
// Shared secret is invalidated, force re-authentication
if (message == null) {
ipcRenderer.send('nativeMessagingReply', {command: 'invalidateEncryption'});
ipcRenderer.send('nativeMessagingReply', {command: 'invalidateEncryption', appId: appId});
return;
}
@ -70,14 +80,26 @@ export class NativeMessagingService {
switch (message.command) {
case 'biometricUnlock':
if (! this.platformUtilService.supportsBiometric()) {
return this.send({command: 'biometricUnlock', response: 'not supported'});
return this.send({command: 'biometricUnlock', response: 'not supported'}, appId);
}
if (! await this.vaultTimeoutService.isBiometricLockSet()) {
this.send({command: 'biometricUnlock', response: 'not enabled'}, appId);
return await Swal.fire({
title: this.i18nService.t('biometricsNotEnabledTitle'),
text: this.i18nService.t('biometricsNotEnabledDesc'),
showCancelButton: true,
cancelButtonText: this.i18nService.t('cancel'),
showConfirmButton: false,
});
}
const response = await this.platformUtilService.authenticateBiometric();
if (response) {
this.send({command: 'biometricUnlock', response: 'unlocked', keyB64: (await this.cryptoService.getKey()).keyB64});
this.send({command: 'biometricUnlock', response: 'unlocked', keyB64: (await this.cryptoService.getKey()).keyB64}, appId);
} else {
this.send({command: 'biometricUnlock', response: 'canceled'});
this.send({command: 'biometricUnlock', response: 'canceled'}, appId);
}
break;
@ -86,19 +108,19 @@ export class NativeMessagingService {
}
}
private async send(message: any) {
private async send(message: any, appId: string) {
message.timestamp = Date.now();
const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret);
const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecrets.get(appId));
ipcRenderer.send('nativeMessagingReply', encrypted);
ipcRenderer.send('nativeMessagingReply', {appId: appId, message: encrypted});
}
private async secureCommunication(remotePublicKey: ArrayBuffer) {
private async secureCommunication(remotePublicKey: ArrayBuffer, appId: string) {
const secret = await this.cryptoFunctionService.randomBytes(64);
this.sharedSecret = new SymmetricCryptoKey(secret);
this.sharedSecrets.set(appId, new SymmetricCryptoKey(secret));
const encryptedSecret = await this.cryptoFunctionService.rsaEncrypt(secret, remotePublicKey, EncryptionAlgorithm);
ipcRenderer.send('nativeMessagingReply', {command: 'setupEncryption', sharedSecret: Utils.fromBufferToB64(encryptedSecret)});
ipcRenderer.send('nativeMessagingReply', {appId: appId, command: 'setupEncryption', sharedSecret: Utils.fromBufferToB64(encryptedSecret)});
}
}