diff --git a/.gitignore b/.gitignore index 5cad93a78..511af2fce 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules /src/version.ts /src/licenses.json /public/openpgp +/public/web-streams-adapter /public/sitemap.xml /public/robots.txt diff --git a/package-lock.json b/package-lock.json index 456bb5558..3c33e5e3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2004,6 +2004,11 @@ "postcss": "^7.0.0" } }, + "@mattiasbuelens/web-streams-adapter": { + "version": "0.1.0-alpha.3", + "resolved": "https://registry.npmjs.org/@mattiasbuelens/web-streams-adapter/-/web-streams-adapter-0.1.0-alpha.3.tgz", + "integrity": "sha512-zZ5DOPokJLzmvklk151Rk9e79+xos5d9V0azVLy6jX+28113ffoCR0FYUVu0YQr+J4L/qFZI46jXsbv1a9velA==" + }, "@mdi/js": { "version": "4.8.95", "resolved": "https://registry.npmjs.org/@mdi/js/-/js-4.8.95.tgz", @@ -12309,7 +12314,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -16424,8 +16428,7 @@ "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "optional": true + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" }, "lcid": { "version": "1.0.0", @@ -16500,8 +16503,7 @@ "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "optional": true + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" }, "loose-envify": { "version": "1.3.1", diff --git a/package.json b/package.json index e87e551fe..7541d0913 100644 --- a/package.json +++ b/package.json @@ -4,21 +4,23 @@ "private": true, "author": "Ryo Ota (https://github.com/nwtgck)", "scripts": { - "serve": "npm run generate-version && npm run copy-openpgp && vue-cli-service serve", - "build": "npm run generate-version && npm run generate-sitemap && npm run generate-robots-txt && npm run copy-openpgp && vue-cli-service build", + "serve": "npm run generate-version && npm run copy-openpgp && npm run copy-web-streams-adapter && vue-cli-service serve", + "build": "npm run generate-version && npm run generate-sitemap && npm run generate-robots-txt && npm run copy-openpgp && npm run copy-web-streams-adapter && vue-cli-service build", "test:unit": "vue-cli-service test:unit", "lint": "vue-cli-service lint", "copy-openpgp": "copyfiles --flat node_modules/openpgp/dist/*.min.js public/openpgp", + "copy-web-streams-adapter": "copyfiles --flat node_modules/@mattiasbuelens/web-streams-adapter/dist/web-streams-adapter.js public/web-streams-adapter", "generate-robots-txt": "ts-node --project scripts/tsconfig.json scripts/generate-robots-txt.tsx > public/robots.txt", "generate-sitemap": "ts-node --project scripts/tsconfig.json scripts/generate-sitemap.tsx > public/sitemap.xml", "generate-version": "cross-var echo \"export const VERSION = \\\"$npm_package_version\\\";\" > src/version.ts", "postinstall": "license-checker --production --json > src/licenses.json", - "real-serve": "watch-build-serve -i=dist -i=.idea -i=./node_modules -i=.git -i=src/version.ts -i src/licenses.json -i public/openpgp/openpgp.min.js -i public/openpgp/openpgp.worker.min.js -i public/sitemap.xml -i public/robots.txt" + "real-serve": "watch-build-serve -i=dist -i=.idea -i=./node_modules -i=.git -i=src/version.ts -i src/licenses.json -i public/openpgp/openpgp.min.js -i public/openpgp/openpgp.worker.min.js -i public/web-streams-adapter/web-streams-adapter.js -i public/sitemap.xml -i public/robots.txt" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.26", "@fortawesome/free-brands-svg-icons": "^5.12.0", "@fortawesome/vue-fontawesome": "^0.1.9", + "@mattiasbuelens/web-streams-adapter": "0.1.0-alpha.3", "binconv": "^0.1.2", "clipboard": "^2.0.4", "core-js": "^3.6.4", diff --git a/src/sw.js b/src/sw.js index e84a32855..b728eeb2a 100644 --- a/src/sw.js +++ b/src/sw.js @@ -1,6 +1,49 @@ // (from: https://medium.com/@dougallrich/give-users-control-over-app-updates-in-vue-cli-3-pwas-20453aedc1f2) +// Backup the native ReadableStream because OpenPGP.js might modify it on Firefox +const NativeReadableStream = ReadableStream; importScripts('openpgp/openpgp.min.js'); +importScripts('web-streams-adapter/web-streams-adapter.js'); + + +/** + * Convert a native ReadableStream to polyfill ReadableStream if ReadableStream class is polyfill. + * + * @param readableStream Native ReadableStream + * @returns {*} + */ +function toPolyfillReadableIfNeed(readableStream) { + // If not polyfilled + if (NativeReadableStream === ReadableStream) { + return readableStream; + // If ReadableStream is polyfill + } else { + // (base: https://github.com/MattiasBuelens/web-streams-adapter/tree/d76e3789d67b1ab3c91699ecc0c42bde897d2298) + // NOTE: ReadableStream is polyfill ReadableStream in this condition + const toPolyfillReadable = WebStreamsAdapter.createReadableStreamWrapper(ReadableStream); + // Convert a native ReadableStream to polyfill ReadableStream + return toPolyfillReadable(readableStream); + } +} + +/** + * Convert a polyfill ReadableStream to native ReadableStream if ReadableStream class is polyfill. + * + * @param readableStream Native ReadableStream or polyfill ReadableStream + * @returns {*} + */ +function toNativeReadableIfNeed(readableStream) { + // If not polyfilled + if (NativeReadableStream === ReadableStream) { + return readableStream; + // If ReadableStream is polyfill + } else { + // (base: https://github.com/MattiasBuelens/web-streams-adapter/tree/d76e3789d67b1ab3c91699ecc0c42bde897d2298) + const toNativeReadable = WebStreamsAdapter.createReadableStreamWrapper(NativeReadableStream); + // Convert a polyfill ReadableStream to native ReadableStream + return toNativeReadable(readableStream); + } +} // Generate random string with specific length function generateRandomString(len){ @@ -89,7 +132,7 @@ self.addEventListener('fetch', (event) => { if (url.pathname === '/sw-download-support') { // Return "OK" event.respondWith(new Response( - new ReadableStream({ + new NativeReadableStream({ start(controller) { controller.enqueue(new Uint8Array([79, 75])); controller.close(); @@ -146,7 +189,7 @@ self.addEventListener('fetch', (event) => { openpgp.config.allow_unauthenticated_stream = true; // Decrypt the response body const decrypted = await openpgp.decrypt({ - message: await openpgp.message.read(res.body), + message: await openpgp.message.read(toPolyfillReadableIfNeed(res.body)), passwords: [password], format: 'binary' }); @@ -160,7 +203,7 @@ self.addEventListener('fetch', (event) => { } } - const downloadableRes = new Response(plainStream, { + const downloadableRes = new Response(toNativeReadableIfNeed(plainStream), { headers }); return downloadableRes;