Skip to content

Commit

Permalink
[Job Launcher] Decrypt file after downloading (#1328)
Browse files Browse the repository at this point in the history
* decrypt file content after downloading

* use existing pgp private key
  • Loading branch information
leric7 authored Jan 18, 2024
1 parent 47b5f8b commit 180e32c
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { StorageClient } from '@human-protocol/sdk';
import { ConfigModule, registerAs } from '@nestjs/config';
import {
Encryption,
EncryptionUtils,
StorageClient,
} from '@human-protocol/sdk';
import { ConfigModule, ConfigService, registerAs } from '@nestjs/config';
import { Test } from '@nestjs/testing';
import {
MOCK_FILE_HASH,
MOCK_FILE_URL,
MOCK_MANIFEST,
MOCK_PGP_PRIVATE_KEY,
MOCK_S3_ACCESS_KEY,
MOCK_S3_BUCKET,
MOCK_S3_ENDPOINT,
Expand All @@ -23,6 +28,12 @@ jest.mock('@human-protocol/sdk', () => ({
StorageClient: {
downloadFileFromUrl: jest.fn(),
},
Encryption: {
build: jest.fn(),
},
EncryptionUtils: {
isEncrypted: jest.fn(),
},
}));

jest.mock('minio', () => {
Expand All @@ -45,6 +56,15 @@ describe('StorageService', () => {
let storageService: StorageService;

beforeAll(async () => {
const mockConfigService: Partial<ConfigService> = {
get: jest.fn((key: string) => {
switch (key) {
case 'MOCK_PGP_PRIVATE_KEY':
return MOCK_PGP_PRIVATE_KEY;
}
}),
};

const moduleRef = await Test.createTestingModule({
imports: [
ConfigModule.forFeature(
Expand All @@ -58,7 +78,10 @@ describe('StorageService', () => {
})),
),
],
providers: [StorageService],
providers: [
StorageService,
{ provide: ConfigService, useValue: mockConfigService },
],
}).compile();

storageService = moduleRef.get<StorageService>(StorageService);
Expand Down Expand Up @@ -128,11 +151,38 @@ describe('StorageService', () => {
],
};

EncryptionUtils.isEncrypted = jest.fn().mockReturnValueOnce(false);
StorageClient.downloadFileFromUrl = jest
.fn()
.mockResolvedValueOnce(expectedJobFile);
const solutionsFile = await storageService.download(MOCK_FILE_URL);
expect(solutionsFile).toBe(expectedJobFile);
expect(solutionsFile).toStrictEqual(expectedJobFile);
});

it('should download the encrypted file correctly', async () => {
const exchangeAddress = '0x1234567890123456789012345678901234567892';
const workerAddress = '0x1234567890123456789012345678901234567891';
const solution = 'test';

const expectedJobFile = {
exchangeAddress,
solutions: [
{
workerAddress,
solution,
},
],
};

EncryptionUtils.isEncrypted = jest.fn().mockReturnValueOnce(true);
StorageClient.downloadFileFromUrl = jest
.fn()
.mockResolvedValueOnce('encrypted');
Encryption.build = jest.fn().mockResolvedValueOnce({
decrypt: jest.fn().mockResolvedValueOnce(expectedJobFile),
});
const solutionsFile = await storageService.download(MOCK_FILE_URL);
expect(solutionsFile).toStrictEqual(expectedJobFile);
});

it('should return empty array when file cannot be downloaded', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { StorageClient } from '@human-protocol/sdk';
import {
Encryption,
EncryptionUtils,
StorageClient,
} from '@human-protocol/sdk';
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import * as Minio from 'minio';
import { S3ConfigType, s3ConfigKey } from '../../common/config';
import axios from 'axios';
import { ConfigNames, S3ConfigType, s3ConfigKey } from '../../common/config';
import { ErrorBucket } from '../../common/constants/errors';
import { parseString } from 'xml2js';
import stringify from 'json-stable-stringify';
import { ContentType, Extension } from '../../common/enums/storage';
import { UploadedFile } from '../../common/interfaces';
import { generateBucketUrl } from '../../common/utils/storage';
import { StorageDataDto } from '../job/job.dto';
import { JobRequestType } from '../../common/enums/job';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class StorageService {
Expand All @@ -19,6 +19,7 @@ export class StorageService {
constructor(
@Inject(s3ConfigKey)
private s3Config: S3ConfigType,
public readonly configService: ConfigService,
) {
this.minioClient = new Minio.Client({
endPoint: this.s3Config.endPoint,
Expand All @@ -36,7 +37,20 @@ export class StorageService {

public async download(url: string): Promise<any> {
try {
return await StorageClient.downloadFileFromUrl(url);
const fileContent = await StorageClient.downloadFileFromUrl(url);

if (
typeof fileContent === 'string' &&
EncryptionUtils.isEncrypted(fileContent)
) {
const encryption = await Encryption.build(
this.configService.get<string>(ConfigNames.PGP_ENCRYPT, ''),
);

return await encryption.decrypt(fileContent);
} else {
return fileContent;
}
} catch {
return [];
}
Expand Down
1 change: 1 addition & 0 deletions packages/apps/job-launcher/server/test/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const MOCK_MANIFEST: FortuneManifestDto = {
fundAmount: 10,
requestType: JobRequestType.FORTUNE,
};

export const MOCK_ENCRYPTED_MANIFEST = 'encryptedManifest';
export const MOCK_PGP_PRIVATE_KEY = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Expand Down

0 comments on commit 180e32c

Please sign in to comment.