From 96c9b20fd30f136a6ab8824712d290227f5707a1 Mon Sep 17 00:00:00 2001 From: Radoslav Penev Date: Thu, 14 Aug 2025 17:08:04 +0300 Subject: [PATCH 1/5] Add ability to change default storage URL --- .../User Storage/SQLiteHelper.swift | 27 +++++++------ .../User Storage/SQLiteUserStorage.swift | 12 ++++-- .../SQLiteUserStorageMigrationTests.swift | 9 +++-- .../SQLiteUserStorageTests.swift | 39 ++++++++++++++++++- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift index 823b392..09fc098 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift @@ -19,9 +19,8 @@ final class SQLiteHelper: @unchecked Sendable { } } - func openDatabaseConnection(for dbName: String) throws { + func openDatabaseConnection(for dbName: String, directoryURL: URL) throws { try queue.sync { - let directoryURL = try getDocumentsDirectory() var dbFileURL = directoryURL .appendingPathComponent("\(dbName).sqlite") let dbFilePath = dbFileURL.relativePath @@ -281,16 +280,22 @@ final class SQLiteHelper: @unchecked Sendable { return isNeeded } - func getDocumentsDirectory() throws -> URL { - guard let directoryURL = try? FileManager.default.url( - for: .documentDirectory, - in: .userDomainMask, - appropriateFor: nil, - create: true - ) else { - throw SQLiteDefaultStorageError.noDir + func getDatabaseDirectoryURL(directoryURL: URL?) throws -> URL { + let databaseDirectoryURL: URL + if let directoryURL { + databaseDirectoryURL = directoryURL + } else { + guard let directoryURL = try? FileManager.default.url( + for: .documentDirectory, + in: .userDomainMask, + appropriateFor: nil, + create: true + ) else { + throw SQLiteDefaultStorageError.noDir + } + databaseDirectoryURL = directoryURL } - return directoryURL + return databaseDirectoryURL } private func getErrorMessage() -> String? { diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift index 841d438..656c4a6 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift @@ -10,12 +10,15 @@ final class SQLiteUserStorage: NSObject, UserStorage { let databaseName: String let projectId: String let sqliteHelper = SQLiteHelper() + let directoryURL: URL? init( projectId: String, + directoryURL: URL? = nil, databaseName: String = "miracl" ) { self.projectId = projectId + self.directoryURL = directoryURL self.databaseName = databaseName } @@ -24,12 +27,15 @@ final class SQLiteUserStorage: NSObject, UserStorage { let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self) func loadStorage() throws { - let directoryURL = try sqliteHelper.getDocumentsDirectory() - let dbFileURL = directoryURL + let databaseDirectoryURL = try sqliteHelper.getDatabaseDirectoryURL(directoryURL: directoryURL) + let dbFileURL = databaseDirectoryURL .appendingPathComponent("\(databaseName).sqlite") let isDatabaseExist = FileManager.default.fileExists(atPath: dbFileURL.path) - try sqliteHelper.openDatabaseConnection(for: databaseName) + try sqliteHelper.openDatabaseConnection( + for: databaseName, + directoryURL: databaseDirectoryURL + ) try sqliteHelper.encryptDatabase() let currentDatabaseVersion = try sqliteHelper.getCurrentDatabaseVersion() diff --git a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift index 34620b0..42a19a3 100644 --- a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift +++ b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift @@ -135,7 +135,8 @@ class SQLiteUserStorageMigrationTests: XCTestCase { } private func createV2Storage() throws { - try sqliteHelper.openDatabaseConnection(for: databaseName) + let directoryURL = try sqliteHelper.getDatabaseDirectoryURL(directoryURL: nil) + try sqliteHelper.openDatabaseConnection(for: databaseName, directoryURL: directoryURL) try sqliteHelper.encryptDatabase() try sqliteHelper.setCurrentDatabaseVersion(databaseVersion: 2) @@ -229,7 +230,8 @@ class SQLiteUserStorageMigrationTests: XCTestCase { } private func createV1Storage() throws { - try sqliteHelper.openDatabaseConnection(for: databaseName) + let directoryURL = try sqliteHelper.getDatabaseDirectoryURL(directoryURL: nil) + try sqliteHelper.openDatabaseConnection(for: databaseName, directoryURL: directoryURL) try sqliteHelper.encryptDatabase() try sqliteHelper.setCurrentDatabaseVersion(databaseVersion: 1) @@ -323,7 +325,8 @@ class SQLiteUserStorageMigrationTests: XCTestCase { } private func createV0Storage() throws { - try sqliteHelper.openDatabaseConnection(for: "test-for-migration") + let directoryURL = try sqliteHelper.getDatabaseDirectoryURL(directoryURL: nil) + try sqliteHelper.openDatabaseConnection(for: "test-for-migration", directoryURL: directoryURL) try sqliteHelper.encryptDatabase() try sqliteHelper.setCurrentDatabaseVersion(databaseVersion: 0) diff --git a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift index 5c8b1fb..ec26aff 100644 --- a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift +++ b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift @@ -30,7 +30,44 @@ class SQLiteUserStorageTests: XCTestCase { } } - // MARK: Migrations test + // MARK: `loadStorage()` method tests + + func testChangedDatabaseName() throws { + let newName = "miracl-test-new" + let newStorage = SQLiteUserStorage(projectId: UUID().uuidString, databaseName: newName) + let configuration = try Configuration + .Builder( + projectId: projectId + ) + .userStorage(userStorage: newStorage) + .build() + try MIRACLTrust.configure(with: configuration) + + let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + let path = fileURL.appendingPathComponent("\(newName).sqlite").relativePath + XCTAssertTrue(FileManager.default.fileExists(atPath: path)) + } + + func testChangedDatabaseURL() throws { + let newName = "miracl-test-new" + let tempDirectorURL = FileManager.default.temporaryDirectory + let newStorage = SQLiteUserStorage( + projectId: UUID().uuidString, + directoryURL: tempDirectorURL, + databaseName: newName + ) + + let configuration = try Configuration + .Builder( + projectId: projectId + ) + .userStorage(userStorage: newStorage) + .build() + try MIRACLTrust.configure(with: configuration) + + let path = tempDirectorURL.appendingPathComponent("\(newName).sqlite").relativePath + XCTAssertTrue(FileManager.default.fileExists(atPath: path)) + } // MARK: `add` method test From 62e0ce05ad4019b02e54704236192b86b3d0842b Mon Sep 17 00:00:00 2001 From: Radoslav Penev Date: Mon, 18 Aug 2025 12:01:17 +0300 Subject: [PATCH 2/5] Keychain access group support for storage --- .../User Storage/SQLiteEncryptionHelper.swift | 62 +++++++++++++++++-- .../User Storage/SQLiteHelper.swift | 7 ++- .../User Storage/SQLiteUserStorage.swift | 7 ++- .../User Storage/SQLiteUserStorageError.swift | 1 + .../SQLiteUserStorageMigrationTests.swift | 6 +- 5 files changed, 72 insertions(+), 11 deletions(-) diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteEncryptionHelper.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteEncryptionHelper.swift index 1daf60e..f10a8b2 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteEncryptionHelper.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteEncryptionHelper.swift @@ -1,8 +1,13 @@ import Foundation class SQLiteEncryptionHandler { + private let keychainAccessGroup: String? private let keychainItemAccount = "com.miracl.keys.userstable" + init(keychainAccessGroup: String?) { + self.keychainAccessGroup = keychainAccessGroup + } + func createEncryptionKey() -> String? { var data = Data(count: 256) _ = data.withUnsafeMutableBytes { @@ -10,13 +15,18 @@ class SQLiteEncryptionHandler { } let key = data.base64EncodedString() - let addQuery: [String: Any] = [ + var addQuery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: keychainItemAccount, kSecValueData as String: data.base64EncodedData(), kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly ] + // Add keychain access group if needed. + if let keychainAccessGroup { + addQuery[kSecAttrAccessGroup as String] = keychainAccessGroup + } + let result: OSStatus = SecItemAdd(addQuery as CFDictionary, nil) guard result == errSecSuccess else { return nil @@ -26,10 +36,16 @@ class SQLiteEncryptionHandler { } func loadEncryptionKey() -> String? { - let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, + var query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, kSecMatchLimit as String: kSecMatchLimitOne, kSecAttrAccount as String: keychainItemAccount, kSecReturnData as String: true] + + // Add keychain access group if needed. + if let keychainAccessGroup { + query[kSecAttrAccessGroup as String] = keychainAccessGroup + } + var queryResult: AnyObject? SecItemCopyMatching(query as CFDictionary, &queryResult) if let data = queryResult as? Data { @@ -39,6 +55,39 @@ class SQLiteEncryptionHandler { return nil } + func updateEncryptionKeyAccessGroupIfNeeded() -> Bool { + if let keychainAccessGroup { + let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, + kSecMatchLimit as String: kSecMatchLimitOne, + kSecAttrAccount as String: keychainItemAccount, + kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, + kSecAttrAccessGroup as String: keychainAccessGroup, + kSecReturnData as String: true] + var queryResult: AnyObject? + SecItemCopyMatching(query as CFDictionary, &queryResult) + + if queryResult == nil { + let getItemQuery: [String: Any] = [ + kSecClass as String: kSecClassGenericPassword, + kSecAttrAccount as String: keychainItemAccount + ] + + let updatedAttributes = [ + kSecAttrAccessGroup as String: keychainAccessGroup + ] + + let result: OSStatus = SecItemUpdate(getItemQuery as CFDictionary, updatedAttributes as CFDictionary) + if result == errSecSuccess { + return true + } else { + return false + } + } + } + + return true + } + func updateEncryptionKeyAccessibilityIfNeeded() -> Bool { let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, kSecMatchLimit as String: kSecMatchLimitOne, @@ -54,11 +103,16 @@ class SQLiteEncryptionHandler { kSecAttrAccount as String: keychainItemAccount ] - let updatedAttribute = [ + var updatedAttributes = [ kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly ] - let result: OSStatus = SecItemUpdate(getItemQuery as CFDictionary, updatedAttribute as CFDictionary) + if let keychainAccessGroup { + let keychainAccessGroup: CFString = keychainAccessGroup as NSString + updatedAttributes[kSecAttrAccessGroup as String] = keychainAccessGroup + } + + let result: OSStatus = SecItemUpdate(getItemQuery as CFDictionary, updatedAttributes as CFDictionary) if result == errSecSuccess { return true } else { diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift index 09fc098..a17583a 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift @@ -43,9 +43,9 @@ final class SQLiteHelper: @unchecked Sendable { } } - func encryptDatabase() throws { + func encryptDatabase(keychainAccessGroup: String?) throws { try queue.sync { - let encryptionHelper = SQLiteEncryptionHandler() + let encryptionHelper = SQLiteEncryptionHandler(keychainAccessGroup: keychainAccessGroup) var encryptionKey = encryptionHelper.loadEncryptionKey() @@ -53,6 +53,9 @@ final class SQLiteHelper: @unchecked Sendable { encryptionKey = encryptionHelper.createEncryptionKey() } + if !encryptionHelper.updateEncryptionKeyAccessGroupIfNeeded() { + throw SQLiteDefaultStorageError.accessGroupUpdateError + } if !encryptionHelper.updateEncryptionKeyAccessibilityIfNeeded() { throw SQLiteDefaultStorageError.encryptionKeyUpdateError } diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift index 656c4a6..1612c7d 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorage.swift @@ -11,15 +11,18 @@ final class SQLiteUserStorage: NSObject, UserStorage { let projectId: String let sqliteHelper = SQLiteHelper() let directoryURL: URL? + let keychainAccessGroup: String? init( projectId: String, directoryURL: URL? = nil, - databaseName: String = "miracl" + databaseName: String = "miracl", + keychainAccessGroup: String? = nil ) { self.projectId = projectId self.directoryURL = directoryURL self.databaseName = databaseName + self.keychainAccessGroup = keychainAccessGroup } // Current version of the SQLite database @@ -36,7 +39,7 @@ final class SQLiteUserStorage: NSObject, UserStorage { for: databaseName, directoryURL: databaseDirectoryURL ) - try sqliteHelper.encryptDatabase() + try sqliteHelper.encryptDatabase(keychainAccessGroup: keychainAccessGroup) let currentDatabaseVersion = try sqliteHelper.getCurrentDatabaseVersion() if sqliteHelper.isMigrationNeeded( diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift index f088514..90d442f 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift @@ -6,4 +6,5 @@ enum SQLiteDefaultStorageError: Error, Equatable { case emptyOrNullParametersError case encryptionError case encryptionKeyUpdateError + case accessGroupUpdateError } diff --git a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift index 42a19a3..623dac4 100644 --- a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift +++ b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageMigrationTests.swift @@ -137,7 +137,7 @@ class SQLiteUserStorageMigrationTests: XCTestCase { private func createV2Storage() throws { let directoryURL = try sqliteHelper.getDatabaseDirectoryURL(directoryURL: nil) try sqliteHelper.openDatabaseConnection(for: databaseName, directoryURL: directoryURL) - try sqliteHelper.encryptDatabase() + try sqliteHelper.encryptDatabase(keychainAccessGroup: nil) try sqliteHelper.setCurrentDatabaseVersion(databaseVersion: 2) let alterOldTablesStatement = """ @@ -232,7 +232,7 @@ class SQLiteUserStorageMigrationTests: XCTestCase { private func createV1Storage() throws { let directoryURL = try sqliteHelper.getDatabaseDirectoryURL(directoryURL: nil) try sqliteHelper.openDatabaseConnection(for: databaseName, directoryURL: directoryURL) - try sqliteHelper.encryptDatabase() + try sqliteHelper.encryptDatabase(keychainAccessGroup: nil) try sqliteHelper.setCurrentDatabaseVersion(databaseVersion: 1) let alterOldTablesStatement = """ @@ -327,7 +327,7 @@ class SQLiteUserStorageMigrationTests: XCTestCase { private func createV0Storage() throws { let directoryURL = try sqliteHelper.getDatabaseDirectoryURL(directoryURL: nil) try sqliteHelper.openDatabaseConnection(for: "test-for-migration", directoryURL: directoryURL) - try sqliteHelper.encryptDatabase() + try sqliteHelper.encryptDatabase(keychainAccessGroup: nil) try sqliteHelper.setCurrentDatabaseVersion(databaseVersion: 0) let alterOldTablesStatement = """ From c1a17db54ab7f09ee9fd417fc57480cba2c88637 Mon Sep 17 00:00:00 2001 From: Radoslav Penev Date: Wed, 20 Aug 2025 16:07:13 +0300 Subject: [PATCH 3/5] Update storage configuration methods --- .../MIRACLTrust-Sources/Configuration.swift | 30 +++++++++++++++---- .../MIRACLTrust-Sources/MIRACLTrust.swift | 15 +++++++--- .../DefaultUserStorageOptions.swift | 15 ++++++++++ .../User Storage/StorageType.swift | 6 ++++ .../MIRACLTrust.xcodeproj/project.pbxproj | 8 +++++ .../xcshareddata/swiftpm/Package.resolved | 3 +- 6 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 MIRACLTrust/MIRACLTrust-Sources/User Storage/DefaultUserStorageOptions.swift create mode 100644 MIRACLTrust/MIRACLTrust-Sources/User Storage/StorageType.swift diff --git a/MIRACLTrust/MIRACLTrust-Sources/Configuration.swift b/MIRACLTrust/MIRACLTrust-Sources/Configuration.swift index ab74892..5a3afcc 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/Configuration.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/Configuration.swift @@ -6,9 +6,6 @@ import Foundation /// Identifier of the project in the MIRACL Trust platform. var projectId: String - /// User objects are kept in this storage when they are registered. By default, they are written into an internal for the application SQLite database. - var userStorage: UserStorage? - /// Base URL of the MIRACL platform. var platformURL: URL @@ -29,6 +26,9 @@ import Foundation // Additional information that will be sent via `X-MIRACL-CLIENT` HTTP header. var applicationInfo: String? + /// Type of the storage that could be configured. + var storageType: StorageType + override private init() { projectId = "" platformURL = MIRACL_API_URL @@ -38,8 +38,8 @@ import Foundation urlSessionConfiguration.timeoutIntervalForRequest = 30 urlSessionConfiguration.timeoutIntervalForResource = 300 deviceName = "" - loggingLevel = .none + storageType = .default(DefaultUserStorageOptions()) } /// Builds ``Configuration`` objects. @@ -69,13 +69,33 @@ import Foundation } } + /// Sets ``DefaultStorageOptions``. + /// + /// The default storage is and encrypted SQLite database stored in the `documents` directory. + /// + /// - Parameter closure: A closure that receives an inout ``DefaultUserStorageOptions`` instance + /// so you can modify its properties. Any changes you make inside the closure + /// are applied to the user storage setup. + /// - Returns: ``Configuration/Builder`` object. + @discardableResult + public func configureDefaultUserStorage( + _ closure: (inout DefaultUserStorageOptions) -> Void + ) -> Builder { + var options = DefaultUserStorageOptions() + closure(&options) + + configurationToBuild.storageType = .default(options) + + return self + } + /// Set custom ``UserStorage`` implementation. /// - Parameter userStorage: custom ``UserStorage`` implementation. /// - Returns: Configuration.Builder object. @discardableResult public func userStorage( userStorage: UserStorage ) -> Builder { - configurationToBuild.userStorage = userStorage + configurationToBuild.storageType = .custom(userStorage) return self } diff --git a/MIRACLTrust/MIRACLTrust-Sources/MIRACLTrust.swift b/MIRACLTrust/MIRACLTrust-Sources/MIRACLTrust.swift index 827280b..0252e7e 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/MIRACLTrust.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/MIRACLTrust.swift @@ -34,11 +34,18 @@ import Foundation projectId = configuration.projectId deviceName = configuration.deviceName urlSessionConfiguration = configuration.urlSessionConfiguration - userStorage = - configuration.userStorage ?? - SQLiteUserStorage( - projectId: configuration.projectId + + switch configuration.storageType { + case let .default(options): + userStorage = SQLiteUserStorage( + projectId: projectId, + directoryURL: options.directoryURL, + databaseName: options.storageName, + keychainAccessGroup: options.keychainAccessGroup ) + case let .custom(storage): + userStorage = storage + } miraclAPI = API( baseURL: configuration.platformURL, diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/DefaultUserStorageOptions.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/DefaultUserStorageOptions.swift new file mode 100644 index 0000000..e466f64 --- /dev/null +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/DefaultUserStorageOptions.swift @@ -0,0 +1,15 @@ +import Foundation + +/// Configurable options for the default storage provided by MIRACL Trust iOS SDK. +/// +/// The default storage that MIRACL Trust iOS SDK provides is an encrypted SQLite database stored at the `documents` directory. +public class DefaultUserStorageOptions { + /// Name of the storage file. + public var storageName: String = "miracl" + + /// File system path used for default storage file. + public var directoryURL: URL? + + /// [Keychain access group](https://developer.apple.com/documentation/security/sharing-access-to-keychain-items-among-a-collection-of-apps) identifier used to share a storage key between applications from the same company. + public var keychainAccessGroup: String? +} diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/StorageType.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/StorageType.swift new file mode 100644 index 0000000..c1d7ad3 --- /dev/null +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/StorageType.swift @@ -0,0 +1,6 @@ +import Foundation + +enum StorageType { + case `default`(DefaultUserStorageOptions) + case custom(UserStorage) +} diff --git a/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj b/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj index cab5731..61dcc5d 100644 --- a/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj +++ b/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 6D22F0E12B1092BE008FE5E5 /* AbortAuthenticationSessionCompatibilityCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D22F0DF2B1092BE008FE5E5 /* AbortAuthenticationSessionCompatibilityCase.m */; }; 6D25C44A25D6853F00E878C9 /* JWTAuthenticationTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D25C44925D6853F00E878C9 /* JWTAuthenticationTestCase.swift */; }; 6D26142C24AB1B7C004F0B54 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D26142B24AB1B7C004F0B54 /* Constants.swift */; }; + 6D291E942E55F80600C6AD80 /* StorageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D291E932E55F80200C6AD80 /* StorageType.swift */; }; + 6D291E962E55F8CD00C6AD80 /* DefaultUserStorageOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D291E952E55F8C600C6AD80 /* DefaultUserStorageOptions.swift */; }; 6D2E4F112E2E62DA0001B5A7 /* CrossDeviceSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2E4F102E2E62D40001B5A7 /* CrossDeviceSession.swift */; }; 6D2E4F132E2E62E60001B5A7 /* CrossDeviceSessionFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2E4F122E2E62DF0001B5A7 /* CrossDeviceSessionFetcher.swift */; }; 6D2E4F152E2E62FE0001B5A7 /* CrossDeviceSessionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2E4F142E2E62F90001B5A7 /* CrossDeviceSessionResponse.swift */; }; @@ -328,6 +330,8 @@ 6D22F0DF2B1092BE008FE5E5 /* AbortAuthenticationSessionCompatibilityCase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AbortAuthenticationSessionCompatibilityCase.m; sourceTree = ""; }; 6D25C44925D6853F00E878C9 /* JWTAuthenticationTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTAuthenticationTestCase.swift; sourceTree = ""; }; 6D26142B24AB1B7C004F0B54 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + 6D291E932E55F80200C6AD80 /* StorageType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageType.swift; sourceTree = ""; }; + 6D291E952E55F8C600C6AD80 /* DefaultUserStorageOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultUserStorageOptions.swift; sourceTree = ""; }; 6D2E4F102E2E62D40001B5A7 /* CrossDeviceSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossDeviceSession.swift; sourceTree = ""; }; 6D2E4F122E2E62DF0001B5A7 /* CrossDeviceSessionFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossDeviceSessionFetcher.swift; sourceTree = ""; }; 6D2E4F142E2E62F90001B5A7 /* CrossDeviceSessionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossDeviceSessionResponse.swift; sourceTree = ""; }; @@ -763,6 +767,8 @@ 6DB4580C269C17DB00C4FEFA /* SQLiteHelper.swift */, 6DF2D3F8269F0DAF004CAD54 /* SQLiteEncryptionHelper.swift */, 6DF2D3F6269F03DE004CAD54 /* SQLiteUserStorageError.swift */, + 6D291E952E55F8C600C6AD80 /* DefaultUserStorageOptions.swift */, + 6D291E932E55F80200C6AD80 /* StorageType.swift */, ); path = "User Storage"; sourceTree = ""; @@ -1592,6 +1598,7 @@ 6DC46A7E25B9BB210099866C /* Data+Extensions.swift in Sources */, 6DC46A6A25B9BB080099866C /* ClientSecretResponse.swift in Sources */, 6DC46A5425B9BAFD0099866C /* VerificationRequestResponse.swift in Sources */, + 6D291E942E55F80600C6AD80 /* StorageType.swift in Sources */, FA5D21162D0890CC00E3548C /* VerificationQuickCodeRequestBody.swift in Sources */, 6DC4696725B9B7FC0099866C /* Configuration.swift in Sources */, 6DC46A2025B9BAE40099866C /* Signature.swift in Sources */, @@ -1613,6 +1620,7 @@ 6DC46A0625B9BAD40099866C /* LoggingConstants.swift in Sources */, 6D6D9A0C282BEB9800316755 /* SigningSessionDetailsRequestBody.swift in Sources */, 6DC46A5225B9BAFD0099866C /* ActivationTokenError.swift in Sources */, + 6D291E962E55F8CD00C6AD80 /* DefaultUserStorageOptions.swift in Sources */, 6DF2D3F7269F03DE004CAD54 /* SQLiteUserStorageError.swift in Sources */, 6DDFB53A29EFDCCE00B981FB /* FallbackRequestErrorResponse.swift in Sources */, 6DC46A7D25B9BB210099866C /* UIDevice+Helpers.swift in Sources */, diff --git a/MIRACLTrust/MIRACLTrust.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/MIRACLTrust/MIRACLTrust.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1d3cf86..185856e 100644 --- a/MIRACLTrust/MIRACLTrust.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/MIRACLTrust/MIRACLTrust.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "e0ac3fd34b7305dbde096625b8eefa11940bc1a3b6d213527e91bedce8a4b7ac", "pins" : [ { "identity" : "jwt-kit", @@ -28,5 +29,5 @@ } } ], - "version" : 2 + "version" : 3 } From 99b8e103beba3282b5070b4727d40a391e5a703d Mon Sep 17 00:00:00 2001 From: Radoslav Penev Date: Wed, 27 Aug 2025 16:57:49 +0300 Subject: [PATCH 4/5] Rename the default user storage error --- .../User Storage/SQLiteHelper.swift | 34 +++---- .../User Storage/SQLiteUserStorageError.swift | 91 ++++++++++++++++++- .../SQLiteUserStorageTests.swift | 24 ++--- 3 files changed, 115 insertions(+), 34 deletions(-) diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift index a17583a..2524f58 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteHelper.swift @@ -38,7 +38,7 @@ final class SQLiteHelper: @unchecked Sendable { } if sqlite3_open(dbFilePath, &database) != SQLITE_OK { - throw SQLiteDefaultStorageError.noConnection + throw SQLiteUserStorageError.noConnection } } } @@ -54,14 +54,14 @@ final class SQLiteHelper: @unchecked Sendable { } if !encryptionHelper.updateEncryptionKeyAccessGroupIfNeeded() { - throw SQLiteDefaultStorageError.accessGroupUpdateError + throw SQLiteUserStorageError.accessGroupUpdateError } if !encryptionHelper.updateEncryptionKeyAccessibilityIfNeeded() { - throw SQLiteDefaultStorageError.encryptionKeyUpdateError + throw SQLiteUserStorageError.encryptionKeyUpdateAccessibilityError } guard let encryptionKeyAsNSString = encryptionKey as NSString? else { - throw SQLiteDefaultStorageError.encryptionError + throw SQLiteUserStorageError.encryptionKeyConfigurationError } let dbOperationResult = sqlite3_key( @@ -71,7 +71,7 @@ final class SQLiteHelper: @unchecked Sendable { ) if dbOperationResult != SQLITE_OK { - throw SQLiteDefaultStorageError.encryptionError + throw SQLiteUserStorageError.encryptionKeyConfigurationError } } } @@ -92,12 +92,12 @@ final class SQLiteHelper: @unchecked Sendable { ) guard prepareQueryResult == SQLITE_OK else { - throw SQLiteDefaultStorageError.prepareStatementError(message: getErrorMessage()) + throw SQLiteUserStorageError.prepareStatementError(message: getErrorMessage()) } prepareQueryResult = sqlite3_step(createTableStatement) guard prepareQueryResult == SQLITE_DONE else { - throw SQLiteDefaultStorageError.sqliteQueryError(message: getErrorMessage()) + throw SQLiteUserStorageError.sqliteQueryError(message: getErrorMessage()) } } } @@ -126,10 +126,10 @@ final class SQLiteHelper: @unchecked Sendable { let dbOperationResult = sqlite3_step(insertStatement) if dbOperationResult != SQLITE_DONE { - throw SQLiteDefaultStorageError.sqliteQueryError(message: getErrorMessage()) + throw SQLiteUserStorageError.sqliteQueryError(message: getErrorMessage()) } } else { - throw SQLiteDefaultStorageError.prepareStatementError(message: getErrorMessage()) + throw SQLiteUserStorageError.prepareStatementError(message: getErrorMessage()) } } } @@ -153,7 +153,7 @@ final class SQLiteHelper: @unchecked Sendable { nil ) guard dbOperationResult == SQLITE_OK else { - throw SQLiteDefaultStorageError.prepareStatementError(message: getErrorMessage()) + throw SQLiteUserStorageError.prepareStatementError(message: getErrorMessage()) } if let bindingsBlock = bindingsBlock { @@ -182,14 +182,14 @@ final class SQLiteHelper: @unchecked Sendable { ) guard dbOperationResult == SQLITE_OK else { - throw SQLiteDefaultStorageError.prepareStatementError(message: getErrorMessage()) + throw SQLiteUserStorageError.prepareStatementError(message: getErrorMessage()) } buildBindings(deleteStatement) dbOperationResult = sqlite3_step(deleteStatement) if dbOperationResult != SQLITE_DONE { - throw SQLiteDefaultStorageError.sqliteQueryError(message: getErrorMessage()) + throw SQLiteUserStorageError.sqliteQueryError(message: getErrorMessage()) } } } @@ -213,7 +213,7 @@ final class SQLiteHelper: @unchecked Sendable { ) guard dbOperationResult == SQLITE_OK else { - throw SQLiteDefaultStorageError.prepareStatementError(message: getErrorMessage()) + throw SQLiteUserStorageError.prepareStatementError(message: getErrorMessage()) } buildBindings(updateStatement) @@ -221,7 +221,7 @@ final class SQLiteHelper: @unchecked Sendable { dbOperationResult = sqlite3_step(updateStatement) guard dbOperationResult == SQLITE_DONE else { - throw SQLiteDefaultStorageError.sqliteQueryError(message: getErrorMessage()) + throw SQLiteUserStorageError.sqliteQueryError(message: getErrorMessage()) } } } @@ -250,7 +250,7 @@ final class SQLiteHelper: @unchecked Sendable { ) guard dbOperationResult == SQLITE_OK else { - throw SQLiteDefaultStorageError.prepareStatementError(message: getErrorMessage()) + throw SQLiteUserStorageError.prepareStatementError(message: getErrorMessage()) } var currentDatabaseVersion = Int32() @@ -269,7 +269,7 @@ final class SQLiteHelper: @unchecked Sendable { """ let result = sqlite3_exec(database, statement, nil, nil, nil) if result != SQLITE_OK { - throw SQLiteDefaultStorageError.sqliteQueryError(message: getErrorMessage()) + throw SQLiteUserStorageError.sqliteQueryError(message: getErrorMessage()) } } } @@ -294,7 +294,7 @@ final class SQLiteHelper: @unchecked Sendable { appropriateFor: nil, create: true ) else { - throw SQLiteDefaultStorageError.noDir + throw SQLiteUserStorageError.documentsDirectoryMissing } databaseDirectoryURL = directoryURL } diff --git a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift index 90d442f..510e19d 100644 --- a/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift +++ b/MIRACLTrust/MIRACLTrust-Sources/User Storage/SQLiteUserStorageError.swift @@ -1,10 +1,91 @@ -enum SQLiteDefaultStorageError: Error, Equatable { - case noDir +import Foundation + +/// An enumeration that describes issues with the default user storage. +enum SQLiteUserStorageError: Error { + /// There is no documents directory in the application. + case documentsDirectoryMissing + + /// Could not open database connection to the default storage. case noConnection + + /// Problem with querying the SQL storage. case sqliteQueryError(message: String?) + + /// Problem when preparing SQL statement. case prepareStatementError(message: String?) - case emptyOrNullParametersError - case encryptionError - case encryptionKeyUpdateError + + /// There is an error when configuring an encryption key. + case encryptionKeyConfigurationError + + /// Could not update encryption key accessibility. + case encryptionKeyUpdateAccessibilityError + + /// Could not add access group to the encryption key of the storage. case accessGroupUpdateError } + +extension SQLiteUserStorageError: Equatable { + static func == ( + lhs: SQLiteUserStorageError, + rhs: SQLiteUserStorageError + ) -> Bool { + String(reflecting: lhs) == String(reflecting: rhs) + } +} + +extension SQLiteUserStorageError: LocalizedError { + var errorDescription: String? { + var description = "" + switch self { + case .documentsDirectoryMissing: + description = NSLocalizedString("\(SQLiteUserStorageError.documentsDirectoryMissing)", comment: "") + case .noConnection: + description = NSLocalizedString("\(SQLiteUserStorageError.noConnection)", comment: "") + case let .sqliteQueryError(message: message): + description = NSLocalizedString("\(SQLiteUserStorageError.sqliteQueryError(message: message))", comment: "") + case let .prepareStatementError(message: message): + description = NSLocalizedString("\(SQLiteUserStorageError.prepareStatementError(message: message))", comment: "") + case .encryptionKeyConfigurationError: + description = NSLocalizedString("\(SQLiteUserStorageError.encryptionKeyConfigurationError)", comment: "") + case .encryptionKeyUpdateAccessibilityError: + description = NSLocalizedString("\(SQLiteUserStorageError.encryptionKeyUpdateAccessibilityError)", comment: "") + case .accessGroupUpdateError: + description = NSLocalizedString("\(SQLiteUserStorageError.accessGroupUpdateError)", comment: "") + } + return description + } +} + +extension SQLiteUserStorageError: CustomNSError { + var errorCode: Int { + switch self { + case .documentsDirectoryMissing: + 1 + case .noConnection: + 2 + case .sqliteQueryError: + 3 + case .prepareStatementError: + 4 + case .encryptionKeyConfigurationError: + 5 + case .encryptionKeyUpdateAccessibilityError: + 6 + case .accessGroupUpdateError: + 7 + } + } + + var errorUserInfo: [String: Any] { + switch self { + case let .sqliteQueryError(message), let .prepareStatementError(message): + if let message { + return ["message": message] + } else { + return [String: Any]() + } + default: + return [String: Any]() + } + } +} diff --git a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift index ec26aff..e3d811e 100644 --- a/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift +++ b/MIRACLTrust/MIRACLTrustTests/SQLiteUserStorageTests.swift @@ -90,9 +90,9 @@ class SQLiteUserStorageTests: XCTestCase { func testAddUserWithEmptyUserId() throws { let user = createUser(userId: "") XCTAssertThrowsError(try storage.add(user: user)) { error in - XCTAssertNotNil(error as? SQLiteDefaultStorageError) + XCTAssertNotNil(error as? SQLiteUserStorageError) var isErrorStorage = false - if case SQLiteDefaultStorageError.sqliteQueryError(message: _) = error { + if case SQLiteUserStorageError.sqliteQueryError(message: _) = error { isErrorStorage = true } @@ -123,9 +123,9 @@ class SQLiteUserStorageTests: XCTestCase { XCTAssertEqual(storage.all().count, 1) XCTAssertThrowsError(try storage.add(user: user)) { error in - XCTAssertNotNil(error as? SQLiteDefaultStorageError) + XCTAssertNotNil(error as? SQLiteUserStorageError) var isErrorStorage = false - if case SQLiteDefaultStorageError.sqliteQueryError(message: _) = error { + if case SQLiteUserStorageError.sqliteQueryError(message: _) = error { isErrorStorage = true } @@ -278,9 +278,9 @@ class SQLiteUserStorageTests: XCTestCase { XCTAssertThrowsError(try storage.update(user: user)) { error in XCTAssertEqual(storage.all().count, 1) - XCTAssertNotNil(error as? SQLiteDefaultStorageError) + XCTAssertNotNil(error as? SQLiteUserStorageError) var isErrorStorage = false - if case SQLiteDefaultStorageError.sqliteQueryError(message: _) = error { + if case SQLiteUserStorageError.sqliteQueryError(message: _) = error { isErrorStorage = true } @@ -323,9 +323,9 @@ class SQLiteUserStorageTests: XCTestCase { XCTAssertThrowsError(try storage.update(user: user)) { error in XCTAssertEqual(storage.all().count, 1) - XCTAssertNotNil(error as? SQLiteDefaultStorageError) + XCTAssertNotNil(error as? SQLiteUserStorageError) var isErrorStorage = false - if case SQLiteDefaultStorageError.sqliteQueryError(message: _) = error { + if case SQLiteUserStorageError.sqliteQueryError(message: _) = error { isErrorStorage = true } @@ -369,9 +369,9 @@ class SQLiteUserStorageTests: XCTestCase { XCTAssertThrowsError(try storage.update(user: user)) { error in XCTAssertEqual(storage.all().count, 1) - XCTAssertNotNil(error as? SQLiteDefaultStorageError) + XCTAssertNotNil(error as? SQLiteUserStorageError) var isErrorStorage = false - if case SQLiteDefaultStorageError.sqliteQueryError(message: _) = error { + if case SQLiteUserStorageError.sqliteQueryError(message: _) = error { isErrorStorage = true } @@ -407,9 +407,9 @@ class SQLiteUserStorageTests: XCTestCase { XCTAssertThrowsError(try storage.update(user: user)) { error in XCTAssertEqual(storage.all().count, 1) - XCTAssertNotNil(error as? SQLiteDefaultStorageError) + XCTAssertNotNil(error as? SQLiteUserStorageError) var isErrorStorage = false - if case SQLiteDefaultStorageError.sqliteQueryError(message: _) = error { + if case SQLiteUserStorageError.sqliteQueryError(message: _) = error { isErrorStorage = true } From e32652a1c4894c054b3e62e418e42252e269352f Mon Sep 17 00:00:00 2001 From: Radoslav Penev Date: Wed, 27 Aug 2025 17:06:55 +0300 Subject: [PATCH 5/5] Bump version to 1.4.0 --- MIRACLTrust.podspec | 2 +- .../MIRACLTrust.xcodeproj/project.pbxproj | 20 +++++++++---------- README.md | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/MIRACLTrust.podspec b/MIRACLTrust.podspec index dd83904..f818afe 100644 --- a/MIRACLTrust.podspec +++ b/MIRACLTrust.podspec @@ -5,7 +5,7 @@ Pod::Spec.new do |s| s.name = "MIRACLTrust" s.summary = "MIRACL Trust SDK for iOS" s.requires_arc = true - s.version = "1.3.0" + s.version = "1.4.0" s.license = { :type => "Apache2", :file => "LICENSE" } s.author = { "MIRACL" => "operations@miracl.com" } s.homepage = "https://github.com/miracl/trust-sdk-ios" diff --git a/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj b/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj index 61dcc5d..ece500e 100644 --- a/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj +++ b/MIRACLTrust/MIRACLTrust.xcodeproj/project.pbxproj @@ -1775,7 +1775,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.2; MARKETING_VERSION = "$(MIRACL_SDK_VERSION)"; - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -1838,7 +1838,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.2; MARKETING_VERSION = "$(MIRACL_SDK_VERSION)"; - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -1862,7 +1862,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; PRODUCT_BUNDLE_IDENTIFIER = "com.miracl.trust.sdk-ios.MIRACLTrustTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -1882,7 +1882,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; PRODUCT_BUNDLE_IDENTIFIER = "com.miracl.trust.sdk-ios.MIRACLTrustTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -1904,7 +1904,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; PRODUCT_BUNDLE_IDENTIFIER = com.radoslavpenev.MIRACLTrustIntegrationTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "MIRACLTrustIntegrationTests/Cases/MIRACLTrustIntegrationTests-Bridging-Header.h"; @@ -1929,7 +1929,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; PRODUCT_BUNDLE_IDENTIFIER = com.radoslavpenev.MIRACLTrustIntegrationTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "MIRACLTrustIntegrationTests/Cases/MIRACLTrustIntegrationTests-Bridging-Header.h"; @@ -1952,7 +1952,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; PRODUCT_BUNDLE_IDENTIFIER = "com.miracl.applclippoc.MIRACLTrust-Test-Host-App"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -1972,7 +1972,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.miracl.applclippoc.MIRACLTrust-Test-Host-App"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2011,7 +2011,7 @@ "$(PROJECT_DIR)/MIRACLTrust-Sources/Crypto/src", ); MARKETING_VERSION = "$(MIRACL_SDK_VERSION)"; - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; MODULEMAP_FILE = "$(SRCROOT)/MIRACLTrust-Sources/MIRACLTrust.modulemap"; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( @@ -2060,7 +2060,7 @@ "$(PROJECT_DIR)/MIRACLTrust-Sources/Crypto/src", ); MARKETING_VERSION = "$(MIRACL_SDK_VERSION)"; - MIRACL_SDK_VERSION = 1.3.0; + MIRACL_SDK_VERSION = 1.4.0; MODULEMAP_FILE = "$(SRCROOT)/MIRACLTrust-Sources/MIRACLTrust.modulemap"; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( diff --git a/README.md b/README.md index be8f857..42a743c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ To integrate using Apple's Swift package manager, without Xcode integration, add the following as a dependency to your Package.swift: ```bash -.package(url: "https://github.com/miracl/trust-sdk-ios", .upToNextMajor(from: "1.3.0")) +.package(url: "https://github.com/miracl/trust-sdk-ios", .upToNextMajor(from: "1.4.0")) ``` In both cases after the package is downloaded, go to the