diff --git a/.gitignore b/.gitignore index 0a4b8b0..82f109c 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,16 @@ marketplace-contract/target/* # report report.* + +# backend node_modules +/backend/node_modules/ + +# misc for backend +/backend/.DS_Store +/backend/.env +/backend/.env.local +/backend/.env.development.local +/backend/.env.test.local +/backend/.env.production.local +/backend/.cache + diff --git a/backend/app.js b/backend/app.js new file mode 100644 index 0000000..82e6db6 --- /dev/null +++ b/backend/app.js @@ -0,0 +1,20 @@ +const express = require('express'); +const app = express(); +const uploadRoutes = require('./routes/upload.js'); + +// CORS (we allow everything) +app.use(function(req, res, next) { + res.header("Access-Control-Allow-Origin", "*"); + next(); +}); + +app.get('/', function (req, res) { + res.send("Hello World!"); +}); + +// Routes +app.use('/upload', uploadRoutes); + +app.listen(3000, function () { + console.log("IPFS pinner app listening on port 3000!"); +}); \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000..dfeb3d4 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,1113 @@ +{ + "name": "fono-root-backend", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/runtime": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", + "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@crustio/crust-pin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@crustio/crust-pin/-/crust-pin-1.0.0.tgz", + "integrity": "sha512-ZVDe2CHLtIvSgIFNO5scCeUtT/7jcxtYhPuFRZ7ziyK88Ru+0m30utNcfYMKRIrkXOhboUHG6yd+3Ua1YkiarA==", + "requires": { + "@crustio/type-definitions": "^1.2.0", + "@polkadot/api": "^4.2.1" + } + }, + "@crustio/type-definitions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@crustio/type-definitions/-/type-definitions-1.2.0.tgz", + "integrity": "sha512-i/u3WUuhfC76JirlSwyGIKDwoFrax5QUonxGG/wgX2KEDKM9MIVx4qEsphE/tjAxlX1/qO3c72dzvKR2gndhgg==", + "requires": { + "@open-web3/orml-type-definitions": "^0.8.2-9" + } + }, + "@open-web3/orml-type-definitions": { + "version": "0.8.2-11", + "resolved": "https://registry.npmjs.org/@open-web3/orml-type-definitions/-/orml-type-definitions-0.8.2-11.tgz", + "integrity": "sha512-cUv5+mprnaGNt0tu3FhK1nFRBK7SGjPhA1O0nxWWeRmuuH5fjkr0glbHE9kcKuCBfsh7nt6NGwxwl9emQtUDSA==" + }, + "@polkadot/api": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@polkadot/api/-/api-4.17.1.tgz", + "integrity": "sha512-uuNIKWC+PjM+1AARRu4NLWOEudZE6DW8UOlaubx3uGhPywqPIP+HGWP2I6PqRGYKARBWxxOvca1Q7WoKzpYC8w==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/api-derive": "4.17.1", + "@polkadot/keyring": "^6.11.1", + "@polkadot/metadata": "4.17.1", + "@polkadot/rpc-core": "4.17.1", + "@polkadot/rpc-provider": "4.17.1", + "@polkadot/types": "4.17.1", + "@polkadot/types-known": "4.17.1", + "@polkadot/util": "^6.11.1", + "@polkadot/util-crypto": "^6.11.1", + "@polkadot/x-rxjs": "^6.11.1", + "eventemitter3": "^4.0.7" + } + }, + "@polkadot/api-derive": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@polkadot/api-derive/-/api-derive-4.17.1.tgz", + "integrity": "sha512-mgq57F1yAiZjuiA0vrR2zWidyyd+mGe7Kbs4SxVeDWLsNbLc9+eASIfX7Hch2SDHIn3CQpv6DQqJH00uDfw9Lw==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/api": "4.17.1", + "@polkadot/rpc-core": "4.17.1", + "@polkadot/types": "4.17.1", + "@polkadot/util": "^6.11.1", + "@polkadot/util-crypto": "^6.11.1", + "@polkadot/x-rxjs": "^6.11.1" + } + }, + "@polkadot/keyring": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/keyring/-/keyring-6.11.1.tgz", + "integrity": "sha512-rW8INl7pO6Dmaffd6Df1yAYCRWa2RmWQ0LGfJeA/M6seVIkI6J3opZqAd4q2Op+h9a7z4TESQGk8yggOEL+Csg==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/util": "6.11.1", + "@polkadot/util-crypto": "6.11.1" + } + }, + "@polkadot/metadata": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@polkadot/metadata/-/metadata-4.17.1.tgz", + "integrity": "sha512-219isiCWVfbu5JxZnOPj+cV4T+S0XHS4+Jal3t3xz9y4nbgr+25Pa4KInEsJPx0u8EZAxMeiUCX3vd5U7oe72g==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/types": "4.17.1", + "@polkadot/types-known": "4.17.1", + "@polkadot/util": "^6.11.1", + "@polkadot/util-crypto": "^6.11.1" + } + }, + "@polkadot/networks": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/networks/-/networks-6.11.1.tgz", + "integrity": "sha512-0C6Ha2kvr42se3Gevx6UhHzv3KnPHML0N73Amjwvdr4y0HLZ1Nfw+vcm5yqpz5gpiehqz97XqFrsPRauYdcksQ==", + "requires": { + "@babel/runtime": "^7.14.6" + } + }, + "@polkadot/rpc-core": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-core/-/rpc-core-4.17.1.tgz", + "integrity": "sha512-1gqYaYuSSQsRmt3ol55jmjBP/euKyAh4PwSj94I2wu0fngK/FZwVZNDJZn/Ib68X/s38TBIgqJ6+YdUdr3z1xw==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/metadata": "4.17.1", + "@polkadot/rpc-provider": "4.17.1", + "@polkadot/types": "4.17.1", + "@polkadot/util": "^6.11.1", + "@polkadot/x-rxjs": "^6.11.1" + } + }, + "@polkadot/rpc-provider": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-provider/-/rpc-provider-4.17.1.tgz", + "integrity": "sha512-vlU1H5mnfP0Ej8PbjcxwF9ZlT7LtcpekOKI4iYfMnfdelSUKUVyaD5PC8yRGIg9fxkorA6OM5AZs116jAl3TLA==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/types": "4.17.1", + "@polkadot/util": "^6.11.1", + "@polkadot/util-crypto": "^6.11.1", + "@polkadot/x-fetch": "^6.11.1", + "@polkadot/x-global": "^6.11.1", + "@polkadot/x-ws": "^6.11.1", + "eventemitter3": "^4.0.7" + } + }, + "@polkadot/types": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@polkadot/types/-/types-4.17.1.tgz", + "integrity": "sha512-rjW4OFdwvFekzN3ATLibC2JPSd8AWt5YepJhmuCPdwH26r3zB8bEC6dM7YQExLVUmygVPvgXk5ffHI6RAdXBMg==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/metadata": "4.17.1", + "@polkadot/util": "^6.11.1", + "@polkadot/util-crypto": "^6.11.1", + "@polkadot/x-rxjs": "^6.11.1" + } + }, + "@polkadot/types-known": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@polkadot/types-known/-/types-known-4.17.1.tgz", + "integrity": "sha512-YkOwGrO+k9aVrBR8FgYHnfJKhOfpdgC5ZRYNL/xJ9oa7lBYqPts9ENAxeBmJS/5IGeDF9f32MNyrCP2umeCXWg==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/networks": "^6.11.1", + "@polkadot/types": "4.17.1", + "@polkadot/util": "^6.11.1" + } + }, + "@polkadot/util": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-6.11.1.tgz", + "integrity": "sha512-TEdCetr9rsdUfJZqQgX/vxLuV4XU8KMoKBMJdx+JuQ5EWemIdQkEtMBdL8k8udNGbgSNiYFA6rPppATeIxAScg==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/x-textdecoder": "6.11.1", + "@polkadot/x-textencoder": "6.11.1", + "@types/bn.js": "^4.11.6", + "bn.js": "^4.11.9", + "camelcase": "^5.3.1", + "ip-regex": "^4.3.0" + } + }, + "@polkadot/util-crypto": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/util-crypto/-/util-crypto-6.11.1.tgz", + "integrity": "sha512-fWA1Nz17FxWJslweZS4l0Uo30WXb5mYV1KEACVzM+BSZAvG5eoiOAYX6VYZjyw6/7u53XKrWQlD83iPsg3KvZw==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/networks": "6.11.1", + "@polkadot/util": "6.11.1", + "@polkadot/wasm-crypto": "^4.0.2", + "@polkadot/x-randomvalues": "6.11.1", + "base-x": "^3.0.8", + "base64-js": "^1.5.1", + "blakejs": "^1.1.1", + "bn.js": "^4.11.9", + "create-hash": "^1.2.0", + "elliptic": "^6.5.4", + "hash.js": "^1.1.7", + "js-sha3": "^0.8.0", + "scryptsy": "^2.1.0", + "tweetnacl": "^1.0.3", + "xxhashjs": "^0.2.2" + } + }, + "@polkadot/wasm-crypto": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto/-/wasm-crypto-4.6.1.tgz", + "integrity": "sha512-2wEftBDxDG+TN8Ah6ogtvzjdZdcF0mAjU4UNNOfpmkBCxQYZOrAHB8HXhzo3noSsKkLX7PDX57NxvJ9OhoTAjw==", + "requires": { + "@babel/runtime": "^7.17.2", + "@polkadot/wasm-crypto-asmjs": "^4.6.1", + "@polkadot/wasm-crypto-wasm": "^4.6.1" + } + }, + "@polkadot/wasm-crypto-asmjs": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-4.6.1.tgz", + "integrity": "sha512-1oHQjz2oEO1kCIcQniOP+dZ9N2YXf2yCLHLsKaKSvfXiWaetVCaBNB8oIHIVYvuLnVc8qlMi66O6xc1UublHsw==", + "requires": { + "@babel/runtime": "^7.17.2" + } + }, + "@polkadot/wasm-crypto-wasm": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-4.6.1.tgz", + "integrity": "sha512-NI3JVwmLjrSYpSVuhu0yeQYSlsZrdpK41UC48sY3kyxXC71pi6OVePbtHS1K3xh3FFmDd9srSchExi3IwzKzMw==", + "requires": { + "@babel/runtime": "^7.17.2" + } + }, + "@polkadot/x-fetch": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/x-fetch/-/x-fetch-6.11.1.tgz", + "integrity": "sha512-qJyLLnm+4SQEZ002UDz2wWnXbnnH84rIS0mLKZ5k82H4lMYY+PQflvzv6sbu463e/lgiEao+6zvWS6DSKv1Yog==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/x-global": "6.11.1", + "@types/node-fetch": "^2.5.10", + "node-fetch": "^2.6.1" + } + }, + "@polkadot/x-global": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/x-global/-/x-global-6.11.1.tgz", + "integrity": "sha512-lsBK/e4KbjfieyRmnPs7bTiGbP/6EoCZz7rqD/voNS5qsJAaXgB9LR+ilubun9gK/TDpebyxgO+J19OBiQPIRw==", + "requires": { + "@babel/runtime": "^7.14.6" + } + }, + "@polkadot/x-randomvalues": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-6.11.1.tgz", + "integrity": "sha512-2MfUfGZSOkuPt7GF5OJkPDbl4yORI64SUuKM25EGrJ22o1UyoBnPOClm9eYujLMD6BfDZRM/7bQqqoLW+NuHVw==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/x-global": "6.11.1" + } + }, + "@polkadot/x-rxjs": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/x-rxjs/-/x-rxjs-6.11.1.tgz", + "integrity": "sha512-zIciEmij7SUuXXg9g/683Irx6GogxivrQS2pgBir2DI/YZq+um52+Dqg1mqsEZt74N4KMTMnzAZAP6LJOBOMww==", + "requires": { + "@babel/runtime": "^7.14.6", + "rxjs": "^6.6.7" + } + }, + "@polkadot/x-textdecoder": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/x-textdecoder/-/x-textdecoder-6.11.1.tgz", + "integrity": "sha512-DI1Ym2lyDSS/UhnTT2e9WutukevFZ0WGpzj4eotuG2BTHN3e21uYtYTt24SlyRNMrWJf5+TkZItmZeqs1nwAfQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/x-global": "6.11.1" + } + }, + "@polkadot/x-textencoder": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/x-textencoder/-/x-textencoder-6.11.1.tgz", + "integrity": "sha512-8ipjWdEuqFo+R4Nxsc3/WW9CSEiprX4XU91a37ZyRVC4e9R1bmvClrpXmRQLVcAQyhRvG8DKOOtWbz8xM+oXKg==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/x-global": "6.11.1" + } + }, + "@polkadot/x-ws": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@polkadot/x-ws/-/x-ws-6.11.1.tgz", + "integrity": "sha512-GNu4ywrMlVi0QF6QSpKwYWMK6JRK+kadgN/zEhMoH1z5h8LwpqDLv128j5WspWbQti2teCQtridjf7t2Lzoe8Q==", + "requires": { + "@babel/runtime": "^7.14.6", + "@polkadot/x-global": "6.11.1", + "@types/websocket": "^1.0.3", + "websocket": "^1.0.34" + } + }, + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" + }, + "@types/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "@types/websocket": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz", + "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==", + "requires": { + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "requires": { + "follow-redirects": "^1.14.8" + } + }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "blakejs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.1.tgz", + "integrity": "sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg==" + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "bufferutil": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", + "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "busboy": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", + "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==", + "requires": { + "dicer": "0.3.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=" + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dicer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", + "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", + "requires": { + "streamsearch": "0.1.2" + } + }, + "dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "es5-ext": { + "version": "0.10.58", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.58.tgz", + "integrity": "sha512-LHO+KBBaHGwjy32ibSaMY+ZzjpC4K4I5bPoijICMBL7gXEXfrEUrzssmNP+KigbQEp1dRUnGkry/vUnxOqptLQ==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "express-fileupload": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.3.1.tgz", + "integrity": "sha512-LD1yabD3exmWIFujKGDnT1rmxSomaqQSlUvzIsrA1ZgwCJ6ci7lg2YHFGM3Q6DfK+Yk0gAVU7GWLE7qDMwZLkw==", + "requires": { + "busboy": "^0.3.1" + } + }, + "ext": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", + "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "requires": { + "type": "^2.5.0" + }, + "dependencies": { + "type": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", + "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "requires": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "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==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "scryptsy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz", + "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==" + }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utf-8-validate": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz", + "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==", + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "requires": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + } + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "requires": { + "cuint": "^0.2.2" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" + } + } +} diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..e8f85ad --- /dev/null +++ b/backend/package.json @@ -0,0 +1,19 @@ +{ + "name": "fono-root-backend", + "version": "1.0.0", + "description": "Backend for Fono-Root that is doing file upload and IPFS pinning", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Peter Ott", + "license": "MIT", + "dependencies": { + "@crustio/crust-pin": "^1.0.0", + "axios": "^0.26.1", + "crypto-js": "^4.1.1", + "dotenv": "^16.0.0", + "express": "^4.17.3", + "express-fileupload": "^1.3.1" + } +} diff --git a/backend/routes/index.html b/backend/routes/index.html new file mode 100644 index 0000000..66b8da6 --- /dev/null +++ b/backend/routes/index.html @@ -0,0 +1,13 @@ + + + + Express File Upload + + +

Express File Upload

+
+ + +
+ + diff --git a/backend/routes/upload.js b/backend/routes/upload.js new file mode 100644 index 0000000..e58a25b --- /dev/null +++ b/backend/routes/upload.js @@ -0,0 +1,32 @@ +const express = require('express'); +const fileUpload = require("express-fileupload"); +const path = require("path"); + +const uploadHandler = require('../utils/uploadHandler.js'); +const router = express.Router(); + +// Middleware +router.use( + fileUpload({ + createParentPath: true, + limits: { + fileSize: 50 * 1024 * 1024 // 50 MB + }, + abortOnLimit: true + }) +); + + +router.get('/test', function(req, res) { + res.sendFile(path.join(__dirname, "index.html")); +}); + +router.post('/image', function(req, res) { + uploadHandler(req, res, "image"); +}); + +router.post('/music', function(req, res) { + uploadHandler(req, res, "music"); +}); + +module.exports = router; \ No newline at end of file diff --git a/backend/utils/ipfs.js b/backend/utils/ipfs.js new file mode 100644 index 0000000..6041bef --- /dev/null +++ b/backend/utils/ipfs.js @@ -0,0 +1,107 @@ +const { exec } = require('child_process'); +const axios = require('axios'); +const process = require('process'); +const dotenv = require('dotenv'); +dotenv.config(); +const crustPin = require('@crustio/crust-pin').default; + + +/** + * This function will add the file to the local IPFS repo. + * It will also start the pinning proccess, but that's an async function, and we are not awaiting for it. + * It will return the CID before the file is pinned in outside services (Infura, Pinata, Crust) + */ +function addFileToIPFS(path, callback) { + const alphaNumRegEx = /[a-zA-Z0-9]{22,}/g; + + exec(`ipfs add -Q ${path}`, function (error, stdout, stderr) { + if (error) { + console.log(`error: ${error.message}`); + cid = -1; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + cid = -2; + } + const cid = stdout.match(alphaNumRegEx)[0]; + if (cid !== -1 && cid !== -2) pinEverywhere(cid); // This will start the pinning process + callback(cid); // File is already added to local repo, we are sending back the CID to front-end + }); +} + +async function pinEverywhere(cid) { + pinToPinata(cid); // Pin to Pinata + pinToInfura(cid); // Pin to Infura + crustPin3Times(cid); // Pin to Crust +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function crustPin3Times(cid) { + console.log("Pinning to Crust..."); + const redundancyCount = 3; + const tolerance = 2; // Minimum success number + const maxTry = 3; // Max try for each pin + let successNum = 0; + + for (let i = 1; i <= redundancyCount; i++) { // We want to pin it 3 times, we will retry 3 times for each if failed + let success = false; + let tryCount = 0; + do { + const crust_seed = process.env.CRUST_SEED; // Get the seed from the blockchain + const crust = new crustPin(`${crust_seed}`); // Crust will pin the file on it's IPFS nodes + success = await crust.pin(cid); + if (success) successNum++; + await sleep(1000); + tryCount++; + } while (tryCount < maxTry && success === false); + } + console.log("Success Num: ", successNum); + return (successNum >= tolerance); +} + +async function pinToInfura(cid) { + console.log("Pinning to Infura..."); + let success = false; + + const authString = process.env.INFURA_PROJECT_ID + ":" + process.env.INFURA_PROJECT_SECRET; + const base64 = Buffer.from(authString).toString('base64') + const auth = 'Basic ' + base64; + + await axios.post(`https://ipfs.infura.io:5001/api/v0/pin/add?arg=${cid}`, {}, { headers: { 'Authorization' : auth } }) + .then((res) => success = true) + .catch((err) => console.error("Error: ", err)); + + if (success) console.log("The file was pinned to Infura"); + else console.error("There was an error while pinning to Infura"); + return success; +} + +async function pinToPinata(cid) { + console.log("Pinning to Pinata...") + + const headers = { + pinata_api_key: process.env.PINATA_API_KEY, + pinata_secret_api_key: process.env.PINATA_API_SECRET, + }; + const body = { + hashToPin: cid, + hostNodes: [ + process.env.LOCAL_IPFS_NODE // Because of the hostNodes property, Pinata will know that it should + ] // look for the file in our server. Otherwise it would look for it in the whole IPFS network. + } + let success = false; + + await axios.post("https://api.pinata.cloud/pinning/pinByHash", body, { headers }) + .then((res) => success = true) + .catch((err) => console.error(err)); + + + if (success) console.log("The file was pinned to Pinata"); + else console.error("There was an error while pinning to Pinata"); + return success; +} + +module.exports = addFileToIPFS; \ No newline at end of file diff --git a/backend/utils/uploadHandler.js b/backend/utils/uploadHandler.js new file mode 100644 index 0000000..51e15ef --- /dev/null +++ b/backend/utils/uploadHandler.js @@ -0,0 +1,40 @@ +const path = require("path"); +const addFileToIPFS = require('../utils/ipfs'); +const allowedImage = ['.png','.jpg','.jpeg']; +const allowedMusic = ['.mp3']; + +function uploadHandler(req, res, fileType) { + if (!req.files) { + return res.status(400).send("No files were uploaded."); + } + + const file = req.files.myFile; + const filePath = process.cwd() + "/files/" + file.name; + const extensionName = path.extname(file.name); // Fetch the file extension + if (fileType === "image") { + if(!allowedImage.includes(extensionName)){ + return res.status(422).send("Invalid Image"); + } + } + if (fileType === "music") { + if(!allowedMusic.includes(extensionName)) { + return res.status(422).send("Invalid Music"); + } + } + + file.mv(filePath, (err) => { + if (err) { + return res.status(500).send(err); + } + addFileToIPFS(filePath, function(cid) { + console.log("CID: ", cid) + if ( cid !== -1 && cid !== -2) { + return res.send({ status: "success", cid: cid }); + } else { + return res.send({ status: cid }); // Status will be -1 or -2 + } + }); // This function will call pinEverywhere + }); +} + +module.exports = uploadHandler; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8bbeb9b..ea1dc3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "UNLICENSED", "dependencies": { "@crustio/crust-pin": "^1.0.0", + "axios": "^0.26.1", "crypto-js": "^4.1.1", "cuid": "^2.1.8", "debounce": "^1.2.1", @@ -5739,42 +5740,13 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "node_modules/axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", - "deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410", - "dev": true, - "dependencies": { - "follow-redirects": "1.5.10" - } - }, - "node_modules/axios/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "dependencies": { - "ms": "2.0.0" + "follow-redirects": "^1.14.8" } }, - "node_modules/axios/node_modules/follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "dev": true, - "dependencies": { - "debug": "=3.1.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/axios/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "node_modules/axobject-query": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz", @@ -7220,6 +7192,43 @@ "universal-url": "^2.0.0" } }, + "node_modules/binary-install/node_modules/axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410", + "dev": true, + "dependencies": { + "follow-redirects": "1.5.10" + } + }, + "node_modules/binary-install/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/binary-install/node_modules/follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "dependencies": { + "debug": "=3.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/binary-install/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -13077,9 +13086,9 @@ "integrity": "sha1-kV4tbQI8Q9UiStn20qPEFW9XEvU=" }, "node_modules/follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", "funding": [ { "type": "individual", @@ -39006,38 +39015,11 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", - "dev": true, + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "requires": { - "follow-redirects": "1.5.10" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "dev": true, - "requires": { - "debug": "=3.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "follow-redirects": "^1.14.8" } }, "axobject-query": { @@ -40329,6 +40311,41 @@ "rimraf": "^3.0.0", "tar": "^5.0.5", "universal-url": "^2.0.0" + }, + "dependencies": { + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "dev": true, + "requires": { + "follow-redirects": "1.5.10" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "bindings": { @@ -45106,9 +45123,9 @@ "integrity": "sha1-kV4tbQI8Q9UiStn20qPEFW9XEvU=" }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" }, "for-in": { "version": "1.0.2", diff --git a/package.json b/package.json index 47e025a..f49276f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "build": "npm run build:contract && npm run build:web", "build:contract": "node contract/compile.js", "build:contract:debug": "node contract/compile.js --debug", - "build:web": "parcel build src/index.html --no-minify --public-url ./", + "build:web": "parcel build src/index.html --public-url ./", "dev:deploy:contract": "near dev-deploy", "deploy:contract": "near deploy", "deploy:pages": "gh-pages -d dist/", @@ -35,6 +35,7 @@ }, "dependencies": { "@crustio/crust-pin": "^1.0.0", + "axios": "^0.26.1", "crypto-js": "^4.1.1", "cuid": "^2.1.8", "debounce": "^1.2.1", diff --git a/src/Admin/Admin.js b/src/Admin/Admin.js index 01d0102..6dccd58 100644 --- a/src/Admin/Admin.js +++ b/src/Admin/Admin.js @@ -1,22 +1,16 @@ import React, { useState, useEffect, useCallback } from 'react'; import 'regenerator-runtime/runtime'; -const IPFS = require('ipfs-core') -const all = require('it-all') -const CryptoJS = require('crypto-js'); -const crustPin = require('@crustio/crust-pin').default; +const axios = require('axios'); +const CryptoJS = require('crypto-js'); import MediaDropzone from './MediaDropzone'; -import { getSeed, mintRootNFT, setSeed } from '../utils'; +import { mintRootNFT } from '../utils'; import PreviewBox from './PreviewBox'; -import Loading from './Loading'; import SmallUploader from './SmallUploader'; import infoLogo from '../assets/info.svg'; import ConnectWallet from './ConnectWallet'; -export default function Admin({newAction}) { - const [ipfsNode, setIpfsNode] = useState(null); - const [pageSwitch, setPageSwitch] = useState(0); // If no Crust seed is set yet, the user has to provide one - +export default function Admin({newAction}) { const [title, setTitle] = useState(""); const [desc, setDesc] = useState(""); const [price, setPrice] = useState("0"); @@ -32,26 +26,8 @@ export default function Admin({newAction}) { const [musicReady, setMusicReady] = useState(false); const [musicCID, setMusicCID] = useState(""); const [musicHash, setMusicHash] = useState(""); - - const [mnemonic, setMnemonic] = useState(""); - - function saveMnemonic() { - if (mnemonic.length === 0) return; - - let href = window.location.href; - href = href.slice(0, href.indexOf("?")+1); - history.pushState(null, "SetSeed", href + "?admin=1&setseed=1"); // This is important because of the notification we fire - const setSeedPromise = new Promise(async (resolve, reject) => { // when we got redirected to our page from near.org - await setSeed(mnemonic); - }) - newAction({ - thePromise: setSeedPromise, - pendingPromiseTitle: "Prepairing transaction...", pendingPromiseDesc: "plase wait", - successPromiseTitle: "Redirecting to transaction", successPromiseDesc: "Please sign the transaction in the next screen!", - errorPromiseTitle: "Redirecting to transaction", errorPromiseDesc: "Please sign the transaction in the next screen!" - }); - } + useEffect(async () => { const urlParams = window.location.search; let href = window.location.href; @@ -62,50 +38,14 @@ export default function Admin({newAction}) { newAction({ errorMsg: "There was an error during the transaction!", errorMsgDesc: URLSearchParams.get('errorCode'), }); - } else if (urlParams.includes('transactionHashes') && urlParams.includes('setseed')) { - newAction({ - successMsg: "Saved!", successMsgDesc: "The seed was saved.", - }); } else if (urlParams.includes('transactionHashes')) { newAction({ successMsg: "NFT Minted!", successMsgDesc: "The new RootNFT was successfully minted", }); } - - const seedBoolean = await getSeed() && true; - if (seedBoolean) setPageSwitch(2); // Key is already set - else setPageSwitch(1); // Need to set key - const tempIpfsNode = await IPFS.create(); - setIpfsNode(tempIpfsNode); }, []) - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - - async function crustPin3Times(ipfsFile) { - const redundancyCount = 3; - const tolerance = 2; // Minimum success number - const maxTry = 3; // Max try for each pin - let successNum = 0; - - for (let i = 1; i <= redundancyCount; i++) { // We want to pin it 3 times, we will retry 3 times for each if failed - let success = false; - let tryCount = 0; - do { - const crust_seed = await getSeed(); // Get the seed from the blockchain - const crust = new crustPin(`${crust_seed}`); // Crust will pin the file on it's IPFS nodes - success = await crust.pin(await ipfsFile.cid.toString()); - if (success) successNum++; - await sleep(1000); - tryCount++; - } while (tryCount < maxTry && success === false); - } - console.log("Success Num: ", successNum); - return (successNum >= tolerance); - } - - const onDropMedia = useCallback(async (acceptedFiles, ipfs) => { + const onDropMedia = useCallback(async (acceptedFiles) => { const file = acceptedFiles[0]; // We can only accept 1 file const reader = new FileReader(); reader.readAsArrayBuffer(file); // Read as array buffer, because we need that for SHA256 @@ -129,56 +69,55 @@ export default function Admin({newAction}) { reader.onload = async function () { // onload callback gets called after the reader reads the file data let wordArray = CryptoJS.lib.WordArray.create(reader.result); - - const ipfsPromise = ipfs.add({ // Add the file to IPFS. This won't last, this will be only stored in local node, that is in the browser - path: '.', - content: reader.result - }); - - newAction({ - thePromise: ipfsPromise, - pendingPromiseTitle: "Uploading to local (browser) IPFS node...", pendingPromiseDesc: "and this should be empty", - successPromiseTitle: "Done!", successPromiseDesc: "The file was uploaded to the local (browser) IPFS node.", - errorPromiseTitle: "Upload Failed", errorPromiseDesc: "Error while trying to upload to local IPFS node! Please Try again!", - }); - const ipfsFile = await ipfsPromise - - // This wrapper promise is necesarry, because the Crust API - // would resolve the promise even when the pinning fails - const uploadPromise = new Promise(async (resolve, reject) => { - let successBoolean = false; - - await crustPin3Times(ipfsFile) - .then((pinResult) => { // pinResult is boolean - if (pinResult && file.type.includes("image")) { - setImageHash(CryptoJS.SHA256(wordArray).toString()); - setImageCID(ipfsFile.cid.toString()); - setImageReady(true); - successBoolean = true; - } - if (pinResult && file.type.includes("audio")) { - setMusicHash(CryptoJS.SHA256(wordArray).toString()); - setMusicCID(ipfsFile.cid.toString()) - setMusicReady(true); - successBoolean = true; - } - }) - .catch((err) => console.error("Error from Crust: ", err)); + + // Upload the file to our server using Axios + if (file.type.includes("audio")) uploadFile(file, wordArray, "music"); + if (file.type.includes("image")) uploadFile(file, wordArray, "image"); + } + }); + + /** Upload file to server. The server will do the IPFS pinning */ + function uploadFile(file, wordArray, fileType) { + let successBoolean = false; + + const uploadPromise = new Promise(async (resolve, reject) => { + const formData = new FormData(); + formData.append("myFile", file); + const headers = { + 'Content-Type': 'multipart/form-data', + } + await axios.post(`http://172.105.246.99:3000/upload/${fileType}`, formData, { headers }) + .then((response) => { + console.log("THE RESPONSE: ", response); + if (fileType === "image") { + setImageHash(CryptoJS.SHA256(wordArray).toString()); + setImageCID(response.data.cid); + setImageReady(true); + successBoolean = true; + } + if (fileType === "music") { + setMusicHash(CryptoJS.SHA256(wordArray).toString()); + setMusicCID(response.data.cid) + setMusicReady(true); + successBoolean = true; + } + console.log("Media was uploaded.") + }) + .catch((err) => console.error("Error while uploading file", err)); if(successBoolean) { - resolve("Successfully pinned!") + resolve("(resolve) Successfully uploaded!") } else { - reject("Error occured while uploading the file to Crust!"); + reject("(reject) Error occured while uploading the file!"); } - }); - - newAction({ - thePromise: uploadPromise, - pendingPromiseTitle: "Uploading file to the Crust network...", pendingPromiseDesc: "", - successPromiseTitle: "File uploaded!", successPromiseDesc: "The file was uploaded to the network", - errorPromiseTitle: "Couldn't upload file to Crust!", errorPromiseDesc: "Couldn't upload file to Crust! Please check your Crust balance and try again!" - }); - }; - }); + }); + + newAction({ + thePromise: uploadPromise, + pendingPromiseTitle: "Uploading media...", pendingPromiseDesc: "", + successPromiseTitle: "File uploaded!", successPromiseDesc: "The file was successfully uploaded", + errorPromiseTitle: "Couldn't upload file!", errorPromiseDesc: "There was an error while uploading the file. Please try again!" + }); + } function createNFT() { if (!(imageReady && musicReady)) { @@ -222,102 +161,36 @@ export default function Admin({newAction}) { }); } - /** - * This is the code that we would be using for the site cloning, - * the IPFS-side of it works, but we couldn't create new contract instance - * from browser, so we don't have this feature. The following code is creating - * an almost equal IPFS site, but the `projectConfig.json` can be different. - * It would be also possible to add a different background image for example. - */ - async function folderExperiment() { - if (!ipfsNode) { console.log("The IPFS node is not ready."); return; } - - //await deployContract(); - - - const configObj = { - test: 5, - "contractName": "dev-1644223381077-49369947423471", - } - const strConfig = JSON.stringify(configObj); - let configFileName = null; - - const cid = 'QmQ6siYQBGKQKWqPBhCMWKJQZ3MxTSwpk7Ldc5vW1BGop2'; - const lsResult = await all(ipfsNode.files.ls('/')); - lsResult.map(async (line) => await ipfsNode.files.rm('/' + line.name, { recursive: true })); - - for await (const file of ipfsNode.ls(cid)) { - if (file.name.includes('projectConfig')) configFileName = file.name; - await ipfsNode.files.cp('/ipfs/' + file.path, '/' + file.name); - } - - console.log("configFileName: ", configFileName); - const configByteArray = new TextEncoder().encode(strConfig); - console.log("configByteArray: ", configByteArray) - await ipfsNode.files.rm('/' + configFileName); - await ipfsNode.files.write('/' + configFileName, configByteArray, { create: true, flush: true }); - - const res = await all(ipfsNode.files.read('/' + configFileName)); - console.log("TRS", res[0]) - const decoded = new TextDecoder().decode(res[0]); - console.log(decoded) - - const newnewstat = await ipfsNode.files.stat("/"); - const newnewlsResult = await all(ipfsNode.files.ls('/')); - console.log("stat: ", newnewstat); - console.log("ls: ", newnewlsResult); - - - await crustPin3Times(newnewstat) - .then((pinResult) => { // pinResult is boolean - if (pinResult) console.log("pinResult is true!"); - console.log("CID: ", newnewstat.cid.toString()); - }) - .catch((err) => console.error("Error from Crust: ", err)); - } - - if (!window.walletConnection.isSignedIn()) return - if (pageSwitch === 0) return + return (
- {pageSwitch === 1 &&
-

Enter CRUST Key

- setMnemonic(e.target.value)}> - -
} -
- {pageSwitch === 1 &&
} +

Mint NFT

-
- {ipfsNode && ( - <> - {!(imageReady || musicReady) ? - onDropMedia(files, ipfsNode)} accept={"image/*, audio/*"} /> - : ( - <> - {imageReady ? -

{image.name}

- : - onDropMedia(files, ipfsNode)} accept={"image/*"} /> } - {musicReady ? -

{music.name}

- : - onDropMedia(files, ipfsNode)} accept={"audio/*"} />} - - ) - } -
- -

{"Supported formats .jpg .png and .mp3"}

-
- - )} + {!(imageReady || musicReady) ? + onDropMedia(files)} accept={"image/*, audio/*"} /> + : ( + <> + {imageReady ? +

{image.name}

+ : + onDropMedia(files)} accept={"image/*"} /> } + {musicReady ? +

{music.name}

+ : + onDropMedia(files)} accept={"audio/*"} />} + + ) + } +
+ +

{"Supported formats .jpg .png and .mp3"}

+
setTitle(e.target.value)} /> @@ -332,7 +205,6 @@ export default function Admin({newAction}) {
-
) } diff --git a/src/projectConfig.json b/src/projectConfig.json index b10355f..66b99bf 100644 --- a/src/projectConfig.json +++ b/src/projectConfig.json @@ -1,5 +1,5 @@ { "test": "3", - "contractName": "dev-1645375679480-43401190499657", - "admin": "daorecords.testnet" + "contractName": "dev-1646768562393-54482198873294", + "admin": "optr.testnet" } \ No newline at end of file