diff --git a/package-lock.json b/package-lock.json
index 5d0dd09..0b02744 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -36,19 +36,17 @@
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0",
- "readable-stream-node-to-web": "^1.0.1",
"readable-web-to-node-stream": "^3.0.2",
"remark-gfm": "^3.0.1",
"sass": "^1.54.3",
+ "secure-file-transfer": "^0.0.1",
"streamsaver": "^2.0.6",
"trystero": "github:jeremyckahn/trystero#bugfix/29__clean-up-peers",
"typeface-public-sans": "^1.1.13",
"typeface-roboto": "^1.1.13",
"typescript": "^4.7.4",
"uuid": "^8.3.2",
- "web-vitals": "^2.1.4",
- "webtorrent": "^1.9.7",
- "wormhole-crypto": "^0.3.1"
+ "web-vitals": "^2.1.4"
},
"devDependencies": {
"@types/react-syntax-highlighter": "^15.5.5",
@@ -60,24 +58,19 @@
"autoprefixer": "^10.4.8",
"bittorrent-tracker": "^9.19.0",
"cross-env": "^7.0.3",
- "crypto": "npm:crypto-browserify@^3.12.0",
"eslint": "^8.21.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
- "http": "npm:http-browserify@^1.7.0",
- "https": "npm:https-browserify@^1.0.0",
"husky": "^8.0.1",
"mprocs": "^0.6.4",
- "path": "npm:path-browserify@^1.0.1",
"postcss": "^8.4.16",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"process": "^0.11.10",
"serve": "^14.1.2",
- "stream": "npm:stream-browserify@^3.0.0",
"tailwindcss": "^3.1.8",
"url": "^0.11.0",
"util": "^0.12.5"
@@ -5320,7 +5313,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@types/bittorrent-protocol/-/bittorrent-protocol-3.1.2.tgz",
"integrity": "sha512-7k9nivNeG7Sc8wVuBs+XjBp2u7pH8tqW3BB93/SAg3xht/cZEK+Rqkj79xSyJqyj86eA0F6n85EKkkyGki8afg==",
- "dev": true,
"dependencies": {
"@types/node": "*"
}
@@ -5642,7 +5634,6 @@
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/@types/magnet-uri/-/magnet-uri-5.1.3.tgz",
"integrity": "sha512-FvJN1yYdLhvU6zWJ2YnWQ2GnpFLsA8bt+85WY0tLh6ehzGNrvBorjlcc53/zY43r/IKn+ctFs1nt7andwGnQCQ==",
- "dev": true,
"dependencies": {
"@types/node": "*"
}
@@ -5689,7 +5680,6 @@
"version": "5.8.4",
"resolved": "https://registry.npmjs.org/@types/parse-torrent/-/parse-torrent-5.8.4.tgz",
"integrity": "sha512-FdKs5yN5iYO5Cu9gVz1Zl30CbZe6HTsqloWmCf+LfbImgSzlsUkov2+npQWCQSQ3zi/a2G5C824K0UpZ2sRufA==",
- "dev": true,
"dependencies": {
"@types/magnet-uri": "*",
"@types/node": "*",
@@ -5700,7 +5690,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/parse-torrent-file/-/parse-torrent-file-4.0.3.tgz",
"integrity": "sha512-dFkPnJPKiFWiGX+HXmyTVt2js3k0d9dThmUxX8nfGC22hbyZ5BTmetsEl45sQhHLcFo43njVrIKMXM3F1ahXRw==",
- "dev": true,
"dependencies": {
"@types/node": "*"
}
@@ -5812,7 +5801,6 @@
"version": "9.11.5",
"resolved": "https://registry.npmjs.org/@types/simple-peer/-/simple-peer-9.11.5.tgz",
"integrity": "sha512-haXgWcAa3Y3Sn+T8lzkE4ErQUpYzhW6Cz2lh00RhQTyWt+xZ3s87wJPztUxlqSdFRqGhe2MQIBd0XsyHP3No4w==",
- "dev": true,
"dependencies": {
"@types/node": "*"
}
@@ -5833,8 +5821,7 @@
"node_modules/@types/streamsaver": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/streamsaver/-/streamsaver-2.0.1.tgz",
- "integrity": "sha512-I49NtT8w6syBI3Zg3ixCyygTHoTVMY0z2TMRcTgccdIsVd2MwlKk7ITLHLsJtgchUHcOd7QEARG9h0ifcA6l2Q==",
- "dev": true
+ "integrity": "sha512-I49NtT8w6syBI3Zg3ixCyygTHoTVMY0z2TMRcTgccdIsVd2MwlKk7ITLHLsJtgchUHcOd7QEARG9h0ifcA6l2Q=="
},
"node_modules/@types/testing-library__jest-dom": {
"version": "5.14.5",
@@ -5864,7 +5851,6 @@
"version": "0.109.3",
"resolved": "https://registry.npmjs.org/@types/webtorrent/-/webtorrent-0.109.3.tgz",
"integrity": "sha512-EJLsxMEcEjPXHcBqL6TRAbUwIpxAul5ULrXHJ0zwig7Oe70FS6dAzCWLq4MBafX3QrQG1DzGAS0fS8iJEOjD0g==",
- "dev": true,
"dependencies": {
"@types/bittorrent-protocol": "*",
"@types/node": "*",
@@ -7470,8 +7456,7 @@
"node_modules/Base64": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz",
- "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw==",
- "dev": true
+ "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw=="
},
"node_modules/base64-js": {
"version": "1.5.1",
@@ -8063,7 +8048,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
- "dev": true,
"dependencies": {
"buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0",
@@ -8077,7 +8061,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
"integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
- "dev": true,
"dependencies": {
"browserify-aes": "^1.0.4",
"browserify-des": "^1.0.0",
@@ -8088,7 +8071,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
"integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
- "dev": true,
"dependencies": {
"cipher-base": "^1.0.1",
"des.js": "^1.0.0",
@@ -8105,7 +8087,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
"integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
- "dev": true,
"dependencies": {
"bn.js": "^5.0.0",
"randombytes": "^2.0.1"
@@ -8114,14 +8095,12 @@
"node_modules/browserify-rsa/node_modules/bn.js": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
- "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
- "dev": true
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="
},
"node_modules/browserify-sign": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
"integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
- "dev": true,
"dependencies": {
"bn.js": "^5.1.1",
"browserify-rsa": "^4.0.1",
@@ -8137,14 +8116,12 @@
"node_modules/browserify-sign/node_modules/bn.js": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
- "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
- "dev": true
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="
},
"node_modules/browserify-sign/node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -8253,8 +8230,7 @@
"node_modules/buffer-xor": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
- "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
- "dev": true
+ "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ=="
},
"node_modules/bufferutil": {
"version": "4.0.6",
@@ -8691,7 +8667,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
- "dev": true,
"dependencies": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -9129,7 +9104,6 @@
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
"integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
- "dev": true,
"dependencies": {
"bn.js": "^4.1.0",
"elliptic": "^6.5.3"
@@ -9139,7 +9113,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
- "dev": true,
"dependencies": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
@@ -9152,7 +9125,6 @@
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
- "dev": true,
"dependencies": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
@@ -9198,7 +9170,6 @@
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
"integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
- "dev": true,
"dependencies": {
"browserify-cipher": "^1.0.0",
"browserify-sign": "^4.0.0",
@@ -9899,7 +9870,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
"integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
- "dev": true,
"dependencies": {
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0"
@@ -9957,9 +9927,9 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/detectincognitojs": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/detectincognitojs/-/detectincognitojs-1.1.2.tgz",
- "integrity": "sha512-7b+0/zJ76ZTeEtNl9MCPEKgFauEw/LerdlwnEnnrgYCFhp5FL+RJGD13EF/R9FYqrVxL7H5fgCyBdzJ6BtkPhg=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/detectincognitojs/-/detectincognitojs-1.3.0.tgz",
+ "integrity": "sha512-/uAMG+6Ipa8izluYQ45HqARjeYgtJLLBvpAiX1Zd3zWJ1MhEne6FDSjkkLaC3pdNeHfT3qhpvFRqB6dwLbdnng=="
},
"node_modules/detective": {
"version": "5.2.1",
@@ -10002,7 +9972,6 @@
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
- "dev": true,
"dependencies": {
"bn.js": "^4.1.0",
"miller-rabin": "^4.0.0",
@@ -11481,7 +11450,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
- "dev": true,
"dependencies": {
"md5.js": "^1.3.4",
"safe-buffer": "^5.1.1"
@@ -12638,7 +12606,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
- "dev": true,
"dependencies": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
@@ -12652,7 +12619,6 @@
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -12925,7 +12891,6 @@
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz",
"integrity": "sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==",
- "dev": true,
"dependencies": {
"Base64": "~0.2.0",
"inherits": "~2.0.1"
@@ -13023,8 +12988,7 @@
"name": "https-browserify",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
- "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
- "dev": true
+ "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg=="
},
"node_modules/https-proxy-agent": {
"version": "5.0.1",
@@ -17858,7 +17822,6 @@
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
- "dev": true,
"dependencies": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
@@ -18749,7 +18712,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
"integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
- "dev": true,
"dependencies": {
"bn.js": "^4.0.0",
"brorand": "^1.0.1"
@@ -19775,7 +19737,6 @@
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
"integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
- "dev": true,
"dependencies": {
"asn1.js": "^5.2.0",
"browserify-aes": "^1.0.0",
@@ -19858,8 +19819,7 @@
"name": "path-browserify",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
- "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
- "dev": true
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
},
"node_modules/path-exists": {
"version": "4.0.0",
@@ -19913,7 +19873,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
- "dev": true,
"dependencies": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
@@ -21760,7 +21719,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
"integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
- "dev": true,
"dependencies": {
"bn.js": "^4.1.0",
"browserify-rsa": "^4.0.0",
@@ -21920,7 +21878,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
"integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
- "dev": true,
"dependencies": {
"randombytes": "^2.0.5",
"safe-buffer": "^5.1.0"
@@ -22933,7 +22890,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
- "dev": true,
"dependencies": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
@@ -23217,6 +23173,29 @@
"node": ">=10.0.0"
}
},
+ "node_modules/secure-file-transfer": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/secure-file-transfer/-/secure-file-transfer-0.0.1.tgz",
+ "integrity": "sha512-biTN2faslbvKUMA+vax9z1a/8suJpga1fgXHSTrWaKTKnH/sbFRH+eT3LB1LFywZVl6tUMHM+IacauqTrdnQcg==",
+ "dependencies": {
+ "@types/streamsaver": "^2.0.1",
+ "@types/webtorrent": "^0.109.3",
+ "crypto": "npm:crypto-browserify@^3.12.0",
+ "detectincognitojs": "^1.3.0",
+ "http": "npm:http-browserify@^1.7.0",
+ "https": "npm:https-browserify@^1.0.0",
+ "idb-chunk-store": "^1.0.1",
+ "path": "npm:path-browserify@^1.0.1",
+ "readable-stream-node-to-web": "^1.0.1",
+ "stream": "npm:stream-browserify@^3.0.0",
+ "streamsaver": "^2.0.6",
+ "webtorrent": "^1.9.7",
+ "wormhole-crypto": "^0.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -23532,7 +23511,6 @@
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
- "dev": true,
"dependencies": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -24033,7 +24011,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
- "dev": true,
"dependencies": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
@@ -30669,7 +30646,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@types/bittorrent-protocol/-/bittorrent-protocol-3.1.2.tgz",
"integrity": "sha512-7k9nivNeG7Sc8wVuBs+XjBp2u7pH8tqW3BB93/SAg3xht/cZEK+Rqkj79xSyJqyj86eA0F6n85EKkkyGki8afg==",
- "dev": true,
"requires": {
"@types/node": "*"
}
@@ -30953,7 +30929,6 @@
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/@types/magnet-uri/-/magnet-uri-5.1.3.tgz",
"integrity": "sha512-FvJN1yYdLhvU6zWJ2YnWQ2GnpFLsA8bt+85WY0tLh6ehzGNrvBorjlcc53/zY43r/IKn+ctFs1nt7andwGnQCQ==",
- "dev": true,
"requires": {
"@types/node": "*"
}
@@ -31000,7 +30975,6 @@
"version": "5.8.4",
"resolved": "https://registry.npmjs.org/@types/parse-torrent/-/parse-torrent-5.8.4.tgz",
"integrity": "sha512-FdKs5yN5iYO5Cu9gVz1Zl30CbZe6HTsqloWmCf+LfbImgSzlsUkov2+npQWCQSQ3zi/a2G5C824K0UpZ2sRufA==",
- "dev": true,
"requires": {
"@types/magnet-uri": "*",
"@types/node": "*",
@@ -31011,7 +30985,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/parse-torrent-file/-/parse-torrent-file-4.0.3.tgz",
"integrity": "sha512-dFkPnJPKiFWiGX+HXmyTVt2js3k0d9dThmUxX8nfGC22hbyZ5BTmetsEl45sQhHLcFo43njVrIKMXM3F1ahXRw==",
- "dev": true,
"requires": {
"@types/node": "*"
}
@@ -31123,7 +31096,6 @@
"version": "9.11.5",
"resolved": "https://registry.npmjs.org/@types/simple-peer/-/simple-peer-9.11.5.tgz",
"integrity": "sha512-haXgWcAa3Y3Sn+T8lzkE4ErQUpYzhW6Cz2lh00RhQTyWt+xZ3s87wJPztUxlqSdFRqGhe2MQIBd0XsyHP3No4w==",
- "dev": true,
"requires": {
"@types/node": "*"
}
@@ -31144,8 +31116,7 @@
"@types/streamsaver": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/streamsaver/-/streamsaver-2.0.1.tgz",
- "integrity": "sha512-I49NtT8w6syBI3Zg3ixCyygTHoTVMY0z2TMRcTgccdIsVd2MwlKk7ITLHLsJtgchUHcOd7QEARG9h0ifcA6l2Q==",
- "dev": true
+ "integrity": "sha512-I49NtT8w6syBI3Zg3ixCyygTHoTVMY0z2TMRcTgccdIsVd2MwlKk7ITLHLsJtgchUHcOd7QEARG9h0ifcA6l2Q=="
},
"@types/testing-library__jest-dom": {
"version": "5.14.5",
@@ -31175,7 +31146,6 @@
"version": "0.109.3",
"resolved": "https://registry.npmjs.org/@types/webtorrent/-/webtorrent-0.109.3.tgz",
"integrity": "sha512-EJLsxMEcEjPXHcBqL6TRAbUwIpxAul5ULrXHJ0zwig7Oe70FS6dAzCWLq4MBafX3QrQG1DzGAS0fS8iJEOjD0g==",
- "dev": true,
"requires": {
"@types/bittorrent-protocol": "*",
"@types/node": "*",
@@ -32311,8 +32281,7 @@
"Base64": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz",
- "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw==",
- "dev": true
+ "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw=="
},
"base64-js": {
"version": "1.5.1",
@@ -32713,7 +32682,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
- "dev": true,
"requires": {
"buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0",
@@ -32727,7 +32695,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
"integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
- "dev": true,
"requires": {
"browserify-aes": "^1.0.4",
"browserify-des": "^1.0.0",
@@ -32738,7 +32705,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
"integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
- "dev": true,
"requires": {
"cipher-base": "^1.0.1",
"des.js": "^1.0.0",
@@ -32755,7 +32721,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
"integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
- "dev": true,
"requires": {
"bn.js": "^5.0.0",
"randombytes": "^2.0.1"
@@ -32764,8 +32729,7 @@
"bn.js": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
- "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
- "dev": true
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="
}
}
},
@@ -32773,7 +32737,6 @@
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
"integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
- "dev": true,
"requires": {
"bn.js": "^5.1.1",
"browserify-rsa": "^4.0.1",
@@ -32789,14 +32752,12 @@
"bn.js": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
- "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
- "dev": true
+ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
}
}
},
@@ -32860,8 +32821,7 @@
"buffer-xor": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
- "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
- "dev": true
+ "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ=="
},
"bufferutil": {
"version": "4.0.6",
@@ -33133,7 +33093,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
- "dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -33460,7 +33419,6 @@
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
"integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
- "dev": true,
"requires": {
"bn.js": "^4.1.0",
"elliptic": "^6.5.3"
@@ -33470,7 +33428,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
- "dev": true,
"requires": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
@@ -33483,7 +33440,6 @@
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
- "dev": true,
"requires": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
@@ -33516,7 +33472,6 @@
"version": "npm:crypto-browserify@3.12.0",
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
"integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
- "dev": true,
"requires": {
"browserify-cipher": "^1.0.0",
"browserify-sign": "^4.0.0",
@@ -34016,7 +33971,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
"integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
- "dev": true,
"requires": {
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0"
@@ -34062,9 +34016,9 @@
}
},
"detectincognitojs": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/detectincognitojs/-/detectincognitojs-1.1.2.tgz",
- "integrity": "sha512-7b+0/zJ76ZTeEtNl9MCPEKgFauEw/LerdlwnEnnrgYCFhp5FL+RJGD13EF/R9FYqrVxL7H5fgCyBdzJ6BtkPhg=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/detectincognitojs/-/detectincognitojs-1.3.0.tgz",
+ "integrity": "sha512-/uAMG+6Ipa8izluYQ45HqARjeYgtJLLBvpAiX1Zd3zWJ1MhEne6FDSjkkLaC3pdNeHfT3qhpvFRqB6dwLbdnng=="
},
"detective": {
"version": "5.2.1",
@@ -34095,7 +34049,6 @@
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
- "dev": true,
"requires": {
"bn.js": "^4.1.0",
"miller-rabin": "^4.0.0",
@@ -35186,7 +35139,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
- "dev": true,
"requires": {
"md5.js": "^1.3.4",
"safe-buffer": "^5.1.1"
@@ -36052,7 +36004,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
- "dev": true,
"requires": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
@@ -36062,8 +36013,7 @@
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
}
}
},
@@ -36270,7 +36220,6 @@
"version": "npm:http-browserify@1.7.0",
"resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz",
"integrity": "sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==",
- "dev": true,
"requires": {
"Base64": "~0.2.0",
"inherits": "~2.0.1"
@@ -36343,8 +36292,7 @@
"https": {
"version": "npm:https-browserify@1.0.0",
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
- "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
- "dev": true
+ "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg=="
},
"https-proxy-agent": {
"version": "5.0.1",
@@ -40115,7 +40063,6 @@
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
- "dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
@@ -40679,7 +40626,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
"integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
- "dev": true,
"requires": {
"bn.js": "^4.0.0",
"brorand": "^1.0.1"
@@ -41425,7 +41371,6 @@
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
"integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
- "dev": true,
"requires": {
"asn1.js": "^5.2.0",
"browserify-aes": "^1.0.0",
@@ -41492,8 +41437,7 @@
"path": {
"version": "npm:path-browserify@1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
- "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
- "dev": true
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
},
"path-exists": {
"version": "4.0.0",
@@ -41535,7 +41479,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
- "dev": true,
"requires": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
@@ -42699,7 +42642,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
"integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
- "dev": true,
"requires": {
"bn.js": "^4.1.0",
"browserify-rsa": "^4.0.0",
@@ -42819,7 +42761,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
"integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
- "dev": true,
"requires": {
"randombytes": "^2.0.5",
"safe-buffer": "^5.1.0"
@@ -43580,7 +43521,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
- "dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
@@ -43755,6 +43695,26 @@
"node-gyp-build": "^4.2.0"
}
},
+ "secure-file-transfer": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/secure-file-transfer/-/secure-file-transfer-0.0.1.tgz",
+ "integrity": "sha512-biTN2faslbvKUMA+vax9z1a/8suJpga1fgXHSTrWaKTKnH/sbFRH+eT3LB1LFywZVl6tUMHM+IacauqTrdnQcg==",
+ "requires": {
+ "@types/streamsaver": "^2.0.1",
+ "@types/webtorrent": "^0.109.3",
+ "crypto": "npm:crypto-browserify@^3.12.0",
+ "detectincognitojs": "^1.3.0",
+ "http": "npm:http-browserify@^1.7.0",
+ "https": "npm:https-browserify@^1.0.0",
+ "idb-chunk-store": "^1.0.1",
+ "path": "npm:path-browserify@^1.0.1",
+ "readable-stream-node-to-web": "^1.0.1",
+ "stream": "npm:stream-browserify@^3.0.0",
+ "streamsaver": "^2.0.6",
+ "webtorrent": "^1.9.7",
+ "wormhole-crypto": "^0.3.1"
+ }
+ },
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -44022,7 +43982,6 @@
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
- "dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -44387,7 +44346,6 @@
"version": "npm:stream-browserify@3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
- "dev": true,
"requires": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
diff --git a/package.json b/package.json
index 128a4d8..cb18e47 100644
--- a/package.json
+++ b/package.json
@@ -32,19 +32,17 @@
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0",
- "readable-stream-node-to-web": "^1.0.1",
"readable-web-to-node-stream": "^3.0.2",
"remark-gfm": "^3.0.1",
"sass": "^1.54.3",
+ "secure-file-transfer": "^0.0.1",
"streamsaver": "^2.0.6",
"trystero": "github:jeremyckahn/trystero#bugfix/29__clean-up-peers",
"typeface-public-sans": "^1.1.13",
"typeface-roboto": "^1.1.13",
"typescript": "^4.7.4",
"uuid": "^8.3.2",
- "web-vitals": "^2.1.4",
- "webtorrent": "^1.9.7",
- "wormhole-crypto": "^0.3.1"
+ "web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
@@ -89,24 +87,19 @@
"autoprefixer": "^10.4.8",
"bittorrent-tracker": "^9.19.0",
"cross-env": "^7.0.3",
- "crypto": "npm:crypto-browserify@^3.12.0",
"eslint": "^8.21.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
- "http": "npm:http-browserify@^1.7.0",
- "https": "npm:https-browserify@^1.0.0",
"husky": "^8.0.1",
"mprocs": "^0.6.4",
- "path": "npm:path-browserify@^1.0.1",
"postcss": "^8.4.16",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"process": "^0.11.10",
"serve": "^14.1.2",
- "stream": "npm:stream-browserify@^3.0.0",
"tailwindcss": "^3.1.8",
"url": "^0.11.0",
"util": "^0.12.5"
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 85775b7..6431bc5 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -1,216 +1 @@
///
-
-declare module 'wormhole-crypto' {
- /**
- * The encrypted byte range that is needed to decrypt the client's specified range.
- */
- export type ByteRange = {
- offset: number
- length: number
- }
-
- /**
- * The metadata buffer to encrypt.
- */
- export type Meta = Uint8Array
-
- /**
- * A WHATWG readable stream used as a data source for the plaintext stream.
- */
- export type EncryptedStream = ReadableStream
-
- /**
- * @param streams An array of `ReadableStream` objects, one for each of the requested ranges.
- * @returns Contains the plaintext data for the client's desired byte range.
- */
- export type DecryptFn = (streams: ReadableStream[]) => ReadableStream
-
- export type DecryptedStreamRange = {
- ranges: ByteRange[]
- decrypt: DecryptFn
- }
-
- export class Keychain {
- /**
- * Create a new keychain object. The keychain can be used to create encryption streams, decryption streams, and to encrypt or decrypt a "metadata" buffer.
- *
- * @param key The main key. This should be 16 bytes in length. If a string is given, then it should be a base64-encoded string. If the argument is null, then a key will be automatically generated.
- * @param salt The salt. This should be 16 bytes in length. If a string is given, then it should be a base64-encoded string. If this argument is null, then a salt will be automatically generated.
- */
- constructor(
- key: Uint8Array | string | null = null,
- salt: Uint8Array | string | null = null
- )
-
- /**
- * The main key.
- */
- key: Uint8Array
-
- /**
- * The main key as a base64-encoded string.
- */
- keyB64: string
-
- /**
- * The salt.
- *
- * Implementation note: The salt is used to derive the (internal) metadata key and authentication token.
- */
- salt: Uint8Array
-
- /**
- * The salt as a base64-encoded string.
- */
- saltB64: string
-
- /**
- * Returns a `Promise` which resolves to the authentication token. By default, the authentication token is automatically derived from the main key using HKDF SHA-256.
- *
- * In Wormhole, the authentication token is used to communicate with the server and prove that the client has permission to fetch data for a room. Without a valid authentication token, the server will not return the encrypted room metadata or allow downloading the encrypted file data.
- *
- * Since the authentication token is derived from the main key, the client presents it to the Wormhole server as a "reader token" to prove that it is in possession of the main key without revealing the main key to the server.
- *
- * For destructive operations, like modifying the room, the client instead presents a "writer token", which is not derived from the main key but is provided by the server to the room creator who overrides the keychain authentication token by calling `keychain.setAuthToken(authToken)` with the "writer token".
- */
- authToken(): Promise
-
- /**
- * Returns a `Promise` that resolves to the authentication token as a base64-encoded string.
- */
- authTokenB64(): Promise
-
- /**
- * Returns a `Promise` that resolves to the HTTP header value to be provided to the Wormhole server. It contains the authentication token.
- */
- authHeader(): Promise
-
- /**
- * Update the keychain authentication token to `authToken`.
- *
- * @param authToken The authentication token. This should be 16 bytes in length. If a `string` is given, then it should be a base64-encoded string. If this argument is `null`, then an authentication token will be automatically generated.
- */
- setAuthToken(authToken: Uint8Array | string | null = null): void
-
- /**
- * @param stream A WHATWG readable stream used as a data source for the encrypted stream.
- *
- * @returns A `Promise` that resolves to a `ReadableStream` encryption stream that consumes the data in `stream` and returns an encrypted version. Data is encrypted with [Encrypted Content-Encoding for HTTP (RFC 8188)](https://tools.ietf.org/html/rfc8188).
- */
- encryptStream(stream: ReadableStream): Promise
-
- /**
- * Returns a `Promise` that resolves to a `ReadableStream` decryption stream that consumes the data in `encryptedStream` and returns a plaintext version.
- *
- * @param encryptedStream A WHATWG readable stream that was returned from encryptStream.
- * @returns A `Promise` that resolves to a `ReadableStream` decryption stream that
-consumes the data in `encryptedStream` and returns a plaintext version.
- */
- decryptStream(encryptedStream: EncryptedStream): Promise
-
- /**
- * Returns a `Promise` that resolves to a object containing `ranges`, which is an array of objects containing `offset` and `length` integers specifying the encrypted byte ranges that are needed to decrypt the client's specified range, and a `decrypt` function.
- *
- * Once the client has gathered a stream for each byte range in `ranges`, the client should call `decrypt(streams)`, where `streams` is an array of `ReadableStream` objects, one for each of the requested ranges. `decrypt` will then return a `ReadableStream` containing the plaintext data for the client's desired byte range.
- */
- decryptStreamRange(
- offset: number,
- length: number,
- totalEncryptedLength: number
- ): Promise
-
- /**
- * Implementation note: The metadata key is automatically derived from the main key using HKDF SHA-256. The value is not user-controlled.
- *
- * Implementation note: The initialization vector (IV) is automatically generated and included in the encrypted output. No need to generate it or to manage it separately from the encrypted output.
- *
- * @returns A `Promise` that resolves to an encrypted version of `meta`. The metadata is encrypted with AES-GCM.
- */
- encryptMeta(meta: Meta): Promise
-
- /**
- * @param encryptedMeta The encrypted metadata buffer to decrypt.
- * @returns A `Promise` that resolves to a decrypted version of `encryptedMeta`.
- */
- decryptMeta(encryptedMeta: Uint8Array): Promise
- }
-
- /**
- * Given an encrypted size, return the corresponding plaintext size.
- */
- export function plaintextSize(encryptedSize: number): number
-
- /**
- * Given a plaintext size, return the corresponding encrypted size.
- */
- export function encryptedSize(plaintextSize: number): number
-}
-
-declare module 'abstract-chunk-store' {
- type GetCallback = (err: Error | null, buffer: Buffer) => void
-
- export interface ChunkStore {
- /**
- * Create a new chunk store. Chunks must have a length of `chunkLength`.
- */
- constructor(chunkLength: number)
-
- /**
- * Add a new chunk to the storage. `index` should be an integer.
- */
- put(
- index: number,
- chunkBuffer: Buffer,
- cb: (err: Error | null) => void
- ): void
-
- /**
- * Retrieve a chunk stored. `index` should be an integer.
- */
- get(index: number, cb: GetCallback): void
- get(
- index: number,
- options: { offset?: number; length?: number },
- cb: GetCallback
- ): void
-
- /**
- * Close the underlying resource, e.g. if the store is backed by a file, this would close the file descriptor.
- */
- close(cb: (err: Error | null) => void)
-
- /**
- * Destroy the file data, e.g. if the store is backed by a file, this would delete the file from the filesystem.
- */
- destroy(cb: (err: Error | null) => void)
-
- /**
- * Expose the chunk length from the constructor so that code that receives a chunk store can know what size of chunks to write.
- */
- chunkLength: number
- }
-}
-
-declare module 'idb-chunk-store' {
- import { TorrentOptions } from 'webtorrent'
- import { ChunkStore } from 'abstract-chunk-store'
-
- export default function idbChunkStore(
- chunkLength: number,
- opts?: Partial<{
- /**
- * A name to separate the contents of different stores
- */
- name: string
- }> &
- TorrentOptions.store
- ): ChunkStore
-}
-
-declare module 'readable-stream-node-to-web' {
- export const WEBSTREAM_SUPPORT: boolean
-
- export default function nodeToWeb(
- readableStream: NodeJS.ReadableStream
- ): ReadableStream
-}
diff --git a/src/services/FileTransfer/FileTransfer.ts b/src/services/FileTransfer/FileTransfer.ts
index b016b5a..dcd899b 100644
--- a/src/services/FileTransfer/FileTransfer.ts
+++ b/src/services/FileTransfer/FileTransfer.ts
@@ -1,219 +1,12 @@
-import WebTorrent, { Torrent, TorrentFile } from 'webtorrent'
-import streamSaver from 'streamsaver'
-import { Keychain, plaintextSize, encryptedSize } from 'wormhole-crypto'
-import idbChunkStore from 'idb-chunk-store'
-import { detectIncognito } from 'detectincognitojs'
-import nodeToWebStream from 'readable-stream-node-to-web'
+import { FileTransfer, setStreamSaverMitm } from 'secure-file-transfer'
import { trackerUrls } from 'config/trackerUrls'
import { streamSaverUrl } from 'config/streamSaverUrl'
-streamSaver.mitm = streamSaverUrl
+setStreamSaverMitm(streamSaverUrl)
-const getKeychain = (password: string) => {
- const encoder = new TextEncoder()
- const keyLength = 16
- const padding = new Array(keyLength).join('0')
- const key = password.concat(padding).slice(0, keyLength)
- const salt = window.location.origin.concat(padding).slice(0, keyLength)
-
- const keychain = new Keychain(encoder.encode(key), encoder.encode(salt))
-
- return keychain
-}
-
-interface DownloadOpts {
- doSave?: boolean
- onProgress?: (progress: number) => void
-}
-
-export class FileTransfer {
- private webTorrentClient = new WebTorrent()
-
- private torrents: Record = {}
-
- private async saveTorrentFiles(torrent: Torrent, password: string) {
- for (const file of torrent.files) {
- try {
- const readStream = await this.getDecryptedFileReadStream(file, password)
-
- const writeStream = streamSaver.createWriteStream(file.name, {
- size: plaintextSize(file.length),
- })
-
- await readStream.pipeTo(writeStream)
- } catch (e) {
- console.error(e)
- throw new Error('Download aborted')
- }
- }
- }
-
- constructor() {
- window.addEventListener('beforeunload', this.handleBeforePageUnload)
- }
-
- async getDecryptedFileReadStream(file: TorrentFile, password: string) {
- const keychain = getKeychain(password)
-
- const decryptedStream: ReadableStream = await keychain.decryptStream(
- nodeToWebStream(file.createReadStream())
- )
-
- return decryptedStream
- }
-
- async download(
- magnetURI: string,
- password: string,
- { onProgress, doSave }: DownloadOpts = {}
- ) {
- let torrent = this.torrents[magnetURI]
-
- if (!torrent) {
- const { isPrivate } = await detectIncognito()
-
- torrent = await new Promise(res => {
- this.webTorrentClient.add(
- magnetURI,
- {
- announce: trackerUrls,
- // If the user is using their browser's private mode, IndexedDB
- // will be unavailable and idbChunkStore will break all transfers.
- // In that case, fall back to the default in-memory data store.
- store: isPrivate ? undefined : idbChunkStore,
- destroyStoreOnDestroy: true,
- },
- torrent => {
- res(torrent)
- }
- )
- })
-
- this.torrents[torrent.magnetURI] = torrent
- }
-
- const handleDownload = () => {
- onProgress?.(torrent.progress)
- }
-
- torrent.on('download', handleDownload)
-
- if (doSave) {
- try {
- await this.saveTorrentFiles(torrent, password)
- } catch (e) {
- torrent.off('download', handleDownload)
-
- // Propagate error to the UI
- throw e
- }
- }
-
- return torrent.files
- }
-
- async offer(files: File[] | FileList, password: string) {
- const { isPrivate } = await detectIncognito()
-
- const filesToSeed: File[] =
- files instanceof FileList ? Array.from(files) : files
-
- const encryptedFiles = await Promise.all(
- filesToSeed.map(async file => {
- // Force a type conversion here to prevent stream from being typed as a
- // NodeJS.ReadableStream, which is the default overloaded return type
- // for file.stream().
- const stream = file.stream() as any as ReadableStream
-
- const encryptedStream = await getKeychain(password).encryptStream(
- stream
- )
-
- // WebTorrent internally opens the ReadableStream for file data twice.
- // Normally this would not be an issue for File instances provided to
- // WebTorrent for seeding. `encryptedFile` is implemented as a facade
- // for a File instance, with the key difference being that stream() is
- // overridden to return an encrypted instance of the file's stream
- // data. If this stream is reopened, an error would be thrown and the
- // operation would fail. To avoid this, `encryptedFile` streams are
- // tee'd and pooled beforehand so that reopening of the encrypted
- // stream data directly is avoided.
- //
- // See:
- // - https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/tee
- const streamPool = encryptedStream.tee()
-
- // Providing the file data as a File instance rather than a
- // ReadableStream directly (which WebTorrent would accept) prevents
- // WebTorrent from loading the entire contents of the file into memory.
- //
- // See:
- // - https://github.com/webtorrent/webtorrent/blob/e26b64c0d0b4bdd8222e19d90bfcf7a688203e3c/index.js#L376-L384
- // - https://github.com/feross/simple-concat/blob/44134bf16667b6006a254135d5c8c76ea96823d4/index.js#L3-L8
- const encryptedFile = Object.setPrototypeOf(
- {
- lastModified: file.lastModified,
- name: file.name,
- size: encryptedSize(file.size),
- stream: () => streamPool.pop(),
- type: file.type,
- },
- File.prototype
- )
-
- return encryptedFile
- })
- )
-
- const offer = await new Promise(res => {
- this.webTorrentClient.seed(
- encryptedFiles,
- {
- announce: trackerUrls,
- // If the user is using their browser's private mode, IndexedDB will
- // be unavailable and idbChunkStore will break all transfers. In that
- // case, fall back to the default in-memory data store.
- store: isPrivate ? undefined : idbChunkStore,
- destroyStoreOnDestroy: true,
- },
- torrent => {
- res(torrent)
- }
- )
- })
-
- const { magnetURI } = offer
- this.torrents[magnetURI] = offer
-
- return magnetURI
- }
-
- rescind(magnetURI: string) {
- const torrent = this.torrents[magnetURI]
-
- if (torrent) {
- torrent.destroy()
- } else {
- console.error(`Attempted to clean up nonexistent torrent: ${magnetURI}`)
- }
-
- delete this.torrents[magnetURI]
- }
-
- rescindAll() {
- for (const magnetURI in this.torrents) {
- this.rescind(magnetURI)
- }
- }
-
- isOffering(magnetURI: string) {
- return magnetURI in this.torrents
- }
-
- handleBeforePageUnload = () => {
- this.rescindAll()
- }
-}
-
-export const fileTransfer = new FileTransfer()
+export const fileTransfer = new FileTransfer({
+ torrentOpts: {
+ announce: trackerUrls,
+ },
+})
diff --git a/src/setupTests.ts b/src/setupTests.ts
index bee9a8e..80ce0c6 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -8,12 +8,10 @@ afterEach(() => {
jest.restoreAllMocks()
})
-jest.mock('webtorrent', () => ({
+jest.mock('secure-file-transfer', () => ({
__esModule: true,
- default: class WebTorrent {},
-}))
-
-jest.mock('wormhole-crypto', () => ({
- __esModule: true,
- Keychain: class Keychain {},
+ FileTransfer: class FileTransfer {
+ rescindAll() {}
+ },
+ setStreamSaverMitm: () => {},
}))