diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml
index e35bb81..7d9a64c 100644
--- a/.github/workflows/swift.yml
+++ b/.github/workflows/swift.yml
@@ -26,7 +26,7 @@ jobs:
"hostname": "${{ secrets.SQ_LITE_CLOUD_HOST }}",
"username": "${{ secrets.SQ_LITE_CLOUD_USER }}",
"password": "${{ secrets.SQ_LITE_CLOUD_PASS }}",
- "apyKey": "${{ secrets.SQ_LITE_CLOUD_APIKEY }}"
+ "apiKey": "${{ secrets.SQ_LITE_CLOUD_APIKEY }}"
}
' >> Tests/SQLiteCloudTests/Secrets/secrets.json
diff --git a/Sources/SQLiteCloud/Core/SQLiteCloudConfig+Internal.swift b/Sources/SQLiteCloud/Core/SQLiteCloudConfig+Internal.swift
index 8e5c2c5..eda3e2b 100644
--- a/Sources/SQLiteCloud/Core/SQLiteCloudConfig+Internal.swift
+++ b/Sources/SQLiteCloud/Core/SQLiteCloudConfig+Internal.swift
@@ -32,8 +32,14 @@ extension SQLiteCloudConfig {
var sqConfig: SQCloudConfig {
var sqConfig = SQCloudConfig()
sqConfig.family = family.rawValue
- sqConfig.username = (username as NSString).utf8String
- sqConfig.password = (password as NSString).utf8String
+ if let username,
+ let password {
+ sqConfig.username = (username as NSString).utf8String
+ sqConfig.password = (password as NSString).utf8String
+ }
+ if let apiKey {
+ sqConfig.api_key = (apiKey as NSString).utf8String
+ }
sqConfig.password_hashed = passwordHashed
sqConfig.non_linearizable = nonlinearizable
sqConfig.timeout = Int32(timeout)
diff --git a/Sources/SQLiteCloud/Core/SQLiteCloudConfig.swift b/Sources/SQLiteCloud/Core/SQLiteCloudConfig.swift
index b49d298..2b8e61f 100644
--- a/Sources/SQLiteCloud/Core/SQLiteCloudConfig.swift
+++ b/Sources/SQLiteCloud/Core/SQLiteCloudConfig.swift
@@ -28,8 +28,9 @@ import Foundation
public struct SQLiteCloudConfig: Sendable {
public let hostname: String
public let port: Port
- public let username: String
- public let password: String
+ public let username: String?
+ public let password: String?
+ public let apiKey: String?
public let family: Family
public let passwordHashed: Bool
public let nonlinearizable: Bool
@@ -49,6 +50,52 @@ public struct SQLiteCloudConfig: Sendable {
public let clientCertificate: String?
public let clientCertificateKey: String?
+ public init(hostname: String,
+ apiKey: String,
+ port: Port = .default,
+ family: Family = .ipv4,
+ passwordHashed: Bool = false,
+ nonlinearizable: Bool = false,
+ timeout: Int = 0,
+ compression: Bool = false,
+ zerotext: Bool = false,
+ memory: Bool = false,
+ dbCreate: Bool = false,
+ insecure: Bool = false,
+ noblob: Bool = false,
+ isReadonlyConnection: Bool = false,
+ maxData: Int = 0,
+ maxRows: Int = 0,
+ maxRowset: Int = 0,
+ dbname: String? = nil,
+ rootCertificate: String? = nil,
+ clientCertificate: String? = nil,
+ clientCertificateKey: String? = nil) {
+ self.init(hostname: hostname,
+ username: nil,
+ password: nil,
+ apiKey: apiKey,
+ port: port,
+ family: family,
+ passwordHashed: passwordHashed,
+ nonlinearizable: nonlinearizable,
+ timeout: timeout,
+ compression: compression,
+ zerotext: zerotext,
+ memory: memory,
+ dbCreate: dbCreate,
+ insecure: insecure,
+ noblob: noblob,
+ isReadonlyConnection: isReadonlyConnection,
+ maxData: maxData,
+ maxRows: maxRows,
+ maxRowset: maxRowset,
+ dbname: dbname,
+ rootCertificate: rootCertificate,
+ clientCertificate: clientCertificate,
+ clientCertificateKey: clientCertificateKey)
+ }
+
public init(hostname: String,
username: String,
password: String,
@@ -71,10 +118,59 @@ public struct SQLiteCloudConfig: Sendable {
rootCertificate: String? = nil,
clientCertificate: String? = nil,
clientCertificateKey: String? = nil) {
+ self.init(hostname: hostname,
+ username: username,
+ password: password,
+ apiKey: nil,
+ port: port,
+ family: family,
+ passwordHashed: passwordHashed,
+ nonlinearizable: nonlinearizable,
+ timeout: timeout,
+ compression: compression,
+ zerotext: zerotext,
+ memory: memory,
+ dbCreate: dbCreate,
+ insecure: insecure,
+ noblob: noblob,
+ isReadonlyConnection: isReadonlyConnection,
+ maxData: maxData,
+ maxRows: maxRows,
+ maxRowset: maxRowset,
+ dbname: dbname,
+ rootCertificate: rootCertificate,
+ clientCertificate: clientCertificate,
+ clientCertificateKey: clientCertificateKey)
+ }
+
+ private init(hostname: String,
+ username: String?,
+ password: String?,
+ apiKey: String?,
+ port: Port = .default,
+ family: Family = .ipv4,
+ passwordHashed: Bool = false,
+ nonlinearizable: Bool = false,
+ timeout: Int = 0,
+ compression: Bool = false,
+ zerotext: Bool = false,
+ memory: Bool = false,
+ dbCreate: Bool = false,
+ insecure: Bool = false,
+ noblob: Bool = false,
+ isReadonlyConnection: Bool = false,
+ maxData: Int = 0,
+ maxRows: Int = 0,
+ maxRowset: Int = 0,
+ dbname: String? = nil,
+ rootCertificate: String? = nil,
+ clientCertificate: String? = nil,
+ clientCertificateKey: String? = nil) {
self.hostname = hostname
self.port = port
self.username = username
self.password = password
+ self.apiKey = apiKey
self.family = family
self.passwordHashed = passwordHashed
self.nonlinearizable = nonlinearizable
@@ -94,7 +190,7 @@ public struct SQLiteCloudConfig: Sendable {
self.clientCertificate = clientCertificate
self.clientCertificateKey = clientCertificateKey
}
-
+
public init?(connectionString: String) {
guard let url = URL(string: connectionString) else { return nil }
@@ -103,22 +199,38 @@ public struct SQLiteCloudConfig: Sendable {
/// sqlitecloud://user:pass@host.com:port/dbname?timeout=10&key2=value2&key3=value3.
public init?(connectionURL: URL) {
- guard let username = connectionURL.user else { return nil }
- guard let password = connectionURL.password else { return nil }
guard let hostname = connectionURL.host else { return nil }
- let port = connectionURL.port.map { Port.custom(portNumber: $0) } ?? .default
-
+
let urlComponents = URLComponents(string: connectionURL.absoluteString)
let queryItems = urlComponents?.queryItems
-
+
+ // There are 2 kind of possibile credentials types
+ // - based on an apikey
+ // - based on the username and the password combo
+ // We need to search for this credential info in the connection string.
+ // First we check for apikey, if fails we fallback on the user/pass combo.
+
+ if let apiKey = UrlParser.parse(items: queryItems, name: "apikey") {
+ self.username = nil
+ self.password = nil
+ self.apiKey = apiKey
+ } else {
+ guard let username = connectionURL.user else { return nil }
+ guard let password = connectionURL.password else { return nil }
+
+ self.username = username
+ self.password = password
+ self.apiKey = nil
+ }
+
+ let port = connectionURL.port.map { Port.custom(portNumber: $0) } ?? .default
+
// external
self.hostname = hostname
self.port = port
self.isReadonlyConnection = UrlParser.parse(items: queryItems, name: "readonly")
// in config
- self.username = username
- self.password = password
self.dbname = urlComponents?.path.replacingOccurrences(of: "/", with: "")
self.family = Family(rawValue: UrlParser.parse(items: queryItems, name: "family")) ?? .ipv4
self.passwordHashed = UrlParser.parse(items: queryItems, name: "passwordHashed")
@@ -143,7 +255,11 @@ public struct SQLiteCloudConfig: Sendable {
extension SQLiteCloudConfig {
var connectionString: String {
- "sqlitecloud://\(username):****@\(hostname):\(port.number)/\(dbname ?? .empty)"
+ if let apiKey {
+ "sqlitecloud://\(hostname):\(port.number)/\(dbname ?? .empty)?apikey=\(apiKey)"
+ } else {
+ "sqlitecloud://\(username ?? ""):****@\(hostname):\(port.number)/\(dbname ?? .empty)"
+ }
}
}
diff --git a/Sources/libsqcloud.xcframework/Info.plist b/Sources/libsqcloud.xcframework/Info.plist
index 33539da..a0032c8 100644
--- a/Sources/libsqcloud.xcframework/Info.plist
+++ b/Sources/libsqcloud.xcframework/Info.plist
@@ -10,18 +10,15 @@
HeadersPath
Headers
LibraryIdentifier
- ios-arm64_x86_64-simulator
+ ios-arm64
LibraryPath
libsqcloud.a
SupportedArchitectures
arm64
- x86_64
SupportedPlatform
ios
- SupportedPlatformVariant
- simulator
BinaryPath
@@ -29,15 +26,16 @@
HeadersPath
Headers
LibraryIdentifier
- ios-arm64
+ macos-arm64_x86_64
LibraryPath
libsqcloud.a
SupportedArchitectures
arm64
+ x86_64
SupportedPlatform
- ios
+ macos
BinaryPath
@@ -64,7 +62,7 @@
HeadersPath
Headers
LibraryIdentifier
- macos-arm64_x86_64
+ ios-arm64_x86_64-simulator
LibraryPath
libsqcloud.a
SupportedArchitectures
@@ -73,7 +71,9 @@
x86_64
SupportedPlatform
- macos
+ ios
+ SupportedPlatformVariant
+ simulator
CFBundlePackageType
diff --git a/Sources/libsqcloud.xcframework/ios-arm64/libsqcloud.a b/Sources/libsqcloud.xcframework/ios-arm64/libsqcloud.a
index b2ab4f2..7246852 100644
Binary files a/Sources/libsqcloud.xcframework/ios-arm64/libsqcloud.a and b/Sources/libsqcloud.xcframework/ios-arm64/libsqcloud.a differ
diff --git a/Sources/libsqcloud.xcframework/ios-arm64_x86_64-maccatalyst/libsqcloud.a b/Sources/libsqcloud.xcframework/ios-arm64_x86_64-maccatalyst/libsqcloud.a
index b761393..30cf6d4 100644
Binary files a/Sources/libsqcloud.xcframework/ios-arm64_x86_64-maccatalyst/libsqcloud.a and b/Sources/libsqcloud.xcframework/ios-arm64_x86_64-maccatalyst/libsqcloud.a differ
diff --git a/Sources/libsqcloud.xcframework/ios-arm64_x86_64-simulator/libsqcloud.a b/Sources/libsqcloud.xcframework/ios-arm64_x86_64-simulator/libsqcloud.a
index 0a61685..5968d13 100644
Binary files a/Sources/libsqcloud.xcframework/ios-arm64_x86_64-simulator/libsqcloud.a and b/Sources/libsqcloud.xcframework/ios-arm64_x86_64-simulator/libsqcloud.a differ
diff --git a/Sources/libsqcloud.xcframework/macos-arm64_x86_64/libsqcloud.a b/Sources/libsqcloud.xcframework/macos-arm64_x86_64/libsqcloud.a
index a008cc7..7a0f290 100644
Binary files a/Sources/libsqcloud.xcframework/macos-arm64_x86_64/libsqcloud.a and b/Sources/libsqcloud.xcframework/macos-arm64_x86_64/libsqcloud.a differ
diff --git a/Sources/libtls.xcframework/Info.plist b/Sources/libtls.xcframework/Info.plist
index fd21744..d97cdd3 100644
--- a/Sources/libtls.xcframework/Info.plist
+++ b/Sources/libtls.xcframework/Info.plist
@@ -29,15 +29,16 @@
HeadersPath
Headers
LibraryIdentifier
- ios-arm64
+ macos-arm64_x86_64
LibraryPath
libtls.a
SupportedArchitectures
arm64
+ x86_64
SupportedPlatform
- ios
+ macos
BinaryPath
@@ -45,16 +46,15 @@
HeadersPath
Headers
LibraryIdentifier
- macos-arm64_x86_64
+ ios-arm64
LibraryPath
libtls.a
SupportedArchitectures
arm64
- x86_64
SupportedPlatform
- macos
+ ios
BinaryPath
diff --git a/Sources/libtls.xcframework/ios-arm64/libtls.a b/Sources/libtls.xcframework/ios-arm64/libtls.a
index e6653a2..38af8e1 100644
Binary files a/Sources/libtls.xcframework/ios-arm64/libtls.a and b/Sources/libtls.xcframework/ios-arm64/libtls.a differ
diff --git a/Sources/libtls.xcframework/ios-arm64_x86_64-maccatalyst/libtls.a b/Sources/libtls.xcframework/ios-arm64_x86_64-maccatalyst/libtls.a
index 5baa5ff..05e5498 100644
Binary files a/Sources/libtls.xcframework/ios-arm64_x86_64-maccatalyst/libtls.a and b/Sources/libtls.xcframework/ios-arm64_x86_64-maccatalyst/libtls.a differ
diff --git a/Sources/libtls.xcframework/ios-arm64_x86_64-simulator/libtls.a b/Sources/libtls.xcframework/ios-arm64_x86_64-simulator/libtls.a
index 5c6b678..67d888b 100644
Binary files a/Sources/libtls.xcframework/ios-arm64_x86_64-simulator/libtls.a and b/Sources/libtls.xcframework/ios-arm64_x86_64-simulator/libtls.a differ
diff --git a/Sources/libtls.xcframework/macos-arm64_x86_64/libtls.a b/Sources/libtls.xcframework/macos-arm64_x86_64/libtls.a
index 460d5e5..f0e4422 100644
Binary files a/Sources/libtls.xcframework/macos-arm64_x86_64/libtls.a and b/Sources/libtls.xcframework/macos-arm64_x86_64/libtls.a differ
diff --git a/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Blob.swift b/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Blob.swift
index e0e17ff..a4aec56 100644
--- a/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Blob.swift
+++ b/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Blob.swift
@@ -40,7 +40,7 @@ final class SQLiteCloudTests_Blob: XCTestCase {
hostname = secrets.hostname
username = secrets.username
password = secrets.password
-
+
let config = SQLiteCloudConfig(hostname: hostname, username: username, password: password)
cloud = SQLiteCloud(config: config)
try await cloud.connect()
diff --git a/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Connection.swift b/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Connection.swift
index 4e8464f..7d50fbb 100644
--- a/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Connection.swift
+++ b/Tests/SQLiteCloudTests/Integrations/SQLiteCloudTests+Connection.swift
@@ -30,12 +30,14 @@ final class SQLiteCloudTests_Connection: XCTestCase {
private var hostname: String = .empty
private var username: String = .empty
private var password: String = .empty
+ private var apiKey: String = .empty
override func setUpWithError() throws {
let secrets = try Secrets.load()
hostname = secrets.hostname
username = secrets.username
password = secrets.password
+ apiKey = secrets.apiKey
}
func test_connect_withValidCredentials_shouldConnectWithoutError() async throws {
@@ -48,7 +50,18 @@ final class SQLiteCloudTests_Connection: XCTestCase {
XCTFail("An error was thrown: \(error)")
}
}
-
+
+ func test_connect_withValidCredentialAPIKey_shouldConnectWithoutError() async throws {
+ let config = SQLiteCloudConfig(hostname: hostname, apiKey: apiKey)
+ let cloud = SQLiteCloud(config: config)
+
+ do {
+ try await cloud.connect()
+ } catch {
+ XCTFail("An error was thrown: \(error)")
+ }
+ }
+
func test_connect_withInvalidCredentials_shouldThrowError() async throws {
let config = SQLiteCloudConfig(hostname: hostname, username: "!!invalid!!", password: "!!credentials!!")
let cloud = SQLiteCloud(config: config)
@@ -60,7 +73,19 @@ final class SQLiteCloudTests_Connection: XCTestCase {
XCTAssert(error is SQLiteCloudError)
}
}
-
+
+ func test_connect_withInvalidCredentialAPIKey_shouldThrowError() async throws {
+ let config = SQLiteCloudConfig(hostname: hostname, apiKey: "!!invalid!!")
+ let cloud = SQLiteCloud(config: config)
+
+ do {
+ try await cloud.connect()
+ XCTFail("No errors were thrown.")
+ } catch {
+ XCTAssert(error is SQLiteCloudError)
+ }
+ }
+
func test_disconnect_withValidConnection_shouldDisconnectWithoutError() async throws {
let config = SQLiteCloudConfig(hostname: hostname, username: username, password: password)
let cloud = SQLiteCloud(config: config)
diff --git a/Tests/SQLiteCloudTests/Secrets/Secrets.swift b/Tests/SQLiteCloudTests/Secrets/Secrets.swift
index 4cbce11..77b73bd 100644
--- a/Tests/SQLiteCloudTests/Secrets/Secrets.swift
+++ b/Tests/SQLiteCloudTests/Secrets/Secrets.swift
@@ -29,6 +29,7 @@ struct Secrets: Decodable {
let hostname: String
let username: String
let password: String
+ let apiKey: String
}
extension Secrets {
diff --git a/Tests/SQLiteCloudTests/Secrets/secrets.json.sample b/Tests/SQLiteCloudTests/Secrets/secrets.json.sample
index e8a3d92..ffdc227 100644
--- a/Tests/SQLiteCloudTests/Secrets/secrets.json.sample
+++ b/Tests/SQLiteCloudTests/Secrets/secrets.json.sample
@@ -1,5 +1,6 @@
{
"hostname": "",
"username": "",
- "password": ""
+ "password": "",
+ "apiKey": ""
}