diff --git a/README.md b/README.md index 1324843b..f07f2fe4 100644 --- a/README.md +++ b/README.md @@ -1144,6 +1144,7 @@ Process payment receipt Input: - `Authentication` in header: the api key - `receipt_data` in body: the receipt_data base64Encoded returned by StoreKit, i.e. `rawReceiptData.base64EncodedString` +- (optional) `is_macapp` in body: if this field is present, the request is sent from the MacApp (Safari Extension) and not iOS app. Output: 200 if user is upgraded successfully diff --git a/app/api/views/apple.py b/app/api/views/apple.py index c903ed21..5b49c692 100644 --- a/app/api/views/apple.py +++ b/app/api/views/apple.py @@ -8,7 +8,7 @@ from flask import request from flask_cors import cross_origin from app.api.base import api_bp, require_api_auth -from app.config import APPLE_API_SECRET +from app.config import APPLE_API_SECRET, MACAPP_APPLE_API_SECRET from app.extensions import db from app.log import LOG from app.models import PlanEnum, AppleSubscription @@ -16,6 +16,9 @@ from app.models import PlanEnum, AppleSubscription _MONTHLY_PRODUCT_ID = "io.simplelogin.ios_app.subscription.premium.monthly" _YEARLY_PRODUCT_ID = "io.simplelogin.ios_app.subscription.premium.yearly" +_MACAPP_MONTHLY_PRODUCT_ID = "io.simplelogin.macapp.subscription.premium.monthly" +_MACAPP_PRODUCT_ID = "io.simplelogin.macapp.subscription.premium.yearly" + # Apple API URL _SANDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt" _PROD_URL = "https://buy.itunes.apple.com/verifyReceipt" @@ -29,15 +32,23 @@ def apple_process_payment(): Process payment Input: receipt_data: in body + (optional) is_macapp: in body Output: 200 of the payment is successful, i.e. user is upgraded to premium """ LOG.debug("request for /apple/process_payment") user = g.user - receipt_data = request.get_json().get("receipt_data") + data = request.get_json() + receipt_data = data.get("receipt_data") + is_macapp = "is_macapp" in data - apple_sub = verify_receipt(receipt_data, user) + if is_macapp: + password = MACAPP_APPLE_API_SECRET + else: + password = APPLE_API_SECRET + + apple_sub = verify_receipt(receipt_data, user, password) if apple_sub: return jsonify(ok=True), 200 @@ -249,7 +260,8 @@ def apple_update_notification(): expires_date = arrow.get(int(transaction["expires_date_ms"]) / 1000) plan = ( PlanEnum.monthly - if transaction["product_id"] == _MONTHLY_PRODUCT_ID + if transaction["product_id"] + in (_MONTHLY_PRODUCT_ID, _MACAPP_MONTHLY_PRODUCT_ID) else PlanEnum.yearly ) @@ -279,7 +291,7 @@ def apple_update_notification(): return jsonify(ok=False), 400 -def verify_receipt(receipt_data, user) -> Optional[AppleSubscription]: +def verify_receipt(receipt_data, user, password) -> Optional[AppleSubscription]: """Call verifyReceipt endpoint and create/update AppleSubscription table Call the production URL for verifyReceipt first, and proceed to verify with the sandbox URL if receive a 21007 status code. @@ -290,15 +302,14 @@ def verify_receipt(receipt_data, user) -> Optional[AppleSubscription]: """ LOG.d("start verify_receipt") r = requests.post( - _PROD_URL, json={"receipt-data": receipt_data, "password": APPLE_API_SECRET} + _PROD_URL, json={"receipt-data": receipt_data, "password": password} ) if r.json() == {"status": 21007}: # try sandbox_url LOG.warning("Use the sandbox url instead") r = requests.post( - _SANDBOX_URL, - json={"receipt-data": receipt_data, "password": APPLE_API_SECRET}, + _SANDBOX_URL, json={"receipt-data": receipt_data, "password": password}, ) data = r.json() diff --git a/app/config.py b/app/config.py index 158c1331..86c65a42 100644 --- a/app/config.py +++ b/app/config.py @@ -243,4 +243,7 @@ with open(get_abs_path(DISPOSABLE_FILE_PATH), "r") as f: ] # Used when querying info on Apple API +# for iOS App APPLE_API_SECRET = os.environ.get("APPLE_API_SECRET") +# for Mac App +MACAPP_APPLE_API_SECRET = os.environ.get("MACAPP_APPLE_API_SECRET") diff --git a/cron.py b/cron.py index 98c2a0e2..407bfb4e 100644 --- a/cron.py +++ b/cron.py @@ -6,7 +6,12 @@ from arrow import Arrow from app import s3 from app.api.views.apple import verify_receipt -from app.config import IGNORED_EMAILS, ADMIN_EMAIL +from app.config import ( + IGNORED_EMAILS, + ADMIN_EMAIL, + MACAPP_APPLE_API_SECRET, + APPLE_API_SECRET, +) from app.email_utils import send_email, send_trial_end_soon_email, render from app.extensions import db from app.log import LOG @@ -114,7 +119,8 @@ def poll_apple_subscription(): # todo: only near the end of the subscription for apple_sub in AppleSubscription.query.all(): user = apple_sub.user - verify_receipt(apple_sub.receipt_data, user) + verify_receipt(apple_sub.receipt_data, user, APPLE_API_SECRET) + verify_receipt(apple_sub.receipt_data, user, MACAPP_APPLE_API_SECRET) LOG.d("Finish poll_apple_subscription") diff --git a/example.env b/example.env index f4265bdb..24e4147d 100644 --- a/example.env +++ b/example.env @@ -125,4 +125,5 @@ FACEBOOK_CLIENT_SECRET=to_fill # LANDING_PAGE_URL=https://simplelogin.io # Used when querying info on Apple API -# APPLE_API_SECRET=secret \ No newline at end of file +# APPLE_API_SECRET=secret +# MACAPP_APPLE_API_SECRET=secret \ No newline at end of file