diff --git a/README.md b/README.md index 1fe1b1c2..893f86d9 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,9 @@ The Nevermined Node reads the following environment variables allowing the confi | **GRAPH_URL** | Public URL of the Nevermined subgraphs | | **NO_GRAPH** | If `true` the node will read events from the blockchain node instead of from the subgraphs. Depending on the network there could be a limit on the number of blocks to scan. | `false` +| **IPFS_GATEWAY** | Public IPFS gateway that can be used to fech or upload content. | https://ipfs.infura.io:5001 +| **IPFS_PROJECT_ID** | Ipfs Project Id | `2DSADASD4234234234` +| **IPFS_PROJECT_SECRET** | Ipfs Project Secret | `ccdafda55666dada` | **FILECOIN_GATEWAY** | Public Filecoin gateway that can be used to fech content. The `:cid` part of the url will be replace by the file `cid` | https://dweb.link/ipfs/:cid | **ESTUARY_TOKEN** | Estuary is a service that facilitates the interaction with Filecoin. This variable must include the token to use their API. See more here: https://estuary.tech/ | `EST651aa3a7-4756-4bd9-a563-1cdd565894645` | **AWS_S3_ACCESS_KEY_ID** | Amazon S3 Access Key Id | `4535hnj43` diff --git a/package.json b/package.json index 90577825..0d6f04e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-ts", - "version": "0.5.0", + "version": "0.5.1", "description": "Nevermined Node", "main": "main.ts", "scripts": { @@ -19,11 +19,11 @@ }, "dependencies": { "@nestjs/axios": "^1.0.0", - "@nestjs/common": "^8.4.0", - "@nestjs/core": "^8.4.0", - "@nestjs/jwt": "^8.0.0", + "@nestjs/common": "^8.4.5", + "@nestjs/core": "^8.4.5", + "@nestjs/jwt": "^8.0.1", "@nestjs/passport": "^8.2.1", - "@nestjs/platform-express": "^8.4.1", + "@nestjs/platform-express": "^8.4.5", "@nestjs/swagger": "^5.2.0", "@nestjs/typeorm": "^8.0.3", "@nevermined-io/argo-workflows-api": "^0.1.3", @@ -41,6 +41,7 @@ "cli-color": "^2.0.1", "dotenv": "^16.0.0", "eciesjs": "^0.3.15", + "ipfs-http-client-lite": "^0.3.0", "ethers": "^5.6.3", "fetch-blob": "^3.2.0", "form-data": "^4.0.0", diff --git a/src/access/access.controller.ts b/src/access/access.controller.ts index 49fc717b..7083aaab 100644 --- a/src/access/access.controller.ts +++ b/src/access/access.controller.ts @@ -3,6 +3,8 @@ import { Body, Controller, Get, + HttpException, + HttpStatus, NotFoundException, Param, Post, @@ -26,10 +28,18 @@ import { TransferDto } from './dto/transfer'; import { UploadDto } from './dto/upload'; import { UploadResult } from './dto/upload-result'; import { AgreementData } from '@nevermined-io/nevermined-sdk-js/dist/node/keeper/contracts/managers'; +import { utils } from '@nevermined-io/nevermined-sdk-js'; + +export enum UploadBackends { + IPFS = 'ipfs', + Filecoin = 'filecoin', + AmazonS3 = 's3', +} @ApiTags('Access') @Controller() export class AccessController { + constructor(private nvmService: NeverminedService) {} @Get('access/:agreement_id/:index') @@ -134,43 +144,52 @@ export class AccessController { @Post('upload/:backend') @ApiOperation({ - description: 'Access asset', + description: 'Uploads a file or some content to a remote storage', summary: 'Public', }) @Public() @UseInterceptors(FileInterceptor('file')) @ApiResponse({ status: 200, - description: 'Return the url of asset', + description: 'Return the url of the file uploaded', }) async doUpload( @Body() uploadData: UploadDto, - @Param('backend') backend: string, + @Param('backend') backend: UploadBackends, @UploadedFile() file: Express.Multer.File ): Promise { - if (!file) { - throw new BadRequestException('No file in request'); + let data: Buffer + let fileName: string + if (file) { + data = file.buffer; + fileName = file.originalname + } else if (uploadData.message) { + data = Buffer.from(uploadData.message) + fileName = `fileUpload_${utils.generateId()}.data${uploadData.encrypt?'.encrypted':''}` + } else { + throw new BadRequestException('No file or message in request'); } - let data = file.buffer; - if (uploadData.encrypt) { - // generate password - Logger.debug(`Uploading with password, filename ${file.originalname}`); - const password = crypto.randomBytes(32).toString('base64url'); - data = Buffer.from(aes_encryption_256(data, password), 'binary'); - if (backend === 's3') { - const url = await this.nvmService.uploadS3(data, file.originalname); - return { url, password }; - } else if (backend === 'filecoin') { - const url = await this.nvmService.uploadFilecoin(data, file.originalname); + console.log(`Backend ${backend}`) + if (!Object.values(UploadBackends).includes(backend)) + throw new BadRequestException(`Backend ${backend} not supported`); + try { + let url: string + if (uploadData.encrypt) { + // generate password + Logger.debug(`Uploading with password, filename ${fileName}`); + const password = crypto.randomBytes(32).toString('base64url'); + data = Buffer.from(aes_encryption_256(data, password), 'binary'); + url = await this.nvmService.uploadToBackend(backend, data, fileName); return { url, password }; } - } - if (backend === 's3') { - const url = await this.nvmService.uploadS3(data, file.originalname); - return { url }; - } else if (backend === 'filecoin') { - const url = await this.nvmService.uploadFilecoin(data, file.originalname); + + url = await this.nvmService.uploadToBackend(backend, data, fileName); return { url }; + + } catch (error) { + Logger.error(`Error processing upload: ${error.message}`); + throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR); } + } } diff --git a/src/access/access.integration.spec.ts b/src/access/access.integration.spec.ts index 2b7ac371..48015a36 100644 --- a/src/access/access.integration.spec.ts +++ b/src/access/access.integration.spec.ts @@ -93,8 +93,27 @@ describe('Info', () => { }); it('upload / no params', async () => { const response = await request(app.getHttpServer()) - .post(`/upload/method`); + .post(`/upload/ipfs`); expect(response.statusCode).toBe(400); - expect((response.error as any).text).toContain('No file'); + expect((response.error as any).text).toContain('No file or message'); }); + it('upload wrong backend', async () => { + const response = await request(app.getHttpServer()) + .post(`/upload/wrong`) + .send({ + message: 'hi there' + }); + expect(response.statusCode).toBe(400); + expect((response.error as any).text).toContain('Backend wrong not supported'); + }); + it('upload ipfs', async () => { + const response = await request(app.getHttpServer()) + .post(`/upload/ipfs`) + .send({ + message: 'hi there' + }); + expect(response.statusCode).toBe(201); + console.log(JSON.stringify(response.body)) + expect(response.body.url).toContain('cid://'); + }); }); diff --git a/src/access/dto/upload.ts b/src/access/dto/upload.ts index c6459895..bb653996 100644 --- a/src/access/dto/upload.ts +++ b/src/access/dto/upload.ts @@ -1,4 +1,5 @@ import { ApiProperty } from "@nestjs/swagger"; +import { string } from "joi"; export class UploadDto { @ApiProperty({ @@ -6,5 +7,12 @@ export class UploadDto { example: 'false', required: false, }) - encrypt: string; + encrypt: string; + @ApiProperty({ + type: string, + example: 'Hello!', + description: 'Message to upload', + required: false, + }) + message: string; } diff --git a/src/shared/nevermined/nvm.service.ts b/src/shared/nevermined/nvm.service.ts index 71859df6..63c9532c 100644 --- a/src/shared/nevermined/nvm.service.ts +++ b/src/shared/nevermined/nvm.service.ts @@ -14,6 +14,8 @@ import { didZeroX } from '@nevermined-io/nevermined-sdk-js/dist/node/utils'; import { HttpModuleOptions, HttpService } from '@nestjs/axios'; import { firstValueFrom } from 'rxjs'; import { AxiosError } from 'axios'; +import IpfsHttpClientLite from 'ipfs-http-client-lite'; +import { UploadBackends } from 'src/access/access.controller'; @Injectable() export class NeverminedService { @@ -224,7 +226,7 @@ export class NeverminedService { throw new InternalServerErrorException(obj.error); } - return 'cid://' + obj.cid; + return `cid://${obj.cid}`; } catch (e) { if (e instanceof AxiosError) { Logger.error('Axios Error: ', e.response); @@ -236,6 +238,47 @@ export class NeverminedService { } } + async uploadIPFS(content: Buffer, filename: string): Promise { + try { + Logger.debug(`Uploading to IPFS ${filename}`); + const ipfsAuthToken = this.getIPFSAuthToken(); + + const ipfs = IpfsHttpClientLite({ + apiUrl: this.config.get('IPFS_GATEWAY'), + ...(ipfsAuthToken && { + headers: { Authorization: `Basic ${ipfsAuthToken}` } + }) + }); + const addResult = await ipfs.add(content); + return `cid://${addResult[0].hash}`; + } catch (e) { + Logger.error(`Uploading ${filename}: IPFS error ${e}`); + throw new InternalServerErrorException(e); + } + } + + async uploadToBackend(backend: UploadBackends, data: Buffer, fileName: string): Promise { + if (backend === 's3') { + return await this.uploadS3(data, fileName); + } else if (backend === 'filecoin') { + return await this.uploadFilecoin(data, fileName); + } else if (backend === 'ipfs') { + return await this.uploadIPFS(data, fileName); + } + } + + private getIPFSAuthToken(): string | undefined { + + if (!this.config.get('IPFS_PROJECT_ID') || !this.config.get('IPFS_PROJECT_SECRET')) { + Logger.warn(`Infura IPFS_PROJECT_ID or IPFS_PROJECT_SECRET are not set - disabling ipfs auth`) + return undefined + } else { + return Buffer.from( + `${this.config.get('IPFS_PROJECT_ID')}:${this.config.get('IPFS_PROJECT_SECRET')}` + ).toString('base64') + } + } + private isDTP(main: MetaDataMain): boolean { return main.files && main.files.some((f) => f.encryption === 'dtp'); } diff --git a/yarn.lock b/yarn.lock index 0064cbf9..826d44c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1096,7 +1096,7 @@ webpack "5.73.0" webpack-node-externals "3.0.0" -"@nestjs/common@^8.4.0": +"@nestjs/common@^8.4.5": version "8.4.7" resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-8.4.7.tgz#fc4a575b797e230bb5a0bcab6da8b796aa88d605" integrity sha512-m/YsbcBal+gA5CFrDpqXqsSfylo+DIQrkFY3qhVIltsYRfu8ct8J9pqsTO6OPf3mvqdOpFGrV5sBjoyAzOBvsw== @@ -1106,7 +1106,7 @@ tslib "2.4.0" uuid "8.3.2" -"@nestjs/core@^8.4.0": +"@nestjs/core@^8.4.5": version "8.4.7" resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-8.4.7.tgz#fbec7fa744ac8749a4b966f759a6656c1cf43883" integrity sha512-XB9uexHqzr2xkPo6QSiQWJJttyYYLmvQ5My64cFvWFi7Wk2NIus0/xUNInwX3kmFWB6pF1ab5Y2ZBvWdPwGBhw== @@ -1119,7 +1119,7 @@ tslib "2.4.0" uuid "8.3.2" -"@nestjs/jwt@^8.0.0": +"@nestjs/jwt@^8.0.1": version "8.0.1" resolved "https://registry.yarnpkg.com/@nestjs/jwt/-/jwt-8.0.1.tgz#e00f6810705a75d5680903241f4e07272e59e6d5" integrity sha512-9WGfgngX8aclC/MC+CH35Ooo4iPVKc+7xLXaBV6o4ty8g2uZdPomry7cSdK/e6Lv623O/84WapThnPoAtW/jvA== @@ -1137,7 +1137,7 @@ resolved "https://registry.yarnpkg.com/@nestjs/passport/-/passport-8.2.2.tgz#32b3932b83740895f037eabaf812c44f5ec18b3a" integrity sha512-Ytbn8j7WZ4INmEntOpdJY1isTgdQqZkx5ADz8zsZ5wAp0t8tc5GF/A+GlXlmn9/yRPwZHSbmHpv7Qt2EIiNnrw== -"@nestjs/platform-express@^8.4.1": +"@nestjs/platform-express@^8.4.5": version "8.4.7" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-8.4.7.tgz#402a3d3c47327a164bb3867615f423c29d1a6cd9" integrity sha512-lPE5Ltg2NbQGRQIwXWY+4cNrXhJdycbxFDQ8mNxSIuv+LbrJBIdEB/NONk+LLn9N/8d2+I2LsIETGQrPvsejBg== @@ -1885,6 +1885,13 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -2146,7 +2153,15 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async@3.2.3: +async-iterator-to-pull-stream@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/async-iterator-to-pull-stream/-/async-iterator-to-pull-stream-1.3.0.tgz#3a6b9f3cceadff972ca20eb480e3cb43f8789732" + integrity sha512-NjyhAEz/sx32olqgKIk/2xbWEM6o8qef1yetIgb0U/R3oBgndP1kE/0CslowH3jvnA94BO4I6OXpOkTKH7Z1AA== + dependencies: + get-iterator "^1.0.2" + pull-stream-to-async-iterator "^1.0.1" + +async@3.2.3, async@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== @@ -2312,7 +2327,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2: +base-x@^3.0.2, base-x@^3.0.8: version "3.0.9" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== @@ -2576,7 +2591,7 @@ buffer@4.9.2: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.5.0: +buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -2708,6 +2723,17 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.6.2.tgz#362ea15378f1c39378ba786affbc1c9ef015ecfd" integrity sha512-lVZdhvbEudris15CLytp2u6Y0p5EKfztae9Fqa189MfNmln9F33XuH69v5fvNfiRN5/0eAUz2yJL3mo+nhaRKg== +cids@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" + integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.6.0" + multicodec "^1.0.0" + multihashes "~0.4.15" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2738,6 +2764,11 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +class-is@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" + integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== + class-transformer@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" @@ -2879,7 +2910,7 @@ colorette@^2.0.16: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -combined-stream@^1.0.8: +combined-stream@^1.0.6, combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -3805,6 +3836,11 @@ event-emitter@^0.3.5: d "1" es5-ext "~0.10.14" +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + events@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -3869,6 +3905,11 @@ expect@^29.0.0, expect@^29.3.1: jest-message-util "^29.3.1" jest-util "^29.3.1" +explain-error@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/explain-error/-/explain-error-1.0.4.tgz#a793d3ac0cad4c6ab571e9968fbbab6cb2532929" + integrity sha512-/wSgNMxFusiYRy1rd19LT2SQlIXDppHpumpWo06wxjflD1OYxDLbl6rMVw+U3bxD5Nuhex4TKqv9Aem4D0lVzQ== + express@4.18.1: version "4.18.1" resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf" @@ -4115,6 +4156,15 @@ fork-ts-checker-webpack-plugin@7.2.11: semver "^7.3.5" tapable "^2.2.1" +form-data@^2.4.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + form-data@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" @@ -4228,6 +4278,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" +get-iterator@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.2.tgz#cd747c02b4c084461fac14f48f6b45a80ed25c82" + integrity sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg== + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -4589,6 +4644,22 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +ipfs-http-client-lite@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/ipfs-http-client-lite/-/ipfs-http-client-lite-0.3.0.tgz#08d9428fde667b1c602bae6c95e77e04f86c280d" + integrity sha512-fmxEctpzqaPd0gooBuvjMwxSoqz15rwjjm2ZF3Ns4Ckz/zz5JEmiDKuwlMOfwkARd5Wsiy2FqQpQEvBTJ8R7Og== + dependencies: + abort-controller "^3.0.0" + async-iterator-to-pull-stream "^1.3.0" + buffer "^5.2.1" + cids "^0.7.1" + explain-error "^1.0.4" + form-data "^2.4.0" + iterable-ndjson "^1.1.0" + node-fetch "^2.6.0" + pull-stream-to-async-iterator "^1.0.2" + querystring "^0.2.0" + is-arguments@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -4851,6 +4922,13 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +iterable-ndjson@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/iterable-ndjson/-/iterable-ndjson-1.1.0.tgz#36f7e8a5bb04fd087d384f29e44fc4280fc014fc" + integrity sha512-OOp1Lb0o3k5MkXHx1YaIY5Z0ELosZfTnBaas9f8opJVcZGBIONA2zY/6CYE+LKkqrSDooIneZbrBGgOZnHPkrg== + dependencies: + string_decoder "^1.2.0" + iterare@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042" @@ -5820,6 +5898,39 @@ multer@1.4.4-lts.1: type-is "^1.6.4" xtend "^4.0.0" +multibase@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multibase@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" + integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multicodec@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" + integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== + dependencies: + buffer "^5.6.0" + varint "^5.0.0" + +multihashes@~0.4.15: + version "0.4.21" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" + integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -5882,7 +5993,7 @@ node-emoji@1.11.0: dependencies: lodash "^4.17.21" -node-fetch@2.6.7, node-fetch@^2.6.1: +node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -6347,6 +6458,18 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" +pull-stream-to-async-iterator@^1.0.1, pull-stream-to-async-iterator@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pull-stream-to-async-iterator/-/pull-stream-to-async-iterator-1.0.2.tgz#5cc1a3a146ef6bbf01c17755647369b683b24986" + integrity sha512-c3KRs2EneuxP7b6pG9fvQTIjatf33RbIErhbQ75s5r2MI6E8R74NZC1nJgXc8kcmqiQxmr+TWY+WwK2mWaUnlA== + dependencies: + pull-stream "^3.6.9" + +pull-stream@^3.6.9: + version "3.6.14" + resolved "https://registry.yarnpkg.com/pull-stream/-/pull-stream-3.6.14.tgz#529dbd5b86131f4a5ed636fdf7f6af00781357ee" + integrity sha512-KIqdvpqHHaTUA2mCYcLG1ibEbu/LCKoJZsBWyv9lSYtPkJPBq8m3Hxa103xHi6D2thj5YXa0TqK3L3GUkwgnew== + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -6389,6 +6512,11 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== +querystring@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" + integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -7029,7 +7157,7 @@ string.prototype.trimstart@^1.0.5: define-properties "^1.1.4" es-abstract "^1.20.4" -string_decoder@^1.1.1: +string_decoder@^1.1.1, string_decoder@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -7592,6 +7720,11 @@ validator@^13.7.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== +varint@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" + integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"