Skip to content
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

Android alignment #25

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Android alignment #25

wants to merge 15 commits into from

Conversation

pauljohanneskraft
Copy link

Android alignment

♻️ Current situation & Problem

@eldcn brought up a couple of improvement ideas for SpeziStorage. Since we aim to keep the Android and iOS interfaces similar, this pull request brings those changes to the iOS frameworks. This is mostly a conversation starter to discuss those changes and ultimately build the best version of Spezi for both platforms.

@Supereg Please let me know what you think. More context regarding these changes is also contained in StanfordSpezi/SpeziKt#123 and StanfordSpezi/SpeziKt#108.

⚙️ Release Notes

  • Separates SecureStorage into CredentialStorage and KeyStorage.

📚 Documentation

Please ensure that you properly document any additions in conformance to Spezi Documentation Guide.
You can use this section to describe your solution, but we encourage contributors to document your reasoning and changes using in-line documentation.

✅ Testing

Please ensure that the PR meets the testing requirements set by CodeCov and that new functionality is appropriately tested.
This section describes important information about the tests and why some elements might not be testable.

📝 Code of Conduct & Contributing Guidelines

By submitting creating this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

@pauljohanneskraft pauljohanneskraft self-assigned this Oct 15, 2024
Copy link

codecov bot commented Oct 15, 2024

Codecov Report

Attention: Patch coverage is 79.80132% with 61 lines in your changes missing coverage. Please review.

Project coverage is 82.36%. Comparing base (6096237) to head (3626a28).

Files with missing lines Patch % Lines
...iSecureStorage/Credentials/CredentialStorage.swift 75.23% 28 Missing ⚠️
Sources/SpeziSecureStorage/Keys/KeyStorage.swift 81.19% 19 Missing ⚠️
...eziSecureStorage/Credentials/CredentialTypes.swift 0.00% 13 Missing ⚠️
...ources/SpeziSecureStorage/SecureStorageError.swift 92.31% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #25      +/-   ##
==========================================
- Coverage   90.28%   82.36%   -7.92%     
==========================================
  Files           6       10       +4     
  Lines         473      544      +71     
==========================================
+ Hits          427      448      +21     
- Misses         46       96      +50     
Files with missing lines Coverage Δ
Sources/SpeziLocalStorage/LocalStorage.swift 85.11% <100.00%> (+2.05%) ⬆️
...ources/SpeziLocalStorage/LocalStorageSetting.swift 100.00% <100.00%> (+2.71%) ⬆️
...es/SpeziSecureStorage/Credentials/Credential.swift 100.00% <100.00%> (ø)
Sources/SpeziSecureStorage/SecureStorage.swift 94.21% <100.00%> (+0.24%) ⬆️
...es/SpeziSecureStorage/SecureStorageItemTypes.swift 100.00% <100.00%> (ø)
...ources/SpeziSecureStorage/SecureStorageError.swift 92.31% <92.31%> (ø)
...eziSecureStorage/Credentials/CredentialTypes.swift 0.00% <0.00%> (ø)
Sources/SpeziSecureStorage/Keys/KeyStorage.swift 81.19% <81.19%> (ø)
...iSecureStorage/Credentials/CredentialStorage.swift 75.23% <75.23%> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6096237...3626a28. Read the comment docs.

Copy link

@eldcn eldcn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adaptions, I would propose to wait for @PSchmiedmayer and @Supereg input as well, but I will leave some additional thoughts on the state and some improvements from my pov:

SecureStorageScope – belongs to the LocalStorage target. In the SecureStorage target, we are only using the accessGroup property of it which can safely be required as a nullable string in the store method. A hint in the code that these components do not belong together: assert(!(.secureEnclave ~= storageScope), "Storing of keys in the secure enclave is not supported by Apple.").

Newly added KeyStorage also belongs to the LocalStorage target.
Dependencies should then be reversed: SecureStorage should depend on LocalStorage – however only as long as we continue to support the deprecations.

After that, we can completely cut the dependency between the two targets - We achieve a lower coupling this way between the targets

/// A pair of username and password credentials.
public struct Credentials: Equatable, Identifiable {
/// A user's credential containing username and password.
public struct Credential: Equatable, Identifiable {
/// The username.
public var username: String
/// The password.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider adding server parameter as well? It is not a breaking change if you initialize it with null

Copy link
Author

@pauljohanneskraft pauljohanneskraft Oct 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be the only change that would kind of force us to make a major-version update... Is it really worth it?

Alternatively, we could have those deprecation functions with the server-property being explicit and then we override in the deprecated function just to keep the minor version update. But what behavior should we choose there? Keeping the old struct with the slightly different name but without the server-property, always overriding the struct-property with the function parameter or doing something like server ?? credential.server or the other way around?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nevermind, changed it and deprecated SecureStorage as a whole. We now don't even have SecureStorage on Android anymore, since it isn't needed and just builds a Façade that isn't really necessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would make sense to ensure that we don't have to take a breaking change for now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But soft-deprecation is fine, right? Like I still kept the implementation of SecureStorage on iOS, but marked the whole class as deprecated. So, one can still use it as-is, but internally we are pretty much just calling the new functions instead.

Credential now has a server property, but if you use the deprecated functions, we internally only use the function parameter and ignore what was set in the Credential struct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly; that would be ideal. Once we tag a new major version we can remove all these deprecated function implementations.

Sounds like a good plan!

/// - size: The size of the key in bits. The default value is 256 bits.
/// - storageScope: The ``SecureStorageScope`` used to store the newly generate key.
/// - Returns: Returns the `SecKey` private key generated and stored in the keychain or the secure enclave.
@discardableResult
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be needed, it's quite an expensive operation and we should at least warn the clients to use the result 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be fine to allow this result be be discardable; given the fact that the key generation already takes a decent amount of time this might not make a huge difference. I don't think we require the user to store or process the private key as they could always get it again if needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may not be obvious, but both on Android and on iOS the key is actually already stored in the create function. So, even if you throw away the result, it wouldn't really matter much... I'm ultimately indifferent about this being marked discardableResult or not though, so I would rather keep it as it was.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good; we can keep it as it was for now, makes this backward compatible as well 👍

Copy link
Member

@PSchmiedmayer PSchmiedmayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for all the improvements; great to see this aligned with Android @pauljohanneskraft!

I only had minor comments, they were mainly targeted at enduring backward compatibility before e update to a few major version.

Thank you for the input @eldcn!

Happy to see this merged once the comments and discussion elements are addressed.

Sources/SpeziSecureStorage/SecureStorage.swift Outdated Show resolved Hide resolved
Sources/SpeziSecureStorage/SecureStorage.swift Outdated Show resolved Hide resolved
Sources/SpeziSecureStorage/SecureStorage.swift Outdated Show resolved Hide resolved
@@ -306,17 +192,23 @@ public final class SecureStorage: Module, DefaultInitializable, EnvironmentAcces
/// - removeDuplicate: A flag indicating if any existing key for the `username` of the new credentials and `newServer`
/// combination should be overwritten when storing the credentials.
/// - storageScope: The ``SecureStorageScope`` of the newly stored credentials.
public func updateCredentials( // swiftlint:disable:this function_default_parameter_at_end
public func updateCredential( // swiftlint:disable:this function_default_parameter_at_end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will also add a deprecated overload here; please ensure this for all methods that have changed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now made sure to not change the interface of SecureStorage at all and just deprecated it as a whole.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good 👍

/// - size: The size of the key in bits. The default value is 256 bits.
/// - storageScope: The ``SecureStorageScope`` used to store the newly generate key.
/// - Returns: Returns the `SecKey` private key generated and stored in the keychain or the secure enclave.
@discardableResult
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be fine to allow this result be be discardable; given the fact that the key generation already takes a decent amount of time this might not make a huge difference. I don't think we require the user to store or process the private key as they could always get it again if needed.

@PSchmiedmayer PSchmiedmayer added the enhancement New feature or request label Oct 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

3 participants