refactor: use secure-file-transfer@0.0.1
This commit is contained in:
parent
67ee15c40e
commit
ebb8efb3f6
176
package-lock.json
generated
176
package-lock.json
generated
@ -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"
|
||||
|
11
package.json
11
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"
|
||||
|
215
src/react-app-env.d.ts
vendored
215
src/react-app-env.d.ts
vendored
@ -1,216 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
|
||||
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<Uint8Array>
|
||||
|
||||
/**
|
||||
* Returns a `Promise` that resolves to the authentication token as a base64-encoded string.
|
||||
*/
|
||||
authTokenB64(): Promise<string>
|
||||
|
||||
/**
|
||||
* Returns a `Promise` that resolves to the HTTP header value to be provided to the Wormhole server. It contains the authentication token.
|
||||
*/
|
||||
authHeader(): Promise<string>
|
||||
|
||||
/**
|
||||
* 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<EncryptedStream>
|
||||
|
||||
/**
|
||||
* 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<ReadableStream>
|
||||
|
||||
/**
|
||||
* 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<DecryptedStreamRange>
|
||||
|
||||
/**
|
||||
* 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<Uint8Array>
|
||||
|
||||
/**
|
||||
* @param encryptedMeta The encrypted metadata buffer to decrypt.
|
||||
* @returns A `Promise` that resolves to a decrypted version of `encryptedMeta`.
|
||||
*/
|
||||
decryptMeta(encryptedMeta: Uint8Array): Promise<Uint8Array>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
@ -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<Torrent['magnetURI'], Torrent> = {}
|
||||
|
||||
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<Torrent>(res => {
|
||||
this.webTorrentClient.add(
|
||||
magnetURI,
|
||||
{
|
||||
export const fileTransfer = new FileTransfer({
|
||||
torrentOpts: {
|
||||
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<Torrent>(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()
|
||||
|
@ -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: () => {},
|
||||
}))
|
||||
|
Loading…
Reference in New Issue
Block a user