serviceWorker.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import Keychain from './keychain';
  2. import { downloadStream } from './api';
  3. let noSave = false;
  4. const map = new Map();
  5. self.addEventListener('install', event => {
  6. self.skipWaiting();
  7. });
  8. self.addEventListener('activate', event => {
  9. self.clients.claim();
  10. });
  11. async function decryptStream(request) {
  12. const id = request.url.split('/')[5];
  13. try {
  14. const file = map.get(id);
  15. file.download = downloadStream(id, file.keychain);
  16. const stream = await file.download.result;
  17. // eslint-disable-next-line no-undef
  18. const progStream = new TransformStream({
  19. transform: (chunk, controller) => {
  20. file.progress += chunk.length;
  21. controller.enqueue(chunk);
  22. }
  23. });
  24. const readStream = stream.pipeThrough(progStream);
  25. const decrypted = file.keychain.decryptStream(readStream);
  26. const headers = {
  27. 'Content-Disposition': 'attachment; filename=' + file.filename
  28. };
  29. return new Response(decrypted, { headers });
  30. } catch (e) {
  31. if (noSave) {
  32. return new Response(null, { status: e.message });
  33. }
  34. const redirectRes = await fetch(`/download/${id}`);
  35. return new Response(redirectRes.body, { status: 302 });
  36. }
  37. }
  38. self.onfetch = event => {
  39. const req = event.request.clone();
  40. if (req.url.includes('/api/download')) {
  41. event.respondWith(decryptStream(req));
  42. }
  43. };
  44. self.onmessage = event => {
  45. if (event.data.request === 'init') {
  46. noSave = event.data.noSave;
  47. const info = {
  48. keychain: new Keychain(event.data.key),
  49. filename: event.data.filename,
  50. progress: 0,
  51. cancelled: false
  52. };
  53. if (event.data.requiresPassword) {
  54. info.keychain.setPassword(event.data.password, event.data.url);
  55. }
  56. map.set(event.data.id, info);
  57. event.ports[0].postMessage('file info received');
  58. } else if (event.data.request === 'progress') {
  59. const file = map.get(event.data.id);
  60. if (file.cancelled) {
  61. event.ports[0].postMessage({ error: 'cancelled' });
  62. } else {
  63. event.ports[0].postMessage({ progress: file.progress });
  64. }
  65. } else if (event.data.request === 'cancel') {
  66. const file = map.get(event.data.id);
  67. file.cancelled = true;
  68. if (file.download) {
  69. file.download.cancel();
  70. }
  71. event.ports[0].postMessage('download cancelled');
  72. }
  73. };