-
Notifications
You must be signed in to change notification settings - Fork 12
[PB-5709]: feat/add-b2b-workspaces #467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…onal user information
…ctionality for workspace management
…d token management
…ace-specific file creation
…vFolderService for proper asynchronous handling
… handlers, and fixed tests
…ds for consistency
…pty for consistency
…d test reliability
|
| SdkManager.init({ token: userCredentials.token }); | ||
| await ConfigService.instance.saveUser({ ...userCredentials, workspace: undefined }); | ||
| CLIUtils.success(this.log.bind(this), 'Personal drive space selected successfully.'); | ||
| return { success: true, message: 'Personal drive space selected successfully.' }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could encapsulate this logic as you are basically using the same as the use-personal command and reuse it on both places
| if (workspaceTokenDetails.expiration.refreshRequired) { | ||
| SdkManager.init({ token: loginCreds.token, workspaceToken: loginCreds.workspace.workspaceCredentials.token }); | ||
| const workspaceCredentials = await WorkspaceService.instance.getWorkspaceCredentials(workspaceUuid); | ||
| // TODO refresh also workspace data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could reference here a jira ticket so that this todo does not gets forgotten if you dont want to do this change is this pr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also having a look at workspaceData, how much this object is going to change? is it necessary? just out of curiosity
| const privateKeyInBase64 = user.keys?.ecc?.privateKey ?? ''; | ||
| const privateKyberKeyInBase64 = user.keys?.kyber?.privateKey ?? ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what this function is trying to do: Decrypt if possible, default to fallback otherwise.
But this approach have some hidden costs:
the catch block without the proper error handling could make for silent errors, and also raises me this question: does it even make sense to throw an exception that we arent going to handle?
Mutable state increases cognitive load unnecessarly
by fallbacking privateKyberKeyInBase64 and privateKeyInBase64, we are running decryption that we know it will fail.
If we structure this to fail fast and handle each path explicitly. It becomes easier to test and read.
What do you think about this, for example?
private readonly decryptMnemonic = async (
encryptionKey: string,
user: LoginCredentials['user']
): Promise<string> => {
const privateKeyInBase64 = user.keys?.ecc?.privateKey;
const privateKyberKeyInBase64 = user.keys?.kyber?.privateKey;
if (!privateKeyInBase64 || !privateKyberKeyInBase64) {
return user.mnemonic;
}
try {
return await KeysService.instance.hybridDecryptMessageWithPrivateKey({
encryptedMessageInBase64: encryptionKey,
privateKeyInBase64,
privateKyberKeyInBase64,
});
} catch (error) {
logger.warn('Decryption failed, using fallback mnemonic', { error });
return user.mnemonic;
}
};This way getting rid of the let, it makes the code much more linear
| public createFile = async (payload: StorageTypes.FileEntryByUuid): Promise<DriveFileItem> => { | ||
| const storageClient = SdkManager.instance.getStorage(); | ||
| const driveFile = await storageClient.createFileEntryByUuid(payload); | ||
| let driveFile: StorageTypes.DriveFileData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is another example:
you could split this function into 2:
public createFile = async (payload: StorageTypes.FileEntryByUuid): Promise<DriveFileItem> => {
const driveFile = await this.createDriveFileEntry(payload);
return {
itemType: 'file',
name: payload.plainName,
id: driveFile.id,
uuid: driveFile.uuid,
size: driveFile.size,
bucket: driveFile.bucket,
createdAt: new Date(driveFile.createdAt),
updatedAt: new Date(driveFile.updatedAt),
fileId: driveFile.fileId,
type: driveFile.type,
status: driveFile.status as DriveFileItem['status'],
folderId: driveFile.folderId,
folderUuid: driveFile.folderUuid,
creationTime: new Date(driveFile.creationTime ?? driveFile.createdAt),
modificationTime: new Date(driveFile.modificationTime ?? driveFile.updatedAt),
};
};
private async createDriveFileEntry(
payload: StorageTypes.FileEntryByUuid
): Promise<StorageTypes.DriveFileData> {
const currentWorkspace = await AuthService.instance.getCurrentWorkspace();
if (currentWorkspace) {
const workspaceClient = SdkManager.instance.getWorkspaces();
return workspaceClient.createFileEntry(
{
name: payload.plainName,
plainName: payload.plainName,
bucket: payload.bucket,
fileId: payload.fileId ?? '',
encryptVersion: StorageTypes.EncryptionVersion.Aes03,
folderUuid: payload.folderUuid,
size: payload.size,
type: payload.type ?? '',
modificationTime: payload.modificationTime ?? new Date().toISOString(),
date: payload.date ?? new Date().toISOString(),
},
currentWorkspace.workspaceCredentials.id,
);
}
const storageClient = SdkManager.instance.getStorage();
return storageClient.createFileEntryByUuid(payload);
}This way, each function has one job only and we dont have uninitialized variables
| kyberSecret = decapsulate.sharedSecret; | ||
| } | ||
|
|
||
| const decryptedMessage = await this.decryptMessageWithPrivateKey({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could make this method return a string instead of forcing the type using 'as', this can be delicate and have an easy solution
| decryptionKeys: privateKey, | ||
| }); | ||
|
|
||
| return decryptedMessage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here you can use .toString() and then we can change the return type of the function to string, if necessary, right? since the return value of this function is only being used as string
| static readonly instance = new LocalFilesystemService(); | ||
|
|
||
| async scanLocalDirectory(path: string): Promise<ScanResult> { | ||
| public scanLocalDirectory = async (path: string): Promise<ScanResult> => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you change it to arrow function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to maintain consistency with other methods and classes that use arrow functions too, and also to automatically preserve the this context in case the method is passed as a callback or destructured. However, if you think it's not necessary in this case or if we should have a preference in the project for 'traditional' methods, we can always refactor all the methods, but for me is better this way


Adds B2B workspaces
internxt workspaces useinternxt workspaces listinternxt workspaces unsetorinternxt workspaces use --personalImproved and simplified services
Improved and simplified WebDAV handlers and server
Refactored some util classes for better testing process
Fixed tests and changed from vi.mock to vi.spyon for better consistency