From 713d46c81fe95d452b368dbd6eb28ce8e4cdc793 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Tue, 14 Jan 2025 09:59:20 +0100 Subject: [PATCH] add test draft --- .../store/slices/sharedLinks/index.test.ts | 149 ++++++++++++++++++ src/app/store/slices/sharedLinks/index.ts | 22 ++- 2 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 src/app/store/slices/sharedLinks/index.test.ts diff --git a/src/app/store/slices/sharedLinks/index.test.ts b/src/app/store/slices/sharedLinks/index.test.ts new file mode 100644 index 000000000..c5969c613 --- /dev/null +++ b/src/app/store/slices/sharedLinks/index.test.ts @@ -0,0 +1,149 @@ +/** + * @jest-environment jsdom + */ +import { describe, expect, it, vi, beforeEach, beforeAll } from 'vitest'; +import { sharedThunks, ShareFileWithUserPayload } from './index'; +const { shareItemWithUser } = sharedThunks; +import { generateNewKeys, hybridDecryptMessageWithPrivateKey } from '../../../crypto/services/pgp.service'; +import navigationService from 'app/core/services/navigation.service'; +import { RootState } from '../..'; +import { Buffer } from 'buffer'; +import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings'; +import userService from '../../../auth/services/user.service'; +import * as shareService from 'app/share/services/share.service'; + +describe('Encryption and Decryption', () => { + beforeAll(() => { + vi.mock('app/core/types', () => ({ + AppView: vi.fn(), + })); + vi.mock('app/core/services/navigation.service', () => ({ + default: { push: vi.fn() }, + })); + vi.mock('app/share/services/share.service', () => ({ + inviteUserToSharedFolder: vi.fn(), + getSharedFolderInvitationsAsInvitedUser: vi.fn(), + getSharingRoles: vi.fn(), + })); + vi.mock('../../../auth/services/user.service', () => ({ + default: { + getPublicKeyByEmail: vi.fn(), + preCreateUser: vi.fn(), + }, + })); + + vi.mock('../../../notifications/services/notifications.service', () => ({ + default: { + show: vi.fn(), + }, + ToastType: { + Error: 'ERROR', + }, + })); + vi.mock('app/core/services/error.service', () => ({ + default: { + castError: vi.fn().mockImplementation((e) => ({ message: e.message || 'Default error message' })), + reportError: vi.fn(), + }, + })); + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should setup workspace and encrypt mnemonic with kyber', async () => { + const keys = await generateNewKeys(); + const mockPayload: ShareFileWithUserPayload = { + publicKey: keys.publicKeyArmored, + publicKyberKey: keys.publicKyberKeyBase64, + isNewUser: false, + itemId: 'mock-itemId', + itemType: 'file', + notifyUser: false, + notificationMessage: 'mock-notificationMessage', + sharedWith: 'mock-sharedWith', + encryptionAlgorithm: 'mock-encryptionAlgorithm', + roleId: 'mock-roleId', + }; + + const mockUser: Partial = { + mnemonic: + 'truck arch rather sell tilt return warm nurse rack vacuum rubber tribe unfold scissors copper sock panel ozone harsh ahead danger soda legal state', + keys: { + ecc: { + publicKey: keys.publicKeyArmored, + privateKeyEncrypted: Buffer.from(keys.privateKeyArmored).toString('base64'), + }, + kyber: { + publicKey: keys.publicKyberKeyBase64, + privateKeyEncrypted: keys.privateKyberKeyBase64, + }, + }, + }; + + const mockRootState: Partial = { + user: { user: mockUser as UserSettings, isInitializing: false, isAuthenticated: false, isInitialized: false }, + }; + + const user = mockUser as UserSettings; + vi.spyOn(navigationService, 'push').mockImplementation(() => {}); + + const mockShareService = { + inviteUserToSharedFolder: vi.fn(), + getSharedFolderInvitationsAsInvitedUser: vi.fn(), + getSharingRoles: vi.fn(), + }; + + vi.spyOn(shareService, 'getSharedFolderInvitationsAsInvitedUser').mockImplementation( + mockShareService.getSharedFolderInvitationsAsInvitedUser, + ); + vi.spyOn(shareService, 'getSharingRoles').mockImplementation(mockShareService.getSharingRoles); + vi.spyOn(shareService, 'inviteUserToSharedFolder').mockImplementation(mockShareService.inviteUserToSharedFolder); + + vi.spyOn(userService, 'getPublicKeyByEmail').mockReturnValue( + Promise.resolve({ publicKey: user.keys.ecc.publicKey, publicKyberKey: user.keys?.kyber.publicKey }), + ); + vi.spyOn(userService, 'preCreateUser').mockReturnValue( + Promise.resolve({ + publicKey: user.keys.ecc.publicKey, + publicKyberKey: user.keys?.kyber.publicKey, + user: { + uuid: user.userId, + email: user.email, + }, + }), + ); + + const getStateMock = vi.fn(() => mockRootState as RootState); + const dispatchMock = vi.fn(); + + const thunk = shareItemWithUser(mockPayload); + await thunk(dispatchMock, getStateMock, undefined); + + const [inviteUserToSharedFolderInput] = mockShareService.inviteUserToSharedFolder.mock.calls[0]; + expect(inviteUserToSharedFolderInput.encryptionKey).toBeDefined(); + + const { encryptionKey = '' } = inviteUserToSharedFolderInput; + const decryptedMessage = await hybridDecryptMessageWithPrivateKey({ + encryptedMessageInBase64: encryptionKey, + privateKeyInBase64: Buffer.from(keys.privateKeyArmored).toString('base64'), + privateKyberKeyInBase64: keys.privateKyberKeyBase64, + }); + + expect(decryptedMessage).toEqual(mockUser.mnemonic); + expect(mockShareService.inviteUserToSharedFolder).toHaveBeenCalledWith( + expect.objectContaining({ + itemId: mockPayload.itemId, + itemType: mockPayload.itemType, + sharedWith: mockPayload.sharedWith, + notifyUser: mockPayload.notifyUser, + notificationMessage: mockPayload.notificationMessage, + encryptionKey: encryptionKey, + encryptionAlgorithm: mockPayload.encryptionAlgorithm, + roleId: mockPayload.roleId, + persistPreviousSharing: true, + }), + ); + }); +}); diff --git a/src/app/store/slices/sharedLinks/index.ts b/src/app/store/slices/sharedLinks/index.ts index f7cdce8c5..db5d3ca2d 100644 --- a/src/app/store/slices/sharedLinks/index.ts +++ b/src/app/store/slices/sharedLinks/index.ts @@ -1,9 +1,5 @@ import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit'; -import shareService, { - getSharedFolderInvitationsAsInvitedUser, - getSharingRoles, - inviteUserToSharedFolder, -} from 'app/share/services/share.service'; +import * as shareService from 'app/share/services/share.service'; import { RootState } from '../..'; import { Role, SharedFoldersInvitationsAsInvitedUserResponse } from '@internxt/sdk/dist/drive/share/types'; @@ -78,7 +74,7 @@ const shareItemWithUser = createAsyncThunk