-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[ADR-16] Refactor Folders #3732
Conversation
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've also been noodling away on this, please review #3738 as an alternative proposal and let me know what you think. We can line up a call to discuss in more detail if it's useful.
The biggest difference is that I don't want to have this pattern where we:
- pass an object to a decrypt method
- that method passes a service into a method on the object
- there are several levels of nested decrypt calls, passing down the same parameters each time, which you have to trace to find the actual decryption call still nested in
EncString
.
To me that is the real source of the tech debt here, it feels like decryption happens from the inside out, it's difficult to understand and extend. ContainerService
is just a symptom of that. I'd like to flatten it out to a method which acts on an object.
One goal that hasn't been noted in this PR, is the potential use case for a domain model to have multiple views with different amount of data. I kept the
|
Just a note on this topic, I'd like to avoid having lots of custom logic here or different ways of encrypting objects. I'd rather define a few ways of encrypting objects (e.g. individual EncStrings or an encrypted blob) and make people implement those, rather than give every object the ability to do something different. I probably have to experiment with more complex objects though to make sure that we can impose this kind of uniformity across our domain objects.
Nice idea! |
I don't particularly like that it's the The other issue I see here is this doesn't solve the central issue of how to grab the key to my liking. I think I'd like to see an interface on |
Having an interface on Domain to determine which key is used to encrypt things seems reasonable, it could be argued it's part of the domain model. Something that came to mind are Attachments, Name is an |
…crypt-test # Conflicts: # apps/cli/src/commands/create.command.ts # apps/cli/src/commands/edit.command.ts # libs/common/src/abstractions/crypto.service.ts # libs/common/src/abstractions/folder/folder.service.abstraction.ts # libs/common/src/importers/bitwardenJsonImporter.ts # libs/common/src/models/domain/folder.ts # libs/common/src/models/view/folder.view.ts # libs/common/src/services/crypto.service.ts # libs/common/src/services/folder/folder.service.ts
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.
Only one minor comment so far, unfortunately I didn't get to spend a lot of time on this today. Although no surprises immediately jump out at me, which is good. I'll continue Monday.
I'm still a little unsure what the end state of iirc, the last we discussed was potentially changing |
@eliykat I understand and I didn't want to muddle this PR with any refactoring of I agree with the move to |
This reverts commit e298cb1.
I've removed the This lets QA test both potions in isolation and we don't introduce the change until we've migrated Ciphers which prevents us from having 3 ways of doing encryption/decryption of domain models. |
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.
Mostly minor comments given that the cipher changes have been taken out and I think we've discussed the folder stuff quite a bit already.
To be honest I'm struggling with the various type/interface names (Decryptable
/Encryptable
) etc, but I don't have any better suggestions for them. I'll chew on it though.
folder.id = this.id; | ||
folder.revisionDate = this.revisionDate; | ||
|
||
folder.name = this.name != null ? await encryptService.encrypt(this.name, key) : null; |
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 think we can also use NullableFactory
here as well, right?
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.
Not really, it's not a constructor. We could make a nullable factory that accepts an argument with a factory in it.
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.
True. It's a similar pattern though (call a method if value isn't null), and this ternary condition will be repeated 100 times as we encrypt properties on objects under this new pattern.
import { EncryptService } from "../abstractions/encrypt.service"; | ||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; | ||
|
||
export function nullableFactory<T extends new (...args: any) => any>( |
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.
nullableFactory
seems broadly useful to me, I think it should stand outside of the crypto-specific code.
We can discuss it in the future PR, but I don't want to mix in any knowledge of views in the domain. Since domain is in the center and the ambition to support multiple views per domain. |
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.
Looks good to me, but I'd like a final review from @MGibson1.
…crypt-test # Conflicts: # apps/web/src/app/settings/change-password.component.ts
af7c425
to
43850ad
Compare
Removing myself from reviewers on the understanding this will be done in the SDK instead. |
Type of change
Objective
Refactors the Folder domain to follow the new method described in ADR-16. Please read the ADR for some background and the motivation for this move.
This PR focuses on introducing the core services needed for the new data model, and migrates the Folder domain.
The way this is implemented is by adding a generic method
decryptDomain
toCryptoService
. Which currently fetches the relevant encryption key and callsdecryptDomain
onEncryptionService
. Which in turns calls the static methodFolderView.decrypt(encryptionService, key, domain)
. Which performs the actual mapping from domain to view.Fetching of the encryption key is implemented for organizations and personal owned items. Personal items gets a null value assigned while organization items provides the organization ID as the identifier. In the future we can support more keys by adding more lookup locations.
Encryption works in a similar fashion using the
encryptView
which fetches the key and proxies the request toEncryptionService
which callsdecrypt
on the view.Why not just put the decrypt on
FolderService
? TheFolderService
already has a responsibility, and that is to maintain the state ofFolders
. We shouldn't give it more responsibilities, particularly not when theEncryptService
is already responsible for encrypting and decrypting things.Before you submit