diff --git a/scripts/generate-types.js b/scripts/generate-types.js index 760d1cb..176df3b 100644 --- a/scripts/generate-types.js +++ b/scripts/generate-types.js @@ -78,8 +78,8 @@ import { WalletService } from '../services/wallet-service'; signingKey: string; }\n\n`, `export enum WalletTypeEnum { - ED25519 = 'ED25519', - SECP256K1 = 'SECP256K1', + Etherum = 'etherum', + Solana = 'solana', }\n\n`, `export interface JWTData { did: string; diff --git a/src/common/types.ts b/src/common/types.ts index bec1341..41dde2f 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -26,8 +26,8 @@ export interface WalletSignMessageType { } export enum WalletTypeEnum { - ED25519 = 'ED25519', - SECP256K1 = 'SECP256K1', + Etherum = 'etherum', + Solana = 'solana', } export interface JWTData { diff --git a/src/helpers/helper.ts b/src/helpers/helper.ts index d13eb04..86372f4 100644 --- a/src/helpers/helper.ts +++ b/src/helpers/helper.ts @@ -46,9 +46,10 @@ export const parameterChecker = ( throw new Error('Need jwt or private key'); } - const urls = ['https://dev.api.gateway.tech']; + const urls = ['https://dev.api.gateway.tech', 'https://api.gateway.tech']; if (environment === 'dev') return { url: urls[0], mode, value }; + else if (environment === 'prod') return { url: urls[1], mode, value }; else throw new Error('No valid url found!. Use sandbox or production url'); }; diff --git a/src/services/wallet-service.ts b/src/services/wallet-service.ts index 9561557..3296081 100644 --- a/src/services/wallet-service.ts +++ b/src/services/wallet-service.ts @@ -16,9 +16,9 @@ export class WalletService { walletType?: WalletTypeEnum | undefined; }) { this.walletPrivateKey = walletPrivateKey; - this.walletType = walletType ? walletType : WalletTypeEnum.SECP256K1; + this.walletType = walletType ? walletType : WalletTypeEnum.Etherum; this.wallet = - this.walletType === WalletTypeEnum.SECP256K1 + this.walletType === WalletTypeEnum.Etherum ? new EtherumService(this.walletPrivateKey) : new SolanaService(this.walletPrivateKey); } diff --git a/test/data-asset.test.ts b/test/data-asset.test.ts index 084d923..04eaf10 100644 --- a/test/data-asset.test.ts +++ b/test/data-asset.test.ts @@ -24,6 +24,8 @@ import { dataAssetStub, } from './stubs/data-asset.stub'; import { routes } from '../src/common/routes'; +import { toRFC3339 } from '../src/helpers/helper'; +import { AccessLevel } from '../src/common/types'; jest.mock('openapi-fetch'); @@ -86,6 +88,46 @@ describe('Data Assets Test', () => { expect(id).toEqual(ID); }); + it('should create a file-based data asset with ACL and expiration date', async () => { + mockPost.mockResolvedValue(successMessage({ data: { id: ID } })); + + const fileName = 'test.txt'; + const fileBuffer = Buffer.from('test content'); + const mockACL = { address: '', roles: [AccessLevel.VIEW] }; + const mockExpirationDate = new Date('2024-10-01'); + + mockValidateFileName = jest + .spyOn(validationService, 'validateFileName') + .mockReturnValue({ + name: 'test-file', + extension: 'text/plain', + }); + + const id = await dataAsset.createNonStructured( + fileName, + fileBuffer, + mockACL, + mockExpirationDate, + ); + + expect(mockValidateFileName).toHaveBeenCalledWith(fileName); + expect(mockPost).toHaveBeenCalledWith('/data-assets', { + body: {}, + bodySerializer: expect.any(Function), + }); + + const formData = new FormData(); + formData.append( + 'data', + new Blob([fileBuffer], { type: 'text/plain' }), + fileName, + ); + formData.append('acl', JSON.stringify(mockACL)); + formData.append('expiration_date', toRFC3339(mockExpirationDate)); + + expect(id).toEqual(ID); + }); + it('should throw GTWError on failure for create file data asset', async () => { mockPost.mockResolvedValue(errorMessage()); @@ -239,6 +281,49 @@ describe('Data Assets Test', () => { expect(result).toEqual({ id: ID, name: 'Updated Data Asset' }); }); + it('should update a file-based data asset with ACL and expiration date', async () => { + const id = 1; + const fileName = 'test.txt'; + const fileBuffer = Buffer.from('test content'); + const mockACL = { address: '', roles: [AccessLevel.VIEW] }; + const mockExpirationDate = new Date('2024-10-01'); + + mockValidateFileName = jest + .spyOn(validationService, 'validateFileName') + .mockReturnValue({ + name: 'test-file', + extension: 'text/plain', + }); + + mockPut.mockResolvedValue(successMessage()); + + const result = await dataAsset.updateNonStructured( + id, + fileName, + fileBuffer, + mockACL, + mockExpirationDate, + ); + + expect(mockValidateFileName).toHaveBeenCalledWith(fileName); + expect(mockPut).toHaveBeenCalledWith('/data-assets/{id}', { + params: { path: { id } }, + body: {}, + bodySerializer: expect.any(Function), + }); + + const formData = new FormData(); + formData.append( + 'data', + new Blob([fileBuffer], { type: 'text/plain' }), + fileName, + ); + formData.append('acl', JSON.stringify(mockACL)); + formData.append('expiration_date', toRFC3339(mockExpirationDate)); + + expect(result).toBeDefined(); + }); + it('should throw GTWError on failure', async () => { const id = 1; const fileName = 'test.txt'; diff --git a/test/helper.test.ts b/test/helper.test.ts index 93da189..811e87a 100644 --- a/test/helper.test.ts +++ b/test/helper.test.ts @@ -12,7 +12,9 @@ import { Auth } from '../src/modules/auth/auth'; import { routes } from '../src/common/routes'; jest.mock('../src/modules/auth/auth'); -jest.mock('jsonwebtoken'); +jest.mock('jsonwebtoken', () => ({ + decode: jest.fn(), +})); describe('JWT Token Handling', () => { let config: { client: string; wallet: string }; @@ -26,9 +28,9 @@ describe('JWT Token Handling', () => { it('should return existing accessToken when the token is valid', async () => { jest.mock('../src/helpers/helper', () => ({ - ...jest.requireActual('../src/helpers/helper'), // preserve other exports + ...jest.requireActual('../src/helpers/helper'), checkJWTTokenExpiration: jest.fn().mockReturnValue(true), - issueJWT: jest.fn(), // Mock issueJWT but don't call it + issueJWT: jest.fn(), })); accessToken = 'mockAccessToken'; @@ -51,14 +53,31 @@ describe('JWT Token Handling', () => { describe('Utils', () => { describe('parameterChecker', () => { - it('should return dev URL for dev environment', () => { - expect(parameterChecker('dev', '', 'some-random-hex-key')).toStrictEqual({ + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should return dev URL and privateKey mode for dev environment', () => { + const result = parameterChecker('dev', '', 'some-random-hex-key'); + expect(result).toStrictEqual({ mode: 'privateKey', url: 'https://dev.api.gateway.tech', value: 'some-random-hex-key', }); }); + it('should throw error if JWT is expired', () => { + const mockExpiredJwt = 'expiredMockJwt'; + jest.mock('../src/helpers/helper', () => ({ + ...jest.requireActual('../src/helpers/helper'), + checkJWTTokenExpiration: jest.fn().mockReturnValue(false), + })); + + expect(() => parameterChecker('dev', mockExpiredJwt)).toThrow( + 'The provided token is expired or invalid.', + ); + }); + it('should throw error for invalid environment', () => { expect(() => parameterChecker('production' as any)).toThrow( 'Need jwt or private key', @@ -70,6 +89,10 @@ describe('Utils', () => { 'No url found!.Use either sandbox or production env', ); }); + + it('should throw error if neither JWT nor privateKey is provided', () => { + expect(() => parameterChecker('dev')).toThrow('Need jwt or private key'); + }); }); describe('AuthMiddleware', () => { @@ -153,4 +176,71 @@ describe('Utils', () => { expect(toRFC3339(date)).toBe('2023-05-15T10:30:00.000Z'); }); }); + + describe('checkJWTTokenExpiration', () => { + const mockCurrentTime = Math.floor(Date.now() / 1000); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return true if the token is valid and not expired', () => { + const mockToken = 'mockToken'; + const mockDecodedToken = { + exp: mockCurrentTime + 3600, + }; + + (jwt.decode as jest.Mock).mockReturnValue(mockDecodedToken); + + const result = checkJWTTokenExpiration(mockToken); + expect(jwt.decode).toHaveBeenCalledWith(mockToken); + expect(result).toBe(true); + }); + + it('should return false if the token is expired', () => { + const mockToken = 'mockToken'; + const mockDecodedToken = { + exp: mockCurrentTime - 100, + }; + + (jwt.decode as jest.Mock).mockReturnValue(mockDecodedToken); + + const result = checkJWTTokenExpiration(mockToken); + expect(jwt.decode).toHaveBeenCalledWith(mockToken); + expect(result).toBe(false); + }); + + it('should return false if the token does not have an exp field', () => { + const mockToken = 'mockToken'; + const mockDecodedToken = {}; + + (jwt.decode as jest.Mock).mockReturnValue(mockDecodedToken); + + const result = checkJWTTokenExpiration(mockToken); + expect(jwt.decode).toHaveBeenCalledWith(mockToken); + expect(result).toBe(true); + }); + + it('should return false if jwt.decode returns null', () => { + const mockToken = 'mockToken'; + + (jwt.decode as jest.Mock).mockReturnValue(null); + + const result = checkJWTTokenExpiration(mockToken); + expect(jwt.decode).toHaveBeenCalledWith(mockToken); + expect(result).toBe(false); + }); + + it('should return false if jwt.decode throws an error', () => { + const mockToken = 'mockToken'; + + (jwt.decode as jest.Mock).mockImplementation(() => { + throw new Error('Error decoding token'); + }); + + const result = checkJWTTokenExpiration(mockToken); + expect(jwt.decode).toHaveBeenCalledWith(mockToken); + expect(result).toBe(false); + }); + }); }); diff --git a/test/utils.test.ts b/test/utils.test.ts index b1803e0..8a94c75 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -233,7 +233,6 @@ describe('validateObjectProperties', () => { it('should throw an error if validation fails', () => { const obj = { did: 'invalidDID' }; - // Spy on the validateDID method and make it throw an error jest.spyOn(validationService, 'validateDID').mockImplementation(() => { throw new Error('Invalid DID'); });