From 8771519ee582413675f83136df935f18aff9b98e Mon Sep 17 00:00:00 2001 From: enrique Date: Wed, 7 Aug 2024 17:11:09 +0200 Subject: [PATCH] feat: add auxiliar methods to support download with sessionKeys --- package.json | 4 +-- src/nevermined/utils/JwtUtils.ts | 15 ++++++----- src/nevermined/utils/WebServiceConnector.ts | 30 ++++++++++++++------- src/services/node/NeverminedNode.ts | 24 ++++++++++++----- webpack.common.js | 2 +- 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index b61934f90..473b8d5ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nevermined-io/sdk", - "version": "3.0.22", + "version": "3.0.23", "description": "Javascript SDK for connecting with Nevermined Data Platform ", "main": "./dist/node/sdk.js", "typings": "./dist/node/sdk.d.ts", @@ -14,7 +14,7 @@ "jest:test": "jest --no-cache --coverage --rootDir test -w 1 ", "test": "mocha --config test/.mocharc.json ", "test:all": "mocha --config test/.mocharc.json ./test/**/*.test.ts", - "integration": "export NETWORK_NAME=geth-localnet ;mocha --config integration/.mocharc.json ", + "integration": "export NETWORK_NAME=${NETWORK_NAME} ;mocha --config integration/.mocharc.json ", "integration:all": "export NETWORK_NAME=geth-localnet;mocha --config integration/.mocharc.json ./integration/nevermined/*.test.ts", "integration:subgraph": "mocha --config integration/.mocharc.json ./integration/**/*.test.subgraph.ts", "integration:aave": "mocha --config aave_integration/.mocharc.json ./aave_integration/**/*.test.ts", diff --git a/src/nevermined/utils/JwtUtils.ts b/src/nevermined/utils/JwtUtils.ts index 3e90ba6b1..07890557c 100644 --- a/src/nevermined/utils/JwtUtils.ts +++ b/src/nevermined/utils/JwtUtils.ts @@ -1,12 +1,12 @@ +import { deflateSync, inflateSync } from 'fflate' import { JWSHeaderParameters, SignJWT, decodeJwt, importJWK } from 'jose' import { Account, Hash, LocalAccount, hexToBytes, toHex } from 'viem' +import { urlSafeBase64Decode, urlSafeBase64Encode } from '../../common/helpers' import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract' import { NvmAccount } from '../../models/NvmAccount' import { getChecksumAddress } from '../../nevermined/utils/BlockchainViemUtils' import { SignatureUtils } from '../../nevermined/utils/SignatureUtils' import { Babysig, Eip712Data } from '../../types/GeneralTypes' -import { deflateSync, inflateSync } from 'fflate' -import { urlSafeBase64Decode, urlSafeBase64Encode } from '../../common/helpers' export class EthSignJWT extends SignJWT { protectedHeader: JWSHeaderParameters @@ -63,14 +63,12 @@ export class EthSignJWT extends SignJWT { } else { sign = await signatureUtils.signText(decoder.decode(data), account) } - const input = hexToBytes(sign) const signed = this.base64url(input) const grantToken = `${decoder.decode(encodedHeader)}.${decoder.decode( encodedPayload, )}.${signed}` - return grantToken } @@ -329,6 +327,7 @@ export class JwtUtils extends Instantiable { account: NvmAccount, buyer?: string, babysig?: Babysig, + nvmApiKey?: string, ): Promise { const cacheKey = this.generateCacheKey(agreementId, account.getId(), did) @@ -341,10 +340,14 @@ export class JwtUtils extends Instantiable { buyer, babysig, ) - const accessToken = await this.nevermined.services.node.fetchToken(grantToken, 1) + + const accessToken = + account.getType() === 'sessionKey' + ? await this.nevermined.services.node.fetchToken(grantToken, 1, nvmApiKey) + : await this.nevermined.services.node.fetchToken(grantToken, 1) + // TODO: enable the cache back when this issue is fixed in the Node: https://github.com/nevermined-io/node/issues/225 // this.tokenCache.set(cacheKey, accessToken) - return accessToken } else { return this.nevermined.utils.jwt.tokenCache.get(cacheKey) as string diff --git a/src/nevermined/utils/WebServiceConnector.ts b/src/nevermined/utils/WebServiceConnector.ts index e96d9312e..18c0ec7f4 100644 --- a/src/nevermined/utils/WebServiceConnector.ts +++ b/src/nevermined/utils/WebServiceConnector.ts @@ -1,12 +1,12 @@ -import { BodyInit, RequestInit, Response } from 'node-fetch' -import fs, { ReadStream } from 'fs' -import { InstantiableConfig } from '../../Instantiable.abstract' import FormData from 'form-data' -import * as path from 'path' +import fs, { ReadStream } from 'fs' import fileDownload from 'js-file-download' +import { BodyInit, RequestInit, Response } from 'node-fetch' +import * as path from 'path' import { URL } from 'whatwg-url' -import { JwtUtils } from '../../nevermined/utils/JwtUtils' import { HttpError } from '../../errors/NeverminedErrors' +import { InstantiableConfig } from '../../Instantiable.abstract' +import { JwtUtils } from '../../nevermined/utils/JwtUtils' let fetch if (typeof window !== 'undefined') { @@ -162,14 +162,26 @@ export class WebServiceConnector { return this.fetch(url, { method: 'POST', body: form }) } - public async fetchToken(url: string, grantToken: string, numberTries = 1): Promise { + public async fetchToken( + url: string, + grantToken: string, + numberTries = 1, + nvmApiKey?: string, + ): Promise { + const bodyParams = new URLSearchParams({ + client_assertion_type: JwtUtils.CLIENT_ASSERTION_TYPE, + client_assertion: grantToken, + }) + + if (nvmApiKey) { + bodyParams.append('nevermined_api_key', nvmApiKey) + } + return await fetch( url, { method: 'POST', - body: `client_assertion_type=${encodeURI( - JwtUtils.CLIENT_ASSERTION_TYPE, - )}&client_assertion=${encodeURI(grantToken)}`, + body: bodyParams.toString(), headers: { 'Content-type': 'application/x-www-form-urlencoded', }, diff --git a/src/services/node/NeverminedNode.ts b/src/services/node/NeverminedNode.ts index 52eb59065..cd8a15c8b 100644 --- a/src/services/node/NeverminedNode.ts +++ b/src/services/node/NeverminedNode.ts @@ -1,11 +1,11 @@ -import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract' import { ReadStream } from 'fs' -import { Babysig, ERCType } from '../../types/GeneralTypes' -import { PublishMetadataOptions } from '../../types/MetadataTypes' -import { ImmutableBackends, MetaDataExternalResource, ServiceType } from '../../types/DDOTypes' -import { HttpError, NeverminedNodeError } from '../../errors/NeverminedErrors' import { DDO } from '../../ddo/DDO' +import { HttpError, NeverminedNodeError } from '../../errors/NeverminedErrors' +import { Instantiable, InstantiableConfig } from '../../Instantiable.abstract' import { NvmAccount } from '../../models/NvmAccount' +import { ImmutableBackends, MetaDataExternalResource, ServiceType } from '../../types/DDOTypes' +import { Babysig, ERCType } from '../../types/GeneralTypes' +import { PublishMetadataOptions } from '../../types/MetadataTypes' import { noZeroX } from '../../utils/ConversionTypeHelpers' const apiPath = '/api/v1/node/services' @@ -85,6 +85,10 @@ export class NeverminedNode extends Instantiable { return `${this.url}${apiPath}/oauth/token` } + public getFetchTokenWithNvmApiKeyEndpoint() { + return `${this.url}${apiPath}/oauth/nvmApiKey` + } + public getUploadFilecoinEndpoint() { return `${this.url}${apiPath}/upload/filecoin` } @@ -425,11 +429,17 @@ export class NeverminedNode extends Instantiable { } } - public async fetchToken(grantToken: string, numberTries = 3): Promise { + public async fetchToken( + grantToken: string, + numberTries = 3, + nvmApiKey?: string, + ): Promise { + const url = nvmApiKey ? this.getFetchTokenWithNvmApiKeyEndpoint() : this.getFetchTokenEndpoint() const response = await this.nevermined.utils.fetch.fetchToken( - this.getFetchTokenEndpoint(), + url, grantToken, numberTries, + nvmApiKey, ) if (!response.ok) { diff --git a/webpack.common.js b/webpack.common.js index 058b8af61..b0f687c8e 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -21,7 +21,7 @@ module.exports = { assert: require.resolve('assert/'), path: require.resolve('path-browserify'), stream: require.resolve('stream-browserify'), - vm: require.resolve("vm-browserify"), + vm: require.resolve('vm-browserify'), zlib: false, fs: false, },