FXCM-2273: Refactor login/encryption code into a new support crate - #7542
Conversation
27fea06 to
042d197
Compare
aa20b6c to
26697cb
Compare
jo
left a comment
There was a problem hiding this comment.
Thank you very much for this work!
I think that - contrary to our expectations - this represents a breaking change for Android and Swift users, since error handling has changed and the moved import. Therefore, accompanying pull requests for mobile applications would be necessary 😬 see https://github.com/mozilla/application-services/blob/main/docs/howtos/breaking-changes.md
And could you add a CHANGELOG entry?
| [External = "encryption"] | ||
| typedef interface StaticKeyManager; |
| bytes decrypt(bytes ciphertext); | ||
| }; | ||
| [External = "encryption"] | ||
| typedef trait EncryptorDecryptor; |
There was a problem hiding this comment.
I am not sure but this might be
typedef trait_with_foreign EncryptorDecryptor;
| bytes get_key(); | ||
| }; | ||
| [External = "encryption"] | ||
| typedef trait KeyManager; |
There was a problem hiding this comment.
and this
typedef trait_with_foreign KeyManager;
The pull request has been modified, dismissing previous reviews.
88f8453 to
51cb1fa
Compare
mhammond
left a comment
There was a problem hiding this comment.
just a quick driveby, but this looks great!
| Ok(encryption::create_canary(text, key)?) | ||
| } | ||
|
|
||
| pub fn check_canary(canary: &str, text: &str, key: &str) -> ApiResult<bool> { |
There was a problem hiding this comment.
The original code didn't have it before this PR, but I also don't see a reason why not to add it.
| @@ -0,0 +1,30 @@ | |||
| [package] | |||
| name = "encryption" | |||
There was a problem hiding this comment.
I don't like this name, it's too generic and kinda competes with rc_crypto for things generically called "encryption". I think we need some qualification here. Not sure what it might be - something likelogins-encryption, but clearly you are intending to make it more generic than that. I've no great ideas but maybe we can bike-shed?
There was a problem hiding this comment.
I agree, and I am open to suggestions as well.
There was a problem hiding this comment.
I think something along the lines of 'credential-cryptography` would better represent the intended purpose of this crate, but that is a bit of a lengthy name.
There was a problem hiding this comment.
still a fan of enc_dec and renaming EncryptorDecryptor to EncDec
There was a problem hiding this comment.
I'm good with either of those options. enc_dec has the advantage of matching exactly how it is used. Happy to leave this decision to y'all!
There was a problem hiding this comment.
I'm not a huge fan of enc_dec for two reasons:
- It's not really any more specific than
encryption - Could also be confused with
encoder/decoder(a.k.a codecs).
Reading through comments in this area of the code a bit closer suggest that it's really intended for encrypting database records, which by their nature a need to take the form of text both in their plaintext and ciphertext forms (otherwise, I would expect the DB schema to run into problems). And as I understand it, this is also going to be the same case later down the line when autofill starts to use it.
So, how about the name db-crypto, short for Database Cryptography?
e9eb7de to
cf77c1e
Compare
cc7212f to
74a97cc
Compare
74a97cc to
4aa695d
Compare
The pull request has been modified, dismissing previous reviews.
983e0d9 to
1df7392
Compare
b50d133 to
616d37a
Compare
c371c6e to
a49511a
Compare
bendk
left a comment
There was a problem hiding this comment.
This looks good to me overall, it's a fairly straightforward refactor that moves the functionality to a new crate. The only questions I have is around the error handling after the refactor. I think some of it can be removed and if so, I think it should be. It's also very possible that I'm missing something and we actually do need the error conversions that I flagged, so feel free to push back on this.
| impl GetErrorHandling for Error { | ||
| type ExternalError = DbCryptoApiError; | ||
|
|
||
| fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> { |
There was a problem hiding this comment.
When we designed the GetErrorHandling trait, the intended use was for converting errors in top-level API methods that are called in the application. This isn't exactly that, since the db-crypto crate is used by other components and all of this happens below that highest layer. Still, I think it makes sense to report these errors and it seems nice that we can define the logic once here.
Another way of looking at this is the public API of db-crypto is essentially the same as the public API of logins and other components. The fact that db-crypto gets consumed by logins and logins gets consumed by the Firefox application isn't relevant.
I'm not 100% sure what's right, but I'm feeling like the best course is to merge this and see how it works in practice.
There was a problem hiding this comment.
we have found a couple spots in the Firefox codebase that directly reference the types that got moved as a part of this refactoring (specifically toolkit/components/passwordmgr/storage-rust.sys.mjs). So it is not true that the db-crypto crate is exclusively private to this repository.
I must admit I am not enough of an expert on the Firefox side of things to know how this affects the error handling requirements here, and as such I opted to preserve as much of the original error handling traits as was possible.
There was a problem hiding this comment.
I agree with Ben here - this crate shouldn't need to have a "public" error with its own error handling. I haven't thought about options here but it does seem wrong, the consumer crates exposing this as their own variant seems all we need?
There was a problem hiding this comment.
In this sense, db-crypto does two things:
- It provides APIs internal to Application Services (EncryptorDecryptor, etc.)
- It exposes the PrimaryPasswordAuthenticator to the application
Actually, the PrimaryPasswordAuthenticator should provide the appropriate "public" error handling. And all internal traits (the rest: EncryptorDecryptor, KeyManager) should provide low-level ones. Right?
There was a problem hiding this comment.
I feel like we're in new territory here with this refactor.
Maybe PrimaryPasswordAuthenticator could have it's own error enum. It's a callback interface, so it would make sense that it has a different error hierarchy than the normal API. I'm not sure how this would look in practice, but it could be worth a try.
For the rest of the API, I'm not really sure if how we should be conceptualizing it. Like I said in that first comment, I can see it both ways. The one thing I like about having the error handling is this crate, is that I think it makes more sense to define what gets reported as an error in db-crypto rather than in every crate that depends on db-crypto.
The pull request has been modified, dismissing previous reviews.
187938f to
78f5a03
Compare
mhammond
left a comment
There was a problem hiding this comment.
this looks great to me, I'll let Ben finish any thoughts on the errors, but ![]()
| @@ -0,0 +1,81 @@ | |||
| /* This Source Code Form is subject to the terms of the Mozilla Public | |||
There was a problem hiding this comment.
fyi, we are kinda moving away from UDL, so this is fine. But optionally here or in followup it can die and use uniffi macros.
| impl GetErrorHandling for Error { | ||
| type ExternalError = DbCryptoApiError; | ||
|
|
||
| fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> { |
There was a problem hiding this comment.
I agree with Ben here - this crate shouldn't need to have a "public" error with its own error handling. I haven't thought about options here but it does seem wrong, the consumer crates exposing this as their own variant seems all we need?
bendk
left a comment
There was a problem hiding this comment.
The code changes look good to me and I like the name db-crypto. It looks like the last thing to figure out is the error handling. I'm okay with the current system so I'm going to hit the approve button. However, I think it would be good to discuss it some more in that comment thread before merging.
This attempts to refactor the credential encryption code and move it into it's own support crate so that it can be re-used by other modules in the a-s ecosystem, and is a prerequisite for supporting encrypted autofill (eg: to store things like payment details).
There were some changes made to the uniffi API to enable this work, but logically there should be no meaningful changes to the API, and it should be compatible with no changes to the consumers of this code. It's a bit unclear to me how serious these changes are, and whether they constitute an API change. The changes include:
logins.udland into a new crateencryption.udl.logins.udlas external types.LoginsApiErrorto anEncryptionApiError.NSSKeyManagertype now takes akey_nameparameter, though as far as I can tell, theNSSKeyManagerwas never acually exposed by uniffi.Downstream, when merged into Firefox, this will require the following changes to be made:
createKey(),checkCanary()andcreateCanary()have been moved frommozilla.appservices.loginstomozilla.appservices.db_cryptoPrimaryPasswordAuthenticatorwill need to be moved fromRustLogins.sys.mjstoRustDbCrypto.sys.mjsRelated JIRA Issues:
Pull Request checklist
[ci full]to the PR title.