Skip to content

Commit

Permalink
Merge pull request #26 from nevermined-io/feat/more-tests
Browse files Browse the repository at this point in the history
More tests
  • Loading branch information
mrsmkl authored Oct 6, 2022
2 parents a6a08fa + 43c5caa commit f3bc4c7
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 165 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ RUN yarn

COPY src ./src
COPY config ./config
COPY package*.json ./
COPY package.json ./
COPY tsconfig* ./
COPY .env.sample ./.env
COPY .env.sample ./.env.sample
COPY accounts ./accounts

RUN yarn run setup:dev
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"@nestjs/platform-express": "^8.4.1",
"@nestjs/swagger": "^5.2.0",
"@nestjs/typeorm": "^8.0.3",
"@nevermined-io/nevermined-sdk-dtp": "0.0.6",
"@nevermined-io/nevermined-sdk-js": "0.24.0",
"@nevermined-io/nevermined-sdk-dtp": "^0.0.8",
"@nevermined-io/nevermined-sdk-js": "^0.24.1",
"@sideway/address": "^4.1.3",
"@sideway/formula": "^3.0.0",
"@sideway/pinpoint": "^2.0.0",
Expand Down
35 changes: 32 additions & 3 deletions src/access/access.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import { Body, Controller, Get, NotFoundException, Param, Post, Req, Response, StreamableFile, UploadedFile, UseInterceptors } from "@nestjs/common";
import {
BadRequestException,
Body,
Controller,
Get,
NotFoundException,
Param,
Post,
Req,
Response,
StreamableFile,
UploadedFile,
UseInterceptors
} from "@nestjs/common";
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
import { Request } from '../common/helpers/request.interface';
import { Public } from "../common/decorators/auth.decorator";
import { FileInterceptor } from "@nestjs/platform-express";
import crypto from 'crypto';
import { aes_encryption_256 } from "../common/helpers/utils";
import { aes_encryption_256 } from "@nevermined-io/nevermined-sdk-dtp/dist/utils";
import { ValidationParams } from "@nevermined-io/nevermined-sdk-js/dist/node/ddo/Service";
import BigNumber from "@nevermined-io/nevermined-sdk-js/dist/node/utils/BigNumber";
import { NeverminedService } from '../shared/nevermined/nvm.service';
import { Logger } from '../shared/logger/logger.service';
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";

@ApiTags('Access')
@Controller()
Expand All @@ -35,6 +49,9 @@ export class AccessController {
@Response({ passthrough: true }) res,
@Param('index') index: number,
): Promise<StreamableFile|string> {
if (!req.user.did) {
throw new BadRequestException('DID not specified');
}
return await this.nvmService.downloadAsset(req.user.did, index, res, req.user.address);
}

Expand Down Expand Up @@ -70,7 +87,13 @@ export class AccessController {
async doNftTransfer(@Body() transferData: TransferDto, @Req() req: Request<unknown>): Promise<string> {
Logger.debug(`Transferring NFT with agreement ${transferData.agreementId}`);
const nevermined = this.nvmService.getNevermined();
const agreement = await nevermined.keeper.agreementStoreManager.getAgreement(transferData.agreementId);
let agreement: AgreementData;
try {
agreement = await nevermined.keeper.agreementStoreManager.getAgreement(transferData.agreementId);
} catch (e) {
Logger.error(`Error resolving agreement ${transferData.agreementId}`);
throw new NotFoundException(`Agreement ${transferData.agreementId} not found`);
}
if (!agreement) {
Logger.error(`Agreement ${transferData.agreementId} not found`);
throw new NotFoundException(`Agreement ${transferData.agreementId} not found`);
Expand Down Expand Up @@ -104,6 +127,9 @@ export class AccessController {
@Response({ passthrough: true }) res,
@Param('index') index: number,
): Promise<StreamableFile|string> {
if (!req.user.did) {
throw new BadRequestException('DID not specified');
}
return await this.nvmService.downloadAsset(req.user.did, index, res, req.user.address);
}

Expand All @@ -119,6 +145,9 @@ export class AccessController {
description: 'Return the url of asset',
})
async doUpload(@Body() uploadData: UploadDto, @Param('backend') backend: string, @UploadedFile() file: Express.Multer.File): Promise<UploadResult> {
if (!file) {
throw new BadRequestException('No file in request');
}
let data = file.buffer;
if (uploadData.encrypt) {
// generate password
Expand Down
100 changes: 100 additions & 0 deletions src/access/access.integration.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Test } from '@nestjs/testing';
import { JwtAuthGuard } from '../common/guards/auth/jwt-auth.guard';
import { AccessController } from './access.controller';
import { NeverminedModule } from '../shared/nevermined/nvm.module';
import request from 'supertest';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from '../auth/auth.service.mock';
import { JwtStrategy } from '../common/strategies/jwt.strategy';
import { ConfigModule } from '../shared/config/config.module';

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

describe('Info', () => {
let app: INestApplication;
let authService: AuthService;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
NeverminedModule,
ConfigModule,
PassportModule,
JwtModule.register({
secret: 'secret',
signOptions: { expiresIn: '60m' },
}),
],
providers: [
AuthService,
JwtStrategy,
],
controllers: [AccessController],
exports: [],
}).compile();
app = moduleRef.createNestApplication();
authService = moduleRef.get<AuthService>(AuthService);
app.useGlobalPipes(new ValidationPipe());
app.useGlobalGuards(new JwtAuthGuard(new Reflector()));
await app.init();
});
it('no DID', async () => {
const response = await request(app.getHttpServer())
.get(`/access/0x/123`)
.set('Authorization', `Bearer ${await authService.createToken({})}`);
expect((response.error as any).text).toContain('DID not specified');
});
it('access / unknown asset', async () => {
const response = await request(app.getHttpServer())
.get(`/access/0x/123`)
.set(
'Authorization',
`Bearer ${await authService.createToken({did:"did:nv:0ebed8226ada17fde24b6bf2b95d27f8f05fcce09139ff5cec31f6d81a7cd2ea"})}`
);
expect((response.error as any).text).toContain('No such DID');
});
it('download / unknown asset', async () => {
const response = await request(app.getHttpServer())
.get(`/download/123`)
.set(
'Authorization',
`Bearer ${await authService.createToken({did:"did:nv:0ebed8226ada17fde24b6bf2b95d27f8f05fcce09139ff5cec31f6d81a7cd2ea"})}`
);
expect((response.error as any).text).toContain('No such DID');
});
it('nft-access / unknown asset', async () => {
const response = await request(app.getHttpServer())
.get(`/nft-access/0x/123`)
.set(
'Authorization',
`Bearer ${await authService.createToken({did:"did:nv:0ebed8226ada17fde24b6bf2b95d27f8f05fcce09139ff5cec31f6d81a7cd2ea"})}`
);
expect((response.error as any).text).toContain('No such DID');
});
it('nft-transfer / no post data', async () => {
const response = await request(app.getHttpServer())
.post(`/nft-transfer`);
expect((response.error as any).text).toContain('must be a string');
});
it('nft-transfer / unknown agreement', async () => {
const response = await request(app.getHttpServer())
.post(`/nft-transfer`)
.send({
nftType: 1155,
agreementId: '0ebed8226ada17fde24b6bf2b95d27f8f05fcce09139ff5cec31f6d81a7cd2ea',
nftReceiver: '0x123',
nftHolder: '0x123',
nftAmount: "1"
});
expect(response.statusCode).toBe(404);
expect((response.error as any).text).toContain('Agreement');
});
it('upload / no params', async () => {
const response = await request(app.getHttpServer())
.post(`/upload/method`);
expect(response.statusCode).toBe(400);
expect((response.error as any).text).toContain('No file');
});
});
41 changes: 41 additions & 0 deletions src/auth/auth.service.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { decodeJwt, JWTPayload } from 'jose';
import { CLIENT_ASSERTION_TYPE, EthSignJWT } from '../common/guards/shared/jwt.utils';
import { ethers } from 'ethers';

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

@Injectable()
export class AuthService {
constructor(
private jwtService: JwtService,
) {}

validateClaim(clientAssertionType: string, clientAssertion: string) {
if (clientAssertionType !== CLIENT_ASSERTION_TYPE) {
throw new UnauthorizedException('Invalid "assertion_type"');
}

const payload: JWTPayload = decodeJwt(clientAssertion);
delete payload.exp;
return {
access_token: this.jwtService.sign(payload),
};
}
async createToken(obj: any) {
const wallet = ethers.Wallet.createRandom();
const clientAssertion = await new EthSignJWT({
...obj,
iss: wallet.address,
})
.setProtectedHeader({ alg: 'ES256K' })
.setIssuedAt()
.setExpirationTime('60m')
.ethSign(wallet);

return this.validateClaim(CLIENT_ASSERTION_TYPE, clientAssertion).access_token;
};


}
22 changes: 0 additions & 22 deletions src/common/helpers/utils.spec.ts

This file was deleted.

119 changes: 0 additions & 119 deletions src/common/helpers/utils.ts

This file was deleted.

Loading

0 comments on commit f3bc4c7

Please sign in to comment.