Skip to content

Commit e3e861d

Browse files
authored
feat: add access group and keychain synchronization (#378)
* initial code * need to fix tests * fix merge conflicts * update * improve * update tests * remove old code * remove more code * fix keychain tests on macOS * nits * increase codecov * fixes * refactor * fix linux build * always update SDK config during init * add the ability to delete new keychain items * add more tests * don't run keychain test on linux * codecov * nits * move keychain if access group changed * revert to original access group if can't copy * swap * only remove old keychain if part of access group * replace duplicate keychain item if necessary * simplify
1 parent 89e5e69 commit e3e861d

20 files changed

+1040
-107
lines changed

.codecov.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ coverage:
66
status:
77
patch:
88
default:
9-
target: 75
9+
target: auto
1010
changes: false
1111
project:
1212
default:

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
__New features__
1111
- Add methods for migrating users and installations from the Parse Objective-C SDK to the Swift SDK ([#391](https://github.com/parse-community/Parse-Swift/pull/391)), thanks to [Corey Baker](https://github.com/cbaker6).
1212
- Enable query caching by using GET instead of POST. GET is now used by default. To switch back to POST, set usingPostForQuery = true when initializing the SDK which will automatically disable all query caching ([#386](https://github.com/parse-community/Parse-Swift/pull/386)), thanks to [Corey Baker](https://github.com/cbaker6).
13+
- Add setAccessGroup method which allows the Parse Keychain to be shared with app extensions and iCloud accounts ([#378](https://github.com/parse-community/Parse-Swift/pull/378)), thanks to [Corey Baker](https://github.com/cbaker6).
1314

1415
__Improvements__
1516
- Add more details to error messages related when decoding errors occur ([#388](https://github.com/parse-community/Parse-Swift/pull/388)), thanks to [Daniel Blyth](https://github.com/dblythy).

ParseSwift.xcodeproj/project.pbxproj

+18
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,9 @@
447447
7085DDB326D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };
448448
7085DDB426D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };
449449
7085DDB526D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };
450+
708CADCF2872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };
451+
708CADD02872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };
452+
708CADD12872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };
450453
708D035225215F9B00646C70 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708D035125215F9B00646C70 /* Deletable.swift */; };
451454
708D035325215F9B00646C70 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708D035125215F9B00646C70 /* Deletable.swift */; };
452455
708D035425215F9B00646C70 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708D035125215F9B00646C70 /* Deletable.swift */; };
@@ -638,6 +641,10 @@
638641
70D41D6B28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */; };
639642
70D41D6C28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */; };
640643
70D41D6D28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */; };
644+
70D41D8028B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };
645+
70D41D8128B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };
646+
70D41D8228B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };
647+
70D41D8328B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };
641648
70DFEA8A2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */; };
642649
70DFEA8B2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */; };
643650
70DFEA8C2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */; };
@@ -1257,6 +1264,7 @@
12571264
7085DD9326CBF3A70033B977 /* Documentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Documentation.docc; sourceTree = "<group>"; };
12581265
7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ParseHealth+combine.swift"; sourceTree = "<group>"; };
12591266
7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthenticationCombineTests.swift; sourceTree = "<group>"; };
1267+
708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseKeychainAccessGroupTests.swift; sourceTree = "<group>"; };
12601268
708D035125215F9B00646C70 /* Deletable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deletable.swift; sourceTree = "<group>"; };
12611269
709A147C283949D100BF85E5 /* ParseSchema.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchema.swift; sourceTree = "<group>"; };
12621270
709A148128395ED100BF85E5 /* ParseSchema+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseSchema+async.swift"; sourceTree = "<group>"; };
@@ -1311,6 +1319,7 @@
13111319
70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseConfig.swift; sourceTree = "<group>"; };
13121320
70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateObjCSDKTests.swift; sourceTree = "<group>"; };
13131321
70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateObjCSDKCombineTests.swift; sourceTree = "<group>"; };
1322+
70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseKeychainAccessGroup.swift; sourceTree = "<group>"; };
13141323
70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializeSDKTests.swift; sourceTree = "<group>"; };
13151324
70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePointerCombineTests.swift; sourceTree = "<group>"; };
13161325
70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionTests.swift; sourceTree = "<group>"; };
@@ -1619,6 +1628,7 @@
16191628
703B092626BE0719005A112F /* ParseInstallationAsyncTests.swift */,
16201629
7044C1BA25C52E410011F6E7 /* ParseInstallationCombineTests.swift */,
16211630
70110D5B2506ED0E0091CC1D /* ParseInstallationTests.swift */,
1631+
708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */,
16221632
917BA4552703F75E00F8D747 /* ParseLDAPAsyncTests.swift */,
16231633
70386A5B25D9A4010048EC1B /* ParseLDAPCombineTests.swift */,
16241634
70386A4525D99C8B0048EC1B /* ParseLDAPTests.swift */,
@@ -2115,6 +2125,7 @@
21152125
70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */,
21162126
70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */,
21172127
70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */,
2128+
70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */,
21182129
F97B464024D9C78B00F4A88B /* ParseOperation.swift */,
21192130
703B091026BD992E005A112F /* ParseOperation+async.swift */,
21202131
7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */,
@@ -2783,6 +2794,7 @@
27832794
7045769D26BD934000F86F71 /* ParseFile+async.swift in Sources */,
27842795
F97B463324D9C74400F4A88B /* URLSession.swift in Sources */,
27852796
F97B464E24D9C78B00F4A88B /* Add.swift in Sources */,
2797+
70D41D8028B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,
27862798
70385E762858E1000084D306 /* ParseHookFunctionable.swift in Sources */,
27872799
703B095326BF47FD005A112F /* ParseTwitter+async.swift in Sources */,
27882800
70CE0ABC285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,
@@ -2943,6 +2955,7 @@
29432955
911DB13324C494390027F3C7 /* MockURLProtocol.swift in Sources */,
29442956
917BA44A2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */,
29452957
705025A5284407C4008D6624 /* ParseSchemaTests.swift in Sources */,
2958+
708CADCF2872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */,
29462959
);
29472960
runOnlyForDeploymentPostprocessing = 0;
29482961
};
@@ -3089,6 +3102,7 @@
30893102
7045769E26BD934000F86F71 /* ParseFile+async.swift in Sources */,
30903103
F97B463424D9C74400F4A88B /* URLSession.swift in Sources */,
30913104
F97B464F24D9C78B00F4A88B /* Add.swift in Sources */,
3105+
70D41D8128B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,
30923106
70385E772858E1000084D306 /* ParseHookFunctionable.swift in Sources */,
30933107
703B095426BF47FD005A112F /* ParseTwitter+async.swift in Sources */,
30943108
70CE0ABD285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,
@@ -3258,6 +3272,7 @@
32583272
709B98542556ECAA00507778 /* ParseInstallationTests.swift in Sources */,
32593273
917BA44C2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */,
32603274
705025A7284407C4008D6624 /* ParseSchemaTests.swift in Sources */,
3275+
708CADD12872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */,
32613276
);
32623277
runOnlyForDeploymentPostprocessing = 0;
32633278
};
@@ -3380,6 +3395,7 @@
33803395
70F2E2B9254F283000B2EA5C /* KeychainStoreTests.swift in Sources */,
33813396
917BA44B2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */,
33823397
705025A6284407C4008D6624 /* ParseSchemaTests.swift in Sources */,
3398+
708CADD02872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */,
33833399
);
33843400
runOnlyForDeploymentPostprocessing = 0;
33853401
};
@@ -3526,6 +3542,7 @@
35263542
704576A026BD934000F86F71 /* ParseFile+async.swift in Sources */,
35273543
F97B464924D9C78B00F4A88B /* ParseOperation.swift in Sources */,
35283544
F97B45D124D9C6F200F4A88B /* ParseCoding.swift in Sources */,
3545+
70D41D8328B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,
35293546
70385E792858E1000084D306 /* ParseHookFunctionable.swift in Sources */,
35303547
703B095626BF47FD005A112F /* ParseTwitter+async.swift in Sources */,
35313548
70CE0ABF285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,
@@ -3710,6 +3727,7 @@
37103727
7045769F26BD934000F86F71 /* ParseFile+async.swift in Sources */,
37113728
F97B464824D9C78B00F4A88B /* ParseOperation.swift in Sources */,
37123729
F97B45D024D9C6F200F4A88B /* ParseCoding.swift in Sources */,
3730+
70D41D8228B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,
37133731
70385E782858E1000084D306 /* ParseHookFunctionable.swift in Sources */,
37143732
703B095526BF47FD005A112F /* ParseTwitter+async.swift in Sources */,
37153733
70CE0ABE285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,

Sources/ParseSwift/Objects/ParseInstallation.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public extension ParseInstallation {
9797
}
9898

9999
func mergeParse(with object: Self) throws -> Self {
100-
guard hasSameObjectId(as: object) == true else {
100+
guard hasSameObjectId(as: object) else {
101101
throw ParseError(code: .unknownError,
102102
message: "objectId's of objects do not match")
103103
}
@@ -193,7 +193,7 @@ extension ParseInstallation {
193193
}
194194

195195
// MARK: CurrentInstallationContainer
196-
struct CurrentInstallationContainer<T: ParseInstallation>: Codable {
196+
struct CurrentInstallationContainer<T: ParseInstallation>: Codable, Hashable {
197197
var currentInstallation: T?
198198
var installationId: String?
199199
}

Sources/ParseSwift/Objects/ParseObject.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public extension ParseObject {
192192
}
193193

194194
func mergeParse(with object: Self) throws -> Self {
195-
guard hasSameObjectId(as: object) == true else {
195+
guard hasSameObjectId(as: object) else {
196196
throw ParseError(code: .unknownError,
197197
message: "objectId's of objects do not match")
198198
}

Sources/ParseSwift/Objects/ParseUser.swift

+8-6
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public extension ParseUser {
4444
}
4545

4646
func mergeParse(with object: Self) throws -> Self {
47-
guard hasSameObjectId(as: object) == true else {
47+
guard hasSameObjectId(as: object) else {
4848
throw ParseError(code: .unknownError,
4949
message: "objectId's of objects do not match")
5050
}
@@ -101,7 +101,7 @@ extension ParseUser {
101101
}
102102

103103
// MARK: CurrentUserContainer
104-
struct CurrentUserContainer<T: ParseUser>: Codable {
104+
struct CurrentUserContainer<T: ParseUser>: Codable, Hashable {
105105
var currentUser: T?
106106
var sessionToken: String?
107107
}
@@ -399,7 +399,9 @@ extension ParseUser {
399399
}
400400
return
401401
}
402-
completion(.success(currentUser))
402+
callbackQueue.async {
403+
completion(.success(currentUser))
404+
}
403405
}
404406
#endif
405407

@@ -439,9 +441,9 @@ extension ParseUser {
439441
var options = options
440442
options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))
441443
let error = try? logoutCommand().execute(options: options)
442-
//Always let user logout locally, no matter the error.
444+
// Always let user logout locally, no matter the error.
443445
deleteCurrentKeychain()
444-
//Wait to throw error
446+
// Wait to throw error
445447
if let parseError = error {
446448
throw parseError
447449
}
@@ -465,7 +467,7 @@ extension ParseUser {
465467
options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))
466468
logoutCommand().executeAsync(options: options,
467469
callbackQueue: callbackQueue) { result in
468-
//Always let user logout locally, no matter the error.
470+
// Always let user logout locally, no matter the error.
469471
deleteCurrentKeychain()
470472

471473
switch result {

Sources/ParseSwift/Parse.swift

+61-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ public struct ParseConfiguration {
7777
(URLSession.AuthChallengeDisposition,
7878
URLCredential?) -> Void) -> Void)?
7979
internal var mountPath: String
80-
internal var isTestingSDK = false //Enable this only for certain tests like ParseFile
80+
internal var isTestingSDK = false // Enable this only for certain tests like ParseFile
81+
#if !os(Linux) && !os(Android) && !os(Windows)
82+
internal var keychainAccessGroup = ParseKeychainAccessGroup()
83+
#endif
8184

8285
/**
8386
Create a Parse Swift configuration.
@@ -266,6 +269,14 @@ public struct ParseSwift {
266269
authentication: configuration.authentication)
267270
deleteKeychainIfNeeded()
268271

272+
#if !os(Linux) && !os(Android) && !os(Windows)
273+
if let keychainAccessGroup = ParseKeychainAccessGroup.current {
274+
ParseSwift.configuration.keychainAccessGroup = keychainAccessGroup
275+
} else {
276+
ParseKeychainAccessGroup.current = ParseKeychainAccessGroup()
277+
}
278+
#endif
279+
269280
do {
270281
let previousSDKVersion = try ParseVersion(ParseVersion.current)
271282
let currentSDKVersion = try ParseVersion(ParseConstants.version)
@@ -276,7 +287,9 @@ public struct ParseSwift {
276287
if previousSDKVersion < oneNineEightSDKVersion {
277288
// Old macOS Keychain cannot be used because it is global to all apps.
278289
_ = KeychainStore.old
279-
KeychainStore.shared.copy(keychain: KeychainStore.old)
290+
try? KeychainStore.shared.copy(KeychainStore.old,
291+
oldAccessGroup: configuration.keychainAccessGroup,
292+
newAccessGroup: configuration.keychainAccessGroup)
280293
// Need to delete the old Keychain because a new one is created with bundleId.
281294
try? KeychainStore.old.deleteAll()
282295
}
@@ -537,6 +550,51 @@ public struct ParseSwift {
537550
initialize(configuration: configuration)
538551
}
539552

553+
#if !os(Linux) && !os(Android) && !os(Windows)
554+
555+
/**
556+
Sets all of the items in the Parse Keychain to a specific access group.
557+
Apps in the same access group can share Keychain items. See Apple's
558+
[documentation](https://developer.apple.com/documentation/security/ksecattraccessgroup)
559+
for more information.
560+
- parameter accessGroup: The name of the access group.
561+
- parameter synchronizeAcrossDevices: **true** to synchronize all necessary Parse Keychain items to
562+
other devices using iCloud. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecattrsynchronizable)
563+
for more information. **false** to disable synchronization.
564+
- throws: An error of type `ParseError`.
565+
- returns: **true** if the Keychain was moved to the new `accessGroup`, **false** otherwise.
566+
- warning: Setting `synchronizeAcrossDevices == true` requires `accessGroup` to be
567+
set to a valid [keychain group](https://developer.apple.com/documentation/security/ksecattraccessgroup).
568+
*/
569+
@discardableResult static public func setAccessGroup(_ accessGroup: String?,
570+
synchronizeAcrossDevices: Bool) throws -> Bool {
571+
if synchronizeAcrossDevices && accessGroup == nil {
572+
throw ParseError(code: .unknownError,
573+
message: "\"accessGroup\" must be set to a valid string when \"synchronizeAcrossDevices == true\"")
574+
}
575+
guard let currentAccessGroup = ParseKeychainAccessGroup.current else {
576+
throw ParseError(code: .unknownError,
577+
message: "Problem unwrapping the current access group. Did you initialize the SDK before calling this method?")
578+
}
579+
let newKeychainAccessGroup = ParseKeychainAccessGroup(accessGroup: accessGroup,
580+
isSyncingKeychainAcrossDevices: synchronizeAcrossDevices)
581+
guard newKeychainAccessGroup != currentAccessGroup else {
582+
ParseKeychainAccessGroup.current = newKeychainAccessGroup
583+
return true
584+
}
585+
do {
586+
try KeychainStore.shared.copy(KeychainStore.shared,
587+
oldAccessGroup: currentAccessGroup,
588+
newAccessGroup: newKeychainAccessGroup)
589+
ParseKeychainAccessGroup.current = newKeychainAccessGroup
590+
} catch {
591+
ParseKeychainAccessGroup.current = currentAccessGroup
592+
throw error
593+
}
594+
return true
595+
}
596+
#endif
597+
540598
static internal func deleteKeychainIfNeeded() {
541599
#if !os(Linux) && !os(Android) && !os(Windows)
542600
// Clear items out of the Keychain on app first run.
@@ -545,6 +603,7 @@ public struct ParseSwift {
545603
try? KeychainStore.old.deleteAll()
546604
try? KeychainStore.shared.deleteAll()
547605
}
606+
ParseSwift.configuration.keychainAccessGroup = .init()
548607
clearCache()
549608
// This is no longer the first run
550609
UserDefaults.standard.setValue(String(ParseConstants.bundlePrefix),

Sources/ParseSwift/ParseConstants.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Foundation
1010

1111
enum ParseConstants {
1212
static let sdk = "swift"
13-
static let version = "4.8.0"
13+
static let version = "4.9.0"
1414
static let fileManagementDirectory = "parse/"
1515
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
1616
static let fileManagementLibraryDirectory = "Library/"

Sources/ParseSwift/Protocols/ParseHookRequestable.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ extension ParseHookRequestable {
5050
public func options() -> API.Options {
5151
var options = API.Options()
5252
if let masterKey = masterKey,
53-
masterKey == true {
53+
masterKey {
5454
options.insert(.useMasterKey)
5555
} else if let sessionToken = user?.sessionToken {
5656
options.insert(.sessionToken(sessionToken))

0 commit comments

Comments
 (0)