diff --git a/app/capabilities.js b/app/capabilities.js index be76bceb..d43a6b10 100644 --- a/app/capabilities.js +++ b/app/capabilities.js @@ -45,7 +45,13 @@ async function checkCrypto() { ); return true; } catch (err) { - return false; + try { + window.asmCrypto = await import('asmcrypto.js'); + await import('@dannycoates/webcrypto-liner/build/shim'); + return true; + } catch (e) { + return false; + } } } @@ -60,12 +66,25 @@ function checkStreams() { } } +async function polyfillStreams() { + try { + await import('@mattiasbuelens/web-streams-polyfill'); + return true; + } catch (e) { + return false; + } +} + export default async function getCapabilities() { const browser = browserName(); const isMobile = /mobi|android/i.test(navigator.userAgent); const serviceWorker = 'serviceWorker' in navigator && browser !== 'edge'; let crypto = await checkCrypto(); const nativeStreams = checkStreams(); + let polyStreams = false; + if (!nativeStreams) { + polyStreams = await polyfillStreams(); + } let account = typeof AUTH_CONFIG !== 'undefined'; try { account = account && !!localStorage; @@ -87,10 +106,10 @@ export default async function getCapabilities() { account, crypto, serviceWorker, - streamUpload: nativeStreams, + streamUpload: nativeStreams || polyStreams, streamDownload: nativeStreams && serviceWorker && browser !== 'safari' && !mobileFirefox, - multifile: nativeStreams, + multifile: nativeStreams || polyStreams, share, standalone }; diff --git a/app/ece.js b/app/ece.js index d9f40c86..4cd6b45e 100644 --- a/app/ece.js +++ b/app/ece.js @@ -48,7 +48,7 @@ class ECETransformer { name: 'AES-GCM', length: 128 }, - false, + true, // Edge polyfill requires key to be extractable to encrypt :/ ['encrypt', 'decrypt'] ); } diff --git a/app/utils.js b/app/utils.js index e55d2584..80ed462a 100644 --- a/app/utils.js +++ b/app/utils.js @@ -23,34 +23,39 @@ function locale() { return document.querySelector('html').lang; } +function loadShim(polyfill) { + return new Promise((resolve, reject) => { + const shim = document.createElement('script'); + shim.src = polyfill; + shim.addEventListener('load', () => resolve(true)); + shim.addEventListener('error', () => resolve(false)); + document.head.appendChild(shim); + }); +} + function isFile(id) { return /^[0-9a-fA-F]{10,16}$/.test(id); } -async function copyToClipboard(str) { - try { - await navigator.clipboard.writeText(str); - } catch { - // Older browsers or the clipboard API fails because of a missing permission - const aux = document.createElement('input'); - aux.setAttribute('value', str); - aux.contentEditable = true; - aux.readOnly = true; - document.body.appendChild(aux); - if (navigator.userAgent.match(/iphone|ipad|ipod/i)) { - const range = document.createRange(); - range.selectNodeContents(aux); - const sel = getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - aux.setSelectionRange(0, str.length); - } else { - aux.select(); - } - const result = document.execCommand('copy'); - document.body.removeChild(aux); - return result; +function copyToClipboard(str) { + const aux = document.createElement('input'); + aux.setAttribute('value', str); + aux.contentEditable = true; + aux.readOnly = true; + document.body.appendChild(aux); + if (navigator.userAgent.match(/iphone|ipad|ipod/i)) { + const range = document.createRange(); + range.selectNodeContents(aux); + const sel = getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + aux.setSelectionRange(0, str.length); + } else { + aux.select(); } + const result = document.execCommand('copy'); + document.body.removeChild(aux); + return result; } const LOCALIZE_NUMBERS = !!( @@ -282,6 +287,7 @@ module.exports = { copyToClipboard, arrayToB64, b64ToArray, + loadShim, isFile, openLinksInNewTab, browserName, diff --git a/docs/notes/streams.md b/docs/notes/streams.md index 1e0b0889..ec0c0b89 100644 --- a/docs/notes/streams.md +++ b/docs/notes/streams.md @@ -6,6 +6,8 @@ - https://github.com/whatwg/streams/tree/master/reference-implementation - Examples - https://github.com/mdn/dom-examples/tree/master/streams +- Polyfill + - https://github.com/MattiasBuelens/web-streams-polyfill # Encrypted Content Encoding diff --git a/package-lock.json b/package-lock.json index cc37c4d1..c7f59d77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,9 @@ "@babel/plugin-proposal-class-properties": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/preset-env": "^7.16.11", + "@dannycoates/webcrypto-liner": "^0.1.37", "@fullhuman/postcss-purgecss": "^4.1.3", + "@mattiasbuelens/web-streams-polyfill": "0.2.1", "@sentry/browser": "^5.30.0", "asmcrypto.js": "^0.22.0", "babel-loader": "^8.2.4", @@ -1906,6 +1908,21 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@dannycoates/elliptic": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@dannycoates/elliptic/-/elliptic-6.4.2.tgz", + "integrity": "sha512-2G4qWMB2SRBk4H75d+BFBbz2b1cseIYCI8G7duGxtxdnjGxhewpripDsVr1lCagmijyYX4zDyfKTNoId5GGyow==", + "dev": true, + "dependencies": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, "node_modules/@dannycoates/express-ws": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@dannycoates/express-ws/-/express-ws-5.0.3.tgz", @@ -1921,6 +1938,17 @@ "express": "^4.0.0 || ^5.0.0-alpha.1" } }, + "node_modules/@dannycoates/webcrypto-liner": { + "version": "0.1.37", + "resolved": "https://registry.npmjs.org/@dannycoates/webcrypto-liner/-/webcrypto-liner-0.1.37.tgz", + "integrity": "sha512-EM29TDkn7GJaa/oOfLeS1vrAxEkyM+WfUsmHTz7OyrxvMZNqz2SiYdZkXBIvg+QCnKTfXc2x//ORAilesugQlg==", + "dev": true, + "dependencies": { + "@dannycoates/elliptic": "^6.4.2", + "asmcrypto.js": "^0.22.0", + "webcrypto-core": "github:dannycoates/webcrypto-core" + } + }, "node_modules/@fluent/bundle": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/@fluent/bundle/-/bundle-0.17.1.tgz", @@ -2048,6 +2076,19 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@mattiasbuelens/web-streams-polyfill": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@mattiasbuelens/web-streams-polyfill/-/web-streams-polyfill-0.2.1.tgz", + "integrity": "sha512-oKuFCQFa3W7Hj7zKn0+4ypI8JFm4ZKIoncwAC6wd5WwFW2sL7O1hpPoJdSWpynQ4DJ4lQ6MvFoVDmCLilonDFg==", + "deprecated": "moved to web-streams-polyfill@2.0.0", + "dev": true, + "dependencies": { + "@types/whatwg-streams": "^0.0.7" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2480,6 +2521,12 @@ "@types/node": "*" } }, + "node_modules/@types/whatwg-streams": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@types/whatwg-streams/-/whatwg-streams-0.0.7.tgz", + "integrity": "sha512-6sDiSEP6DWcY2ZolsJ2s39ZmsoGQ7KVwBDI3sESQsEm9P2dHTcqnDIHRZFRNtLCzWp7hCFGqYbw5GyfpQnJ01A==", + "dev": true + }, "node_modules/@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -21002,6 +21049,16 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/webcrypto-core": { + "version": "0.1.19", + "resolved": "git+ssh://git@github.com/dannycoates/webcrypto-core.git#8e0152a66d3ae6329cf080ccb3085eb06637070f", + "integrity": "sha512-FQXkmbl8syEGw0LtxcbO5aBmC6dmntkMMSzUxnC0U3Ue8vRrS9LKFsNOfs2XK1Nr5Sw1uGA0k4n7RZXa44vHeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.7.1" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -23562,6 +23619,21 @@ "dev": true, "requires": {} }, + "@dannycoates/elliptic": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@dannycoates/elliptic/-/elliptic-6.4.2.tgz", + "integrity": "sha512-2G4qWMB2SRBk4H75d+BFBbz2b1cseIYCI8G7duGxtxdnjGxhewpripDsVr1lCagmijyYX4zDyfKTNoId5GGyow==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, "@dannycoates/express-ws": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@dannycoates/express-ws/-/express-ws-5.0.3.tgz", @@ -23571,6 +23643,17 @@ "ws": "^7.1.1" } }, + "@dannycoates/webcrypto-liner": { + "version": "0.1.37", + "resolved": "https://registry.npmjs.org/@dannycoates/webcrypto-liner/-/webcrypto-liner-0.1.37.tgz", + "integrity": "sha512-EM29TDkn7GJaa/oOfLeS1vrAxEkyM+WfUsmHTz7OyrxvMZNqz2SiYdZkXBIvg+QCnKTfXc2x//ORAilesugQlg==", + "dev": true, + "requires": { + "@dannycoates/elliptic": "^6.4.2", + "asmcrypto.js": "^0.22.0", + "webcrypto-core": "github:dannycoates/webcrypto-core" + } + }, "@fluent/bundle": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/@fluent/bundle/-/bundle-0.17.1.tgz", @@ -23671,6 +23754,15 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@mattiasbuelens/web-streams-polyfill": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@mattiasbuelens/web-streams-polyfill/-/web-streams-polyfill-0.2.1.tgz", + "integrity": "sha512-oKuFCQFa3W7Hj7zKn0+4ypI8JFm4ZKIoncwAC6wd5WwFW2sL7O1hpPoJdSWpynQ4DJ4lQ6MvFoVDmCLilonDFg==", + "dev": true, + "requires": { + "@types/whatwg-streams": "^0.0.7" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -24023,6 +24115,12 @@ "@types/node": "*" } }, + "@types/whatwg-streams": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@types/whatwg-streams/-/whatwg-streams-0.0.7.tgz", + "integrity": "sha512-6sDiSEP6DWcY2ZolsJ2s39ZmsoGQ7KVwBDI3sESQsEm9P2dHTcqnDIHRZFRNtLCzWp7hCFGqYbw5GyfpQnJ01A==", + "dev": true + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -38782,6 +38880,15 @@ "minimalistic-assert": "^1.0.0" } }, + "webcrypto-core": { + "version": "git+ssh://git@github.com/dannycoates/webcrypto-core.git#8e0152a66d3ae6329cf080ccb3085eb06637070f", + "integrity": "sha512-FQXkmbl8syEGw0LtxcbO5aBmC6dmntkMMSzUxnC0U3Ue8vRrS9LKFsNOfs2XK1Nr5Sw1uGA0k4n7RZXa44vHeQ==", + "dev": true, + "from": "webcrypto-core@github:dannycoates/webcrypto-core", + "requires": { + "tslib": "^1.7.1" + } + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index 04208599..b6e9840b 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,9 @@ "@babel/plugin-proposal-class-properties": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/preset-env": "^7.16.11", + "@dannycoates/webcrypto-liner": "^0.1.37", "@fullhuman/postcss-purgecss": "^4.1.3", + "@mattiasbuelens/web-streams-polyfill": "0.2.1", "@sentry/browser": "^5.30.0", "asmcrypto.js": "^0.22.0", "babel-loader": "^8.2.4",