diff --git a/Bitkit.xcodeproj/project.pbxproj b/Bitkit.xcodeproj/project.pbxproj
index 7ca9acdc6..b2fd14bbb 100644
--- a/Bitkit.xcodeproj/project.pbxproj
+++ b/Bitkit.xcodeproj/project.pbxproj
@@ -1175,7 +1175,7 @@
repositoryURL = "https://github.com/pubky/paykit-rs";
requirement = {
kind = exactVersion;
- version = "0.1.0-rc39";
+ version = "0.1.0-rc42";
};
};
18D65DFE2EB9649F00252335 /* XCRemoteSwiftPackageReference "vss-rust-client-ffi" */ = {
diff --git a/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 0c3fa0aef..30374f26a 100644
--- a/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -42,8 +42,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pubky/paykit-rs",
"state" : {
- "revision" : "2fa056570bd5f93c166e43cf16c5356f6407cbbd",
- "version" : "0.1.0-rc39"
+ "revision" : "192fc700897c3792ae4af221591572f3472089e1",
+ "version" : "0.1.0-rc42"
}
},
{
diff --git a/Bitkit/Constants/Env.swift b/Bitkit/Constants/Env.swift
index 54d037750..fe723acc0 100644
--- a/Bitkit/Constants/Env.swift
+++ b/Bitkit/Constants/Env.swift
@@ -71,7 +71,7 @@ enum Env {
(infoPlistValue("E2E_BACKEND") ?? "local").lowercased()
}
- private static var isLocalE2EBackend: Bool {
+ static var isLocalE2EBackend: Bool {
isE2E && e2eBackend == "local"
}
diff --git a/Bitkit/Info.plist b/Bitkit/Info.plist
index 5ae0d535c..e7804ec2b 100644
--- a/Bitkit/Info.plist
+++ b/Bitkit/Info.plist
@@ -21,6 +21,8 @@
E2E_BACKEND
$(E2E_BACKEND)
+ E2E_HOMEGATE_URL
+ $(E2E_HOMEGATE_URL)
E2E_NETWORK
$(E2E_NETWORK)
TREZOR_BRIDGE
diff --git a/Bitkit/Models/PubkyAuthRequest.swift b/Bitkit/Models/PubkyAuthRequest.swift
index aaca814e5..23efee576 100644
--- a/Bitkit/Models/PubkyAuthRequest.swift
+++ b/Bitkit/Models/PubkyAuthRequest.swift
@@ -5,7 +5,13 @@ enum PubkyAuthClaim: String, Equatable {
case watchOnlyAccountV1 = "watch-only-account-v1"
static let queryParameter = "x-bitkit-claim"
- static let watchOnlyAccountCapabilities = "/pub/paykit/v0/bitkit/server/:rw"
+ static let watchOnlyAccountCapabilities = "/pub/paykit/v0/bitkit/server/:rw,/pub/paykit/v0/private/bitkit/server/:rw"
+ private static let watchOnlyAccountCapabilitySet = Set(watchOnlyAccountCapabilities.split(separator: ",").map(String.init))
+
+ static func matchesWatchOnlyAccountCapabilities(_ capabilities: String) -> Bool {
+ let requestedCapabilitySet = Set(capabilities.split(separator: ",").map(String.init))
+ return requestedCapabilitySet == watchOnlyAccountCapabilitySet
+ }
}
enum PubkyAuthRequestError: Error, Equatable {
@@ -79,7 +85,7 @@ struct PubkyAuthRequest {
throw PubkyAuthRequestError.duplicateBitkitClaim
}
guard let claimValue = claimValues.first else {
- if capabilities == PubkyAuthClaim.watchOnlyAccountCapabilities {
+ if PubkyAuthClaim.matchesWatchOnlyAccountCapabilities(capabilities) {
throw PubkyAuthRequestError.missingBitkitClaim
}
return nil
@@ -87,7 +93,7 @@ struct PubkyAuthRequest {
guard let claim = PubkyAuthClaim(rawValue: claimValue) else {
throw PubkyAuthRequestError.unsupportedBitkitClaim(claimValue)
}
- guard capabilities == PubkyAuthClaim.watchOnlyAccountCapabilities else {
+ guard PubkyAuthClaim.matchesWatchOnlyAccountCapabilities(capabilities) else {
throw PubkyAuthRequestError.invalidBitkitClaimCapabilities
}
diff --git a/Bitkit/Services/PubkyService.swift b/Bitkit/Services/PubkyService.swift
index 3ad14422c..5ce423b8b 100644
--- a/Bitkit/Services/PubkyService.swift
+++ b/Bitkit/Services/PubkyService.swift
@@ -789,11 +789,12 @@ actor PaykitSdkService {
return sdk
}
- let created = try PaykitSdk.withPaymentAdapter(
+ let created = try PaykitSdk.withPaymentAdapterAndPubkyClientConfig(
stateStore: stateStore,
sessionProvider: sessionProvider,
paymentAdapter: paymentAdapter,
- config: Self.config()
+ config: Self.config(),
+ pubkyClient: Self.pubkyClientConfig()
)
sdk = created
return created
@@ -925,7 +926,15 @@ actor PaykitSdkService {
}
private func bootstrap() throws -> PubkySessionBootstrap {
- try PubkySessionBootstrap()
+ try PubkySessionBootstrap.withPubkyClientConfig(pubkyClient: Self.pubkyClientConfig())
+ }
+
+ nonisolated static func pubkyClientConfig(isLocalE2EBackend: Bool = Env.isLocalE2EBackend) -> PubkyClientConfig {
+ var config = Paykit.defaultPubkyClientConfig()
+ if isLocalE2EBackend {
+ config.localTestnetHost = "localhost"
+ }
+ return config
}
private nonisolated static func config() throws -> PaykitSdkConfig {
diff --git a/BitkitTests/PaykitSdkClientConfigTests.swift b/BitkitTests/PaykitSdkClientConfigTests.swift
new file mode 100644
index 000000000..2384b4108
--- /dev/null
+++ b/BitkitTests/PaykitSdkClientConfigTests.swift
@@ -0,0 +1,17 @@
+@testable import Bitkit
+import Paykit
+import XCTest
+
+final class PaykitSdkClientConfigTests: XCTestCase {
+ func testProductionUsesDefaultPubkyClient() {
+ let config = PaykitSdkService.pubkyClientConfig(isLocalE2EBackend: false)
+
+ XCTAssertNil(config.localTestnetHost)
+ }
+
+ func testLocalE2EUsesLocalPubkyTestnet() {
+ let config = PaykitSdkService.pubkyClientConfig(isLocalE2EBackend: true)
+
+ XCTAssertEqual(config.localTestnetHost, "localhost")
+ }
+}
diff --git a/BitkitTests/PubkyAuthRequestTests.swift b/BitkitTests/PubkyAuthRequestTests.swift
index 0539982f5..a45b423ff 100644
--- a/BitkitTests/PubkyAuthRequestTests.swift
+++ b/BitkitTests/PubkyAuthRequestTests.swift
@@ -33,6 +33,18 @@ final class PubkyAuthRequestTests: XCTestCase {
XCTAssertEqual(request.bitkitClaim, .watchOnlyAccountV1)
}
+ func testParseUrlRecognizesWatchOnlyAccountClaimWithReorderedCapabilities() throws {
+ let capabilities = PubkyAuthClaim.watchOnlyAccountCapabilities
+ .split(separator: ",")
+ .reversed()
+ .joined(separator: ",")
+ let url = authUrl(capabilities: capabilities, claimValues: [PubkyAuthClaim.watchOnlyAccountV1.rawValue])
+
+ let request = try PubkyAuthRequest.parse(url: url)
+
+ XCTAssertEqual(request.bitkitClaim, .watchOnlyAccountV1)
+ }
+
func testParseUrlWithoutBitkitClaimPreservesNormalAuth() throws {
let request = try PubkyAuthRequest.parse(url: authUrl(capabilities: "/pub/bitkit.to/:rw"))
@@ -74,6 +86,15 @@ final class PubkyAuthRequestTests: XCTestCase {
}
}
+ func testParseUrlRejectsWatchOnlyClaimWithoutPrivateCapability() {
+ let capabilities = "/pub/paykit/v0/bitkit/server/:rw"
+ let url = authUrl(capabilities: capabilities, claimValues: [PubkyAuthClaim.watchOnlyAccountV1.rawValue])
+
+ XCTAssertThrowsError(try PubkyAuthRequest.parse(url: url)) {
+ XCTAssertEqual($0 as? PubkyAuthRequestError, .invalidBitkitClaimCapabilities)
+ }
+ }
+
// MARK: - parseCapabilities
func testParseCapabilitiesSingleEntry() {
diff --git a/changelog.d/next/653.fixed.md b/changelog.d/next/653.fixed.md
new file mode 100644
index 000000000..5e47caa71
--- /dev/null
+++ b/changelog.d/next/653.fixed.md
@@ -0,0 +1 @@
+Fixed Paykit Server authorization to require both public and private payment capabilities.