Skip to content

Commit

Permalink
Merge pull request #281 from bizz84/feature/verifyReceipt-receiptVeri…
Browse files Browse the repository at this point in the history
…ficator-remove-password

Remove `password` from `ReceiptValidator` protocol as this is specific to `AppleReceiptValidator`
  • Loading branch information
bizz84 authored Oct 11, 2017
2 parents 1eccddc + e42765b commit 90bb551
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 47 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

All notable changes to this project will be documented in this file.

## [0.10.9](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.9) Add `fetchReceipt` method
## [0.11.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.11.0) Add `fetchReceipt` method + update `verifyReceipt` and `ReceiptValidator` protocol

* Add `fetchReceipt` method. Update `verifyReceipt` to use it ([#278](https://github.com/bizz84/SwiftyStoreKit/pull/278), related issues: [#272](https://github.com/bizz84/SwiftyStoreKit/issues/272), [#223](https://github.com/bizz84/SwiftyStoreKit/issues/223)).
* Remove `password` from `ReceiptValidator` protocol as this is specific to `AppleReceiptValidator` ([#281](https://github.com/bizz84/SwiftyStoreKit/pull/281/)). **Note**: This is an API breaking change.


## [0.10.8](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.8) Update to swiftlint 0.22.0

Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,8 @@ If `fetchReceipt` is successful, it will return the **encrypted** receipt as a s
Use this method to (optionally) refresh the receipt and perform validation in one step.

```swift
let appleValidator = AppleReceiptValidator(service: .production)
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret", forceRefresh: false) { result in
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator, forceRefresh: false) { result in
switch result {
case .success(let receipt):
print("Verify receipt Success: \(receipt)")
Expand Down Expand Up @@ -353,8 +353,8 @@ If you need to verify multiple purchases / subscriptions, you can either:
### Verify Purchase

```swift
let appleValidator = AppleReceiptValidator(service: .production)
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
// Verify the purchase of Consumable or NonConsumable
Expand Down Expand Up @@ -387,8 +387,8 @@ From [Apple - Working with Subscriptions](https://developer.apple.com/library/co
When one or more subscriptions are found for a given product id, they are returned as a `ReceiptItem` array ordered by `expiryDate`, with the first one being the newest.

```swift
let appleValidator = AppleReceiptValidator(service: .production)
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
// Verify the purchase of a Subscription
Expand Down Expand Up @@ -448,8 +448,8 @@ SwiftyStoreKit.purchaseProduct(productId, atomically: true) { result in
SwiftyStoreKit.finishTransaction(purchase.transaction)
}

let appleValidator = AppleReceiptValidator(service: .production)
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in

if case .success(let receipt) = result {
let purchaseResult = SwiftyStoreKit.verifySubscription(
Expand Down
5 changes: 2 additions & 3 deletions SwiftyStoreKit-iOS-Demo/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ class ViewController: UIViewController {

func verifyReceipt(completion: @escaping (VerifyReceiptResult) -> Void) {

let appleValidator = AppleReceiptValidator(service: .production)
let password = "your-shared-secret"
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: password, completion: completion)
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator, completion: completion)
}

func verifyPurchase(_ purchase: RegisteredPurchase) {
Expand Down
5 changes: 2 additions & 3 deletions SwiftyStoreKit-macOS-Demo/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,8 @@ class ViewController: NSViewController {

func verifyReceipt(completion: @escaping (VerifyReceiptResult) -> Void) {

let appleValidator = AppleReceiptValidator(service: .production)
let password = "your-shared-secret"
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: password, completion: completion)
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator, completion: completion)
}

func verifyPurchase(_ purchase: RegisteredPurchase) {
Expand Down
24 changes: 14 additions & 10 deletions SwiftyStoreKit/AppleReceiptValidator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,28 @@ public struct AppleReceiptValidator: ReceiptValidator {
case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
}

public init(service: VerifyReceiptURLType = .production) {
private let service: VerifyReceiptURLType
private let sharedSecret: String?

/**
* Reference Apple Receipt Validator
* - Parameter service: Either .production or .sandbox
* - Parameter sharedSecret: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
*/
public init(service: VerifyReceiptURLType = .production, sharedSecret: String? = nil) {
self.service = service
self.sharedSecret = sharedSecret
}

private let service: VerifyReceiptURLType

public func validate(
receipt: String,
password autoRenewPassword: String? = nil,
completion: @escaping (VerifyReceiptResult) -> Void) {
public func validate(receipt: String, completion: @escaping (VerifyReceiptResult) -> Void) {

let storeURL = URL(string: service.rawValue)! // safe (until no more)
let storeRequest = NSMutableURLRequest(url: storeURL)
storeRequest.httpMethod = "POST"

let requestContents: NSMutableDictionary = [ "receipt-data": receipt ]
// password if defined
if let password = autoRenewPassword {
if let password = sharedSecret {
requestContents.setValue(password, forKey: "password")
}

Expand Down Expand Up @@ -101,8 +105,8 @@ public struct AppleReceiptValidator: ReceiptValidator {
*/
let receiptStatus = ReceiptStatus(rawValue: status) ?? ReceiptStatus.unknown
if case .testReceipt = receiptStatus {
let sandboxValidator = AppleReceiptValidator(service: .sandbox)
sandboxValidator.validate(receipt: receipt, password: autoRenewPassword, completion: completion)
let sandboxValidator = AppleReceiptValidator(service: .sandbox, sharedSecret: self.sharedSecret)
sandboxValidator.validate(receipt: receipt, completion: completion)
} else {
if receiptStatus.isValid {
completion(.success(receipt: receiptInfo))
Expand Down
13 changes: 4 additions & 9 deletions SwiftyStoreKit/InAppReceiptVerificator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,19 @@ class InAppReceiptVerificator: NSObject {
/**
* Verify application receipt.
* - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format
* - Parameter password: Your app’s shared secret (a hexadecimal string). Only used for receipts that contain auto-renewable subscriptions.
* - Parameter forceRefresh: If true, refreshes the receipt even if one already exists.
* - Parameter refresh: closure to perform receipt refresh (this is made explicit for testability)
* - Parameter completion: handler for result
*/
public func verifyReceipt(using validator: ReceiptValidator,
password: String? = nil,
forceRefresh: Bool,
refresh: InAppReceiptRefreshRequest.ReceiptRefresh = InAppReceiptRefreshRequest.refresh,
completion: @escaping (VerifyReceiptResult) -> Void) {

fetchReceipt(forceRefresh: forceRefresh, refresh: refresh) { result in
switch result {
case .success(let encryptedReceipt):
self.verify(receipt: encryptedReceipt, using: validator, password: password, completion: completion)
self.verify(receipt: encryptedReceipt, using: validator, completion: completion)
case .error(let error):
completion(.error(error: error))
}
Expand All @@ -79,9 +77,7 @@ class InAppReceiptVerificator: NSObject {
completion: @escaping (FetchReceiptResult) -> Void) {

if let receiptData = appStoreReceiptData, forceRefresh == false {

fetchReceiptSuccessHandler(receiptData: receiptData, completion: completion)

} else {

receiptRefreshRequest = refresh(nil) { result in
Expand Down Expand Up @@ -111,12 +107,11 @@ class InAppReceiptVerificator: NSObject {
/**
* - Parameter receiptData: encrypted receipt data
* - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format
* - Parameter password: Your app’s shared secret (a hexadecimal string). Only used for receipts that contain auto-renewable subscriptions.
* - Parameter completion: handler for result
*/
private func verify(receipt: String, using validator: ReceiptValidator, password: String? = nil, completion: @escaping (VerifyReceiptResult) -> Void) {

validator.validate(receipt: receipt, password: password) { result in
private func verify(receipt: String, using validator: ReceiptValidator, completion: @escaping (VerifyReceiptResult) -> Void) {
validator.validate(receipt: receipt) { result in

DispatchQueue.main.async {
completion(result)
Expand Down
2 changes: 1 addition & 1 deletion SwiftyStoreKit/SwiftyStoreKit+Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public struct PurchaseDetails {

//Conform to this protocol to provide custom receipt validator
public protocol ReceiptValidator {
func validate(receipt: String, password autoRenewPassword: String?, completion: @escaping (VerifyReceiptResult) -> Void)
func validate(receipt: String, completion: @escaping (VerifyReceiptResult) -> Void)
}

// Payment transaction
Expand Down
5 changes: 2 additions & 3 deletions SwiftyStoreKit/SwiftyStoreKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,12 @@ extension SwiftyStoreKit {
/**
* Verify application receipt
* - Parameter validator: receipt validator to use
* - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
* - Parameter forceRefresh: If true, refreshes the receipt even if one already exists.
* - Parameter completion: handler for result
*/
public class func verifyReceipt(using validator: ReceiptValidator, password: String? = nil, forceRefresh: Bool = false, completion: @escaping (VerifyReceiptResult) -> Void) {
public class func verifyReceipt(using validator: ReceiptValidator, forceRefresh: Bool = false, completion: @escaping (VerifyReceiptResult) -> Void) {

sharedInstance.receiptVerificator.verifyReceipt(using: validator, password: password, forceRefresh: forceRefresh, completion: completion)
sharedInstance.receiptVerificator.verifyReceipt(using: validator, forceRefresh: forceRefresh, completion: completion)
}

/**
Expand Down
18 changes: 9 additions & 9 deletions SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import XCTest

class TestReceiptValidator: ReceiptValidator {
var validateCalled = false
func validate(receipt: String, password autoRenewPassword: String?, completion: @escaping (VerifyReceiptResult) -> Void) {
func validate(receipt: String, completion: @escaping (VerifyReceiptResult) -> Void) {
validateCalled = true
completion(.success(receipt: [:]))
}
Expand Down Expand Up @@ -76,7 +76,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)

var refreshCalled = false
verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

refreshCalled = true
return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)
Expand All @@ -95,7 +95,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)

var refreshCalled = false
verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

refreshCalled = true
return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)
Expand All @@ -115,7 +115,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)

var refreshCalled = false
verificator.verifyReceipt(using: validator, password: nil, forceRefresh: true, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: true, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

refreshCalled = true
return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)
Expand All @@ -132,7 +132,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)
let refreshError = NSError(domain: "", code: 0, userInfo: nil)

verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

callback(.error(e: refreshError))
return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)
Expand All @@ -148,7 +148,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let validator = TestReceiptValidator()
let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)

verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

callback(.success)
return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)
Expand All @@ -167,7 +167,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let validator = TestReceiptValidator()
let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)

verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

writeReceiptData(to: testReceiptURL)
callback(.success)
Expand All @@ -188,7 +188,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let validator = TestReceiptValidator()
let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)

verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

writeReceiptData(to: testReceiptURL)
callback(.success)
Expand All @@ -210,7 +210,7 @@ class InAppReceiptVerificatorTests: XCTestCase {
let validator = TestReceiptValidator()
let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)

verificator.verifyReceipt(using: validator, password: nil, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in
verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in

XCTFail("refresh should not be called if we already have a receipt")
return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)
Expand Down

0 comments on commit 90bb551

Please sign in to comment.