[Valet 4.0] Allow kSecAttrService to be a customer-friendly string on Mac#154
[Valet 4.0] Allow kSecAttrService to be a customer-friendly string on Mac#154dfed merged 34 commits intodevelop--4.0from
Conversation
|
Note that I'll probably want to tackle #123 before this merges. |
fadccad to
1a1d23c
Compare
|
This all looks good to me! |
1a1d23c to
64979d4
Compare
|
I've updated the README to include information on this new API. Note that getting this API to compile will require dropping Xcode 9 support. I'm not yet willing to do that, so this PR will stay open until we have more we'd want to roll into a breaking change. |
0c9efbe to
b03a958
Compare
921aa52 to
f087d9e
Compare
51caa23 to
f009f7b
Compare
f087d9e to
e9848e0
Compare
d00a634 to
100df92
Compare
100df92 to
ebf1e11
Compare
ebf1e11 to
0bb4fa1
Compare
| The identifier you choose for your Valet is used to create a sandbox for the data your Valet writes to the keychain. Two Valets of the same type created via the same initializer, accessibility value, and identifier will be able to read and write the same key:value pairs; Valets with different identifiers each have their own sandbox. Choose an identifier that describes the kind of data your Valet will protect. You do not need to include your application name or bundleIdentifier in your Valet’s identifier. | ||
| The identifier you choose for your Valet is used to create a sandbox for the data your Valet writes to the keychain. Two Valets of the same type created via the same initializer, accessibility value, and identifier will be able to read and write the same key:value pairs; Valets with different identifiers each have their own sandbox. Choose an identifier that describes the kind of data your Valet will protect. You do not need to include your application name or bundle identifier in your Valet’s identifier. | ||
|
|
||
| #### Choosing a User-friendly Identifier on macOS |
There was a problem hiding this comment.
nit: Should we have some type
|
|
||
| ```swift | ||
| let mySecureEnclaveValet = Valet.valet(withExplicitlySet: Identifier(nonEmpty: "Druidia")!, accessibility: .whenUnlocked) | ||
| ``` |
There was a problem hiding this comment.
nit: Let's add an Obj-C example
Sources/Valet/SecureEnclave.swift
Outdated
| #endif | ||
| case .standard: | ||
| noPromptValet = .valet(with: identifier, accessibility: .whenPasscodeSetThisDeviceOnly) | ||
| #if os(macOS) |
There was a problem hiding this comment.
nit: This is not correctly indented
README.md
Outdated
| let mySecureEnclaveValet = Valet.valet(withExplicitlySet: Identifier(nonEmpty: "Druidia")!, accessibility: .whenUnlocked) | ||
| ``` | ||
|
|
||
| Mac apps signed with a developer ID may see their Valet’s identifier [shown to their users](https://github.com/square/Valet/issues/140). While it is possible to explicitly set a user-friendly identifier, note that doing so bypasses this project’s guarantee that one Valet type will not have access to one another type’s key:value pairs. To maintain this guarantee, ensure that each Valet’s identifier is globally unique. |
There was a problem hiding this comment.
I think providing an example of what types of Valets will be sharing the same key:value pairs would be useful here.
There was a problem hiding this comment.
Literally any with the same identifier, hence the suggestion to make the identifier globally unique.
| /// - parameter identifier: A non-empty string that must correspond with the value for keychain-access-groups in your Entitlements file. Must be unique relative to other Valet identifiers. | ||
| /// - parameter accessibility: The desired accessibility for the Valet. | ||
| /// - returns: A Valet (synchronized with iCloud) that reads/writes keychain elements that can be shared across applications written by the same development team. | ||
| public class func iCloudSharedAccessGroupValet(withExplicitlySet identifier: Identifier, accessibility: CloudAccessibility) -> Valet { |
There was a problem hiding this comment.
I'm guessing all of these are class and not static for Obj-c interoperability?
There was a problem hiding this comment.
I think I'm using class because of a decision I made years ago where I thought it was nicer? I'll do a separate PR to use static, since we're not using subclassing here.
| } | ||
| return findOrCreate(explicitlySet: identifier, configuration: .iCloud(accessibility), sharedAccessGroup: true) | ||
| } | ||
| #endif |
There was a problem hiding this comment.
Just for my understanding: all of this is also for Obj-C interoperability given structs are not exposed?
There was a problem hiding this comment.
exactly. Identifier is not Objective-C compatible. Given that we're making breaking changes, I'm open to changing this up if you've got better ideas 🙂
Sources/Valet/Valet.swift
Outdated
| class func permutations(withExplictlySet identifier: Identifier, shared: Bool = false) -> [Valet] { | ||
| return Accessibility.allValues().map { accessibility in | ||
| let valet: Valet = shared ? .sharedAccessGroupValet(withExplicitlySet: identifier, accessibility: accessibility) : .valet(withExplicitlySet: identifier, accessibility: accessibility) | ||
| return valet |
There was a problem hiding this comment.
I'm somewhat surprised Swift can't infer this?
nit, but do you think making this closure be explicitly
accessibility -> Valet
so this can be a one-liner makes this nicer?
There was a problem hiding this comment.
yeah let's make it a one-liner. It looks like in the year since this PR started I made the other methods (above) one-liners 😅
| } | ||
| } | ||
|
|
||
| class func iCloudPermutations(withExplictlySet identifier: Identifier, shared: Bool = false) -> [Valet] { |
There was a problem hiding this comment.
I think you might be missing marking this explicitly as internal on this one and on the top
There was a problem hiding this comment.
This is all in internal extension Valet 🙂
| // This is not be the case upon setting a breakpoint and inspecting before the valet.setString(, forKey:) call above. | ||
| } | ||
|
|
||
| func test_withExplicitlySet_identifierHasExplicitlySetIdentifier() { |
There was a problem hiding this comment.
nit: identifierHasExplicitlySetIdentifier -> assignsExplicitIdentifier
|
|
||
| Valet.iCloudPermutations(withExplictlySet: explicitlySetIdentifier, shared: false).forEach { | ||
| XCTAssertEqual($0.keychainQuery?[kSecAttrService as String], explicitlySetIdentifier.description) | ||
| } |
There was a problem hiding this comment.
This is (probably?) a nit, but should these be 2 tests? We're testing the same thing but on different contexts.
There was a problem hiding this comment.
I mean, this could be 4 tests. But I don't gain a lot by splitting this up?
There was a problem hiding this comment.
I'd indeed do 4 tests here 😁
We mostly gain the ability that when a test fails, we immediately know what assert is causing it (since we'd have 1 per test)
I'm a fan of that. I think using XCTest doesn't play that well with this though since you need to write a whole new test for that, but I also think this is fine though 🤷♂
There was a problem hiding this comment.
I think another solve for that is writing good descriptions for the failure case. In this case, I have 4 classes of tests, each with Accessibility.allValues().count asserts. That's... a lot of tests to write. And if we ever add a new accessibility value, it'll get worse.
Let me touch this up by adding some failure strings.
Fwiw, when one of these tests failed earlier in CI, I looked up the line number of the failure. That worked well enough 🤷♂
Codecov Report
@@ Coverage Diff @@
## develop--4.0 #154 +/- ##
================================================
+ Coverage 75.37% 75.57% +0.19%
================================================
Files 14 14
Lines 1206 1269 +63
================================================
+ Hits 909 959 +50
- Misses 297 310 +13
|
…iguration, accessibility, and sharedAccessGroup to prevent returning the wrong Valet
|
The lower test coverage mostly comes from the objc-compatibility layer not being tested. I currently have no test coverage on the compatibility layer. I need to fix that, but that's for another PR. |
Addresses #140.
Note that I haven't added unit tests or README documentation for these cases yet, so this PR is WIP. Before I commit to writing unit tests and README docs, I'm curious what the reaction is to adding this API, and I'd also like feedback on how we can improve the API documentation to make it clear what is going on here.Note that by explicitly setting thekSecAttrService, each Valet instance is no longer guaranteed to be a sandbox, unless thekSecAttrServiceis unique to the organization. Since this API is dangerous, I've only added it to the macOS target.cc @abey, @antons, and @gregcotten