Skip to content

Commit

Permalink
Merge pull request #323 from nevermined-io/feat/remove-dpt-dependency
Browse files Browse the repository at this point in the history
Feat/remove dpt dependency
  • Loading branch information
eruizgar91 authored Apr 8, 2024
2 parents de86949 + 5a9c108 commit c2fe253
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 507 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-ts",
"version": "2.4.8",
"version": "2.4.9",
"description": "Nevermined Node",
"main": "main.ts",
"scripts": {
Expand Down Expand Up @@ -39,7 +39,6 @@
"@nevermined-io/argo-workflows-api": "^0.1.3",
"@nevermined-io/passport-nevermined": "^0.3.0",
"@nevermined-io/sdk": "2.2.18",
"@nevermined-io/sdk-dtp": "^0.7.0-rc5",
"@sideway/address": "^5.0.0",
"@sideway/formula": "^3.0.1",
"@sideway/pinpoint": "^2.0.0",
Expand Down
42 changes: 21 additions & 21 deletions src/access/access.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import {
BadRequestException,
Body,
Controller,
ForbiddenException,
Get,
NotFoundException,
InternalServerErrorException,
Logger,
NotFoundException,
Param,
Post,
Query,
Expand All @@ -13,42 +15,40 @@ import {
StreamableFile,
UploadedFile,
UseInterceptors,
ForbiddenException,
Logger,
} from '@nestjs/common'
import { FileInterceptor } from '@nestjs/platform-express'
import {
ApiBadRequestResponse,
ApiBearerAuth,
ApiForbiddenResponse,
ApiInternalServerErrorResponse,
ApiNotFoundResponse,
ApiOperation,
ApiResponse,
ApiTags,
ApiBadRequestResponse,
ApiNotFoundResponse,
ApiInternalServerErrorResponse,
ApiForbiddenResponse,
} from '@nestjs/swagger'
import { Request } from '../common/helpers/request.interface'
import { Public } from '../common/decorators/auth.decorator'
import { FileInterceptor } from '@nestjs/platform-express'
import {
AgreementData,
DID,
ServiceType,
ValidationParams,
ZeroAddress,
generateId,
zeroX,
} from '@nevermined-io/sdk'
import crypto from 'crypto'
import { AssetResult, NeverminedService } from '../shared/nevermined/nvm.service'
import { aes_encryption_256 } from '../common/helpers/encryption.helper'
import { Public } from '../common/decorators/auth.decorator'
import { Request } from '../common/helpers/request.interface'
import {
AssetTransaction,
BackendService,
UserNotification,
} from '../shared/backend/backend.service'
import { AssetResult, NeverminedService } from '../shared/nevermined/nvm.service'
import { TransferDto } from './dto/transfer'
import { UploadDto } from './dto/upload'
import { UploadResult } from './dto/upload-result'
import {
generateId,
ValidationParams,
AgreementData,
ServiceType,
DID,
zeroX,
ZeroAddress,
} from '@nevermined-io/sdk'
import { aes_encryption_256 } from '@nevermined-io/sdk-dtp'

export enum UploadBackends {
IPFS = 'ipfs',
Expand Down
60 changes: 1 addition & 59 deletions src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { AuthService } from './auth.service'
import { JwtService } from '@nestjs/jwt'
import { NeverminedService } from '../shared/nevermined/nvm.service'
import { Test } from '@nestjs/testing'
import { Babysig, ServiceType, ValidationParams } from '@nevermined-io/sdk'
import { UnauthorizedException } from '@nestjs/common'
import { ServiceType, ValidationParams } from '@nevermined-io/sdk'

describe('AuthService', () => {
let authService: AuthService
Expand Down Expand Up @@ -50,11 +49,6 @@ describe('AuthService', () => {
list: jest.fn().mockResolvedValue([]),
},
}),
getDtp: jest.fn().mockReturnValue({
keytransfer: {
verifyBabyjub: jest.fn().mockResolvedValue(true),
},
}),
}
jwtServiceMock = {
sign: jest.fn().mockReturnValue('token'),
Expand Down Expand Up @@ -98,56 +92,4 @@ describe('AuthService', () => {
).toHaveBeenCalledWith(params)
})
})

describe('ValidateTransferProof', () => {
it('should throw an error if the signature is invalid', async () => {
nvmServiceMock.getDtp.mockReturnValue({
keytransfer: {
verifyBabyjub: jest.fn(() => Promise.resolve(false)),
},
})

const params: ValidationParams = {
did: '0x123',
agreement_id: '0x12345',
buyer: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
consumer_address: '0x0123456789abcdef0123456789abcdef0123456789',
babysig:
'0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' as never as Babysig,
}

await expect(authService.validateTransferProof(params)).rejects.toThrowError(
UnauthorizedException,
)
expect(nvmServiceMock.getDtp().keytransfer.verifyBabyjub).toHaveBeenCalledWith(
expect.any(Object),
BigInt('0x0123456789abcdef0123456789abcdef0123456789'),
'0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
)
})

it('should not throw an error if the signature is valid', async () => {
nvmServiceMock.getDtp.mockReturnValue({
keytransfer: {
verifyBabyjub: jest.fn(() => Promise.resolve(true)),
},
})

const params: ValidationParams = {
did: '0x123',
agreement_id: '0x12345',
buyer: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
consumer_address: '0x0123456789abcdef0123456789abcdef0123456789',
babysig:
'0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' as never as Babysig,
}

await expect(authService.validateTransferProof(params)).resolves.not.toThrowError()
expect(nvmServiceMock.getDtp().keytransfer.verifyBabyjub).toHaveBeenCalledWith(
expect.any(Object),
BigInt('0x0123456789abcdef0123456789abcdef0123456789'),
'0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
)
})
})
})
21 changes: 0 additions & 21 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
ServiceType,
ValidationParams,
didZeroX,
zeroX,
BabyjubPublicKey,
Logger,
Babysig,
DDO,
Expand Down Expand Up @@ -108,23 +106,6 @@ export class AuthService {
}
}

async validateTransferProof(params: ValidationParams): Promise<void> {
const dtp = this.nvmService.getDtp()
const buyerPub = new BabyjubPublicKey(
zeroX(params.buyer.substring(0, 64)),
zeroX(params.buyer.substring(64, 128)),
)
if (
!(await dtp.keytransfer.verifyBabyjub(
buyerPub,
BigInt(params.consumer_address),
params.babysig,
))
) {
throw new UnauthorizedException(`Bad signature for address ${params.consumer_address}`)
}
}

async validateClaim(payload: JWTPayload): Promise<LoginDto> {
try {
const params: ValidationParams = {
Expand All @@ -142,8 +123,6 @@ export class AuthService {
await this.validateOwner(params)
} else if (payload.aud === BASE_URL + 'nft-access') {
await this.validateAccess(params, 'nft-access')
} else if (payload.aud === BASE_URL + 'nft-sales-proof') {
await this.validateTransferProof(params)
}

const { iat: _iat, exp: _exp, ...accessTokenPayload } = payload
Expand Down
127 changes: 127 additions & 0 deletions src/common/helpers/encryption.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import crypto from 'crypto'
import { decrypt as ec_decrypt, encrypt as ec_encrypt } from 'eciesjs'
import { HDNodeWallet, ethers } from 'ethers'
import NodeRSA from 'node-rsa'

export interface CryptoConfig {
provider_key: string
provider_password: string
provider_rsa_public: string
provider_rsa_private: string
}

const get_aes_private_key = (passphrase: string) => {
const salt = Buffer.from('this is a salt')
const kdf = crypto.pbkdf2Sync(passphrase, salt, 48, 10000, 'sha256').toString('binary')
const key = kdf.substring(0, 16)
return Buffer.from(key, 'binary')
}

const BLOCK_SIZE = 16
const AES_BLOCK_SIZE = 16

function mod(a: number, n: number) {
return a - n * Math.floor(a / n)
}

const pad = (s: string) => {
const md = BLOCK_SIZE - mod(s.length, BLOCK_SIZE)
return s + String.fromCharCode(md).repeat(md)
}

const unpad = (s: string) => {
const num = s.charCodeAt(s.length - 1)
return s.substring(0, s.length - num)
}

const aes_encryption = (data, passphrase) => {
const private_key = get_aes_private_key(passphrase)
const iv = crypto.randomBytes(AES_BLOCK_SIZE)
const cipher = crypto.createCipheriv('aes-128-cbc', private_key, iv)
let res = cipher.update(pad(data), 'binary', 'binary')
res += cipher.final('binary')
return Buffer.from(iv.toString('binary') + res, 'binary').toString('base64')
}

const aes_decryption = (data64, passphrase) => {
const private_key = get_aes_private_key(passphrase)
const data = Buffer.from(data64, 'base64')
const iv = data.subarray(0, AES_BLOCK_SIZE)
const cipher = crypto.createDecipheriv('aes-128-cbc', private_key, iv)
let res = cipher.update(data.subarray(AES_BLOCK_SIZE).toString('binary'), 'binary', 'binary')
res += cipher.final('binary')
return unpad(res)
}

export const aes_encryption_256 = (data, passphrase) => {
const salt = crypto.randomBytes(BLOCK_SIZE - 'Salted__'.length)
const kdf = crypto.pbkdf2Sync(passphrase, salt, 10000, 48, 'sha256').toString('binary')
const private_key = Buffer.from(kdf.substring(0, 32), 'binary')
const iv = Buffer.from(kdf.substring(32, 48), 'binary')
const cipher = crypto.createCipheriv('aes-256-cbc', private_key, iv)
let res = cipher.update(pad(data), 'binary', 'binary')
res += cipher.final('binary')
return Buffer.from('Salted__' + salt.toString('binary') + res, 'binary').toString('binary')
}

export const aes_decryption_256 = (encrypted, password) => {
const salt = Buffer.from(encrypted.substring(8, 16), 'binary')
const keydata = crypto.pbkdf2Sync(password, salt, 10000, 48, 'sha256').toString('binary')
const key = Buffer.from(keydata.substring(0, 32), 'binary')
const iv = Buffer.from(keydata.substring(32, 48), 'binary')
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv)

let decrypted = decipher.update(encrypted.substring(16), 'binary', 'binary')
decrypted += decipher.final()
return unpad(decrypted)
}

export const encrypt = async (
config: CryptoConfig,
cipherText: string,
method: string,
): Promise<{ publicKey: string; result: string }> => {
if (method === 'PSK-ECDSA') {
const wallet = await ethers.Wallet.fromEncryptedJson(
config.provider_key,
config.provider_password,
)
const ecdh = crypto.createECDH('secp256k1')
ecdh.setPrivateKey(Buffer.from(wallet.privateKey.substring(2), 'hex'))
const result = ec_encrypt(ecdh.getPublicKey(), Buffer.from(cipherText)).toString('binary')
const res = {
publicKey: (wallet as HDNodeWallet).publicKey,
result,
}
return res
} else if (method === 'PSK-RSA') {
const key = new NodeRSA(config.provider_rsa_public)
const aes_key = crypto.randomBytes(16)
const encrypted_data = aes_encryption(cipherText, aes_key)
const encrypted_aes_key = key.encrypt(aes_key)
return {
publicKey: key.exportKey('public'),
result:
Buffer.from(encrypted_data).toString('hex') +
'|' +
Buffer.from(encrypted_aes_key).toString('hex'),
}
}
}

export const decrypt = async (config: CryptoConfig, cipherText: string, method: string) => {
if (method === 'PSK-ECDSA') {
const wallet = await ethers.Wallet.fromEncryptedJson(
config.provider_key,
config.provider_password,
)
const ecdh = crypto.createECDH('secp256k1')
ecdh.setPrivateKey(Buffer.from(wallet.privateKey.substring(2), 'hex'))
return ec_decrypt(ecdh.getPrivateKey(), Buffer.from(cipherText, 'binary')).toString()
} else if (method === 'PSK-RSA') {
const key = new NodeRSA(config.provider_rsa_private)
const [data, encrypted_aes_key] = cipherText.split('|')
const aes_key = key.decrypt(Buffer.from(encrypted_aes_key, 'hex'))
return aes_decryption(Buffer.from(data, 'hex').toString(), aes_key)
}
}
2 changes: 1 addition & 1 deletion src/encrypt/encrypt.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { JwtAuthGuard } from '../common/guards/auth/jwt-auth.guard'
import { EncryptController } from './encrypt.controller'
import request from 'supertest'
import { ConfigModule } from '../shared/config/config.module'
import { decrypt } from '@nevermined-io/sdk-dtp'
import { ConfigService } from '../shared/config/config.service'
import { decrypt } from '../common/helpers/encryption.helper'

/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument */

Expand Down
2 changes: 1 addition & 1 deletion src/encrypt/encrypt.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Logger } from '@nevermined-io/sdk'
import { EncryptDto } from './dto/encrypt'
import { EncryptResult } from './dto/result'
import { ConfigService } from '../shared/config/config.service'
import { encrypt } from '@nevermined-io/sdk-dtp'
import { encrypt } from '../common/helpers/encryption.helper'

@ApiTags('Encrypt')
@Controller()
Expand Down
Loading

0 comments on commit c2fe253

Please sign in to comment.