From f738aaf358b341cce3ec73f66394625d5c1ff071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=E2=80=99Aquino?= Date: Fri, 8 Mar 2024 21:26:16 +0000 Subject: [PATCH 1/3] Increase verbosity of IAP-related logs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel D’Aquino --- damus/Models/Purple/DamusPurple.swift | 8 ++++---- damus/Models/Purple/StoreObserver.swift | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/damus/Models/Purple/DamusPurple.swift b/damus/Models/Purple/DamusPurple.swift index 1cc9d55c..73fed172 100644 --- a/damus/Models/Purple/DamusPurple.swift +++ b/damus/Models/Purple/DamusPurple.swift @@ -172,11 +172,11 @@ class DamusPurple: StoreObserverDelegate { let account_uuid = try await self.get_maybe_cached_uuid_for_account() let json_text: [String: String] = ["receipt": receipt_base64_string, "account_uuid": account_uuid.uuidString] let json_data = try JSONSerialization.data(withJSONObject: json_text) - + let url = environment.api_base_url().appendingPathComponent("accounts/\(keypair.pubkey.hex())/apple-iap/app-store-receipt") - - Log.info("Sending in-app purchase receipt to Damus Purple server", for: .damus_purple) - + + Log.info("Sending in-app purchase receipt to Damus Purple server: %s", for: .damus_purple, receipt_base64_string) + let (data, response) = try await make_nip98_authenticated_request( method: .post, url: url, diff --git a/damus/Models/Purple/StoreObserver.swift b/damus/Models/Purple/StoreObserver.swift index a78a585e..6dac8d6b 100644 --- a/damus/Models/Purple/StoreObserver.swift +++ b/damus/Models/Purple/StoreObserver.swift @@ -21,7 +21,8 @@ class StoreObserver: NSObject, SKPaymentTransactionObserver { //Observe transaction updates. func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { //Handle transaction states here. - + Log.info("StoreObserver received a transaction update. Notifying to delegate.", for: .damus_purple) + Task { try await self.delegate?.send_receipt() } From ad8d30ded10347f6e1a4d949d7dea47dccffb43a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=E2=80=99Aquino?= Date: Fri, 8 Mar 2024 21:26:23 +0000 Subject: [PATCH 2/3] Improve mechanism of IAP verification with the server right after purchase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was observed that sending the receipt to the server right after performing the StoreKit purchase caused issues due to the receipt not being completely ready when it got sent, causing rejections by the server. This commit, in conjuction with backend changes, implements purchase verification through transaction IDs directly. Testing -------- PASS Device: iPhone 13 Mini (physical device) iOS: 17.3.1 Damus: This commit damus-api: `a878da5598a9344a4d351f9a9da16712ce0615b7` Setup: - Local server Setup - Local testing mode on Damus developer settings - Clean Sandbox account (Create new sandbox account if clearing purchase history does not work) - Fresh DB - App is closed before starting. - Run app on release target - MOCK_VERIFY=false on server, with all IAP environment correctly setup Steps: 1. Make Purple IAP purchase. Make sure that: - Server logs indicate `/apple-iap/transaction-id` is being hit and returning HTTP 200. PASS - No errors appear on the iOS side. After purchase the welcome sheet should appear, and then the account info. PASS Part of: https://github.com/damus-io/damus/issues/2036 Changelog-Fixed: Fix in-app purchase issue that would trigger an error on purchase before confirming the account information. Signed-off-by: Daniel D’Aquino Signed-off-by: William Casarin --- damus/Models/Purple/DamusPurple.swift | 34 ++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/damus/Models/Purple/DamusPurple.swift b/damus/Models/Purple/DamusPurple.swift index 73fed172..9574e02a 100644 --- a/damus/Models/Purple/DamusPurple.swift +++ b/damus/Models/Purple/DamusPurple.swift @@ -120,8 +120,10 @@ class DamusPurple: StoreObserverDelegate { // Record the purchase with the storekit manager, to make sure we have the update on the UIs as soon as possible. // During testing I found that the purchase initiated via `purchase` was not emitted via the listener `StoreKit.Transaction.updates` until the app was restarted. self.storekit_manager.record_purchased_product(StoreKitManager.PurchasedProduct(tx: tx, product: product)) - // Send the receipt to the server - try await self.send_receipt() + await tx.finish() + // Send the transaction id to the server + try await self.send_transaction_id(transaction_id: tx.originalID) + default: // Any time we get a non-verified result, it means that the purchase was not successful, and thus we should throw an error. throw PurpleError.iap_purchase_error(result: result) @@ -196,7 +198,33 @@ class DamusPurple: StoreObserverDelegate { } } } - + + func send_transaction_id(transaction_id: UInt64) async throws { + let account_uuid = try await self.get_maybe_cached_uuid_for_account() + let json_text: [String: Any] = ["transaction_id": transaction_id, "account_uuid": account_uuid.uuidString] + let json_data = try JSONSerialization.data(withJSONObject: json_text) + + let url = environment.api_base_url().appendingPathComponent("accounts/\(keypair.pubkey.hex())/apple-iap/transaction-id") + + let (data, response) = try await make_nip98_authenticated_request( + method: .post, + url: url, + payload: json_data, + payload_type: .json, + auth_keypair: self.keypair + ) + + if let httpResponse = response as? HTTPURLResponse { + switch httpResponse.statusCode { + case 200: + Log.info("Sent transaction ID to Damus Purple server and activated successfully", for: .damus_purple) + default: + Log.error("Error in sending or verifying transaction ID with Damus Purple server. HTTP status code: %d; Response: %s", for: .damus_purple, httpResponse.statusCode, String(data: data, encoding: .utf8) ?? "Unknown") + throw DamusPurple.PurpleError.iap_receipt_verification_error(status: httpResponse.statusCode, response: data) + } + } + } + func translate(text: String, source source_language: String, target target_language: String) async throws -> String { var url = environment.api_base_url() url.append(path: "/translate") From 669ca0d91c9c17f42f5457c1d279d408d67a6b2b Mon Sep 17 00:00:00 2001 From: William Casarin Date: Mon, 11 Mar 2024 09:38:29 +0000 Subject: [PATCH 3/3] v1.7.2 Fix a few appstore iap-subscription purple ux issues Signed-off-by: William Casarin --- damus.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index d66ad874..ffacf051 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -3802,7 +3802,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -3823,7 +3823,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.0; MACOSX_DEPLOYMENT_TARGET = 12.3; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -3869,7 +3869,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -3885,7 +3885,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.0; MACOSX_DEPLOYMENT_TARGET = 12.3; - MARKETING_VERSION = 1.7.1; + MARKETING_VERSION = 1.7.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos;