예제 #1
0
 def test_shortcut(self):
     try:
         from testdata import sandbox_receipt
     except ImportError:
         print('No receipt data to test')
         return
     mode = itunesiap.get_verification_mode()
     itunesiap.set_verification_mode('sandbox')
     itunesiap.verify(sandbox_receipt)
     itunesiap.set_verification_mode(mode)
예제 #2
0
 def test_shortcut(self):
     try:
         from testdata import sandbox_receipt
     except ImportError:
         print('No receipt data to test')
         return
     mode = itunesiap.get_verification_mode()
     itunesiap.set_verification_mode('sandbox')
     itunesiap.verify(sandbox_receipt)
     itunesiap.set_verification_mode(mode)
예제 #3
0
def test_invalid_receipt():
    request = itunesiap.Request('wrong receipt')

    with pytest.raises(itunesiap.exc.InvalidReceipt):
        request.verify(env=itunesiap.env.production)

    with pytest.raises(itunesiap.exc.InvalidReceipt):
        request.verify(env=itunesiap.env.sandbox)

    try:
        itunesiap.verify('bad data')
    except itunesiap.exc.InvalidReceipt as e:
        print(e)  # __str__ test
        print(repr(e))  # __repr__ test
예제 #4
0
def _verify_itunes_receipt(receipt_data):
    expires_date_ms = "0"
    code = 200
    itunes_shared_secret = os.environ['SELSTA101_ITUNES_SHARED_SECRET']

    try:
        with itunesiap.env.review:
            response = itunesiap.verify(receipt_data, itunes_shared_secret)
            in_apps = response.receipt.in_app
            for i in in_apps:
                new_expires_date_ms = i["expires_date_ms"]
                if int(new_expires_date_ms) > int(expires_date_ms):
                    expires_date_ms = new_expires_date_ms
    except itunesiap.exc.InvalidReceipt:
        code = 400
        logger.error("invalid receipt")
    except itunesiap.exc.ItunesServerNotAvailable:
        code = 444
        logger.error("ItunesServiceNotAvailable")
    except itunesiap.exc.ItunesServerNotReachable:
        code = 408
        logger.error("iTunesServerNotReachable")
    except Exception:
        code = 500
        logger.error("Unexpected error, itunesiap")

    if code == 500:
        """This case is a bug in itunesiap module on rare. It will be working to try once again."""
        return _verify_itunes_receipt(receipt_data)

    return code, expires_date_ms
예제 #5
0
async def verifyOrder(receipt: str,
                      orderId: str,
                      db: Session = Depends(get_db),
                      device: int = Header(None),
                      userId: int = Depends(token_is_true)):
    try:
        response = itunesiap.verify(str)
        db_order = crud.getOrderByOrderId(orderId=orderId)
        if db_order:
            # response.receipt.last_login_time
            pass
        else:
            return BaseErrResponse(code=403, message="订单不存在")
    except itunesiap.exc.InvalidReceipt as e:
        return BaseErrResponse(code=403, message="订单校验失败")
예제 #6
0
def validate():
    # Setup parser
    p = optparse.OptionParser(
        description=' Validate iTunes in-app purchase receipt',
        prog='validate.py',
        version='validate 0.1',
        usage='%prog receipt.txt'
    )
    options, arguments = p.parse_args()
    if len(arguments) == 1 and os.path.exists(arguments[0]):
        f = open(arguments[0])
        try:
            # base64-encoded data from file argument
            response = itunesiap.verify(f.read())
            print response.receipt.last_in_app.product_id
        except itunesiap.exc.InvalidReceipt as e:
            print 'invalid receipt: ' + e.description
    else:
        p.print_help()
예제 #7
0
def itunes_response_legacy1(raw_receipt_legacy):
    response = itunesiap.verify(raw_receipt_legacy, env=itunesiap.env.sandbox)
    return getattr(response, '_')
예제 #8
0
def itunes_response_legacy1(raw_receipt_legacy):
    response = itunesiap.verify(raw_receipt_legacy, env=itunesiap.env.sandbox)
    return getattr(response, '_')
예제 #9
0
def test_shortcut():
    """Test shortcuts"""
    with itunesiap.env.sandbox:
        itunesiap.verify(LEGACY_RAW_RECEIPT)
예제 #10
0
.. [#document] https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html#//apple_ref/doc/uid/TP40008267-CH104-SW1
"""

import json
import requests
import pytz
import datetime

from mock import patch

import pytest
import itunesiap

LEGACY_RAW_RECEIPT = '''ewoJInNpZ25hdHVyZSIgPSAiQW1vSjJDNFhra1hXcngwbDBwMUVCMkhqdndWRkJPN3NxaHRPYVpYWXNtd29PblU4dkNYNWZJWFV6SmpwWVpwVGJ1bTJhWW5kci9uOHlBc2czUXc0WUZHMUtCbEpLSjU2c1gzcEpmWTRZd2hEMmJsdm1lZVowZ0FXKzNiajBRWGVjUWJORTk5b2duK09janY2U3dFSEdpdkRIY0FRNzBiMTYxekdpbTk2WHVKTkFBQURWekNDQTFNd2dnSTdvQU1DQVFJQ0NHVVVrVTNaV0FTMU1BMEdDU3FHU0liM0RRRUJCUVVBTUg4eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURXpNREVHQTFVRUF3d3FRWEJ3YkdVZ2FWUjFibVZ6SUZOMGIzSmxJRU5sY25ScFptbGpZWFJwYjI0Z1FYVjBhRzl5YVhSNU1CNFhEVEE1TURZeE5USXlNRFUxTmxvWERURTBNRFl4TkRJeU1EVTFObG93WkRFak1DRUdBMVVFQXd3YVVIVnlZMmhoYzJWU1pXTmxhWEIwUTJWeWRHbG1hV05oZEdVeEd6QVpCZ05WQkFzTUVrRndjR3hsSUdsVWRXNWxjeUJUZEc5eVpURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd2daOHdEUVlKS29aSWh2Y05BUUVCQlFBRGdZMEFNSUdKQW9HQkFNclJqRjJjdDRJclNkaVRDaGFJMGc4cHd2L2NtSHM4cC9Sd1YvcnQvOTFYS1ZoTmw0WElCaW1LalFRTmZnSHNEczZ5anUrK0RyS0pFN3VLc3BoTWRkS1lmRkU1ckdYc0FkQkVqQndSSXhleFRldngzSExFRkdBdDFtb0t4NTA5ZGh4dGlJZERnSnYyWWFWczQ5QjB1SnZOZHk2U01xTk5MSHNETHpEUzlvWkhBZ01CQUFHamNqQndNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVOaDNvNHAyQzBnRVl0VEpyRHRkREM1RllRem93RGdZRFZSMFBBUUgvQkFRREFnZUFNQjBHQTFVZERnUVdCQlNwZzRQeUdVakZQaEpYQ0JUTXphTittVjhrOVRBUUJnb3Foa2lHOTJOa0JnVUJCQUlGQURBTkJna3Foa2lHOXcwQkFRVUZBQU9DQVFFQUVhU2JQanRtTjRDL0lCM1FFcEszMlJ4YWNDRFhkVlhBZVZSZVM1RmFaeGMrdDg4cFFQOTNCaUF4dmRXLzNlVFNNR1k1RmJlQVlMM2V0cVA1Z204d3JGb2pYMGlreVZSU3RRKy9BUTBLRWp0cUIwN2tMczlRVWU4Y3pSOFVHZmRNMUV1bVYvVWd2RGQ0TndOWXhMUU1nNFdUUWZna1FRVnk4R1had1ZIZ2JFL1VDNlk3MDUzcEdYQms1MU5QTTN3b3hoZDNnU1JMdlhqK2xvSHNTdGNURXFlOXBCRHBtRzUrc2s0dHcrR0szR01lRU41LytlMVFUOW5wL0tsMW5qK2FCdzdDMHhzeTBiRm5hQWQxY1NTNnhkb3J5L0NVdk02Z3RLc21uT09kcVRlc2JwMGJzOHNuNldxczBDOWRnY3hSSHVPTVoydG04bnBMVW03YXJnT1N6UT09IjsKCSJwdXJjaGFzZS1pbmZvIiA9ICJld29KSW05eWFXZHBibUZzTFhCMWNtTm9ZWE5sTFdSaGRHVXRjSE4wSWlBOUlDSXlNREV5TFRBNUxUSXdJREU0T2pNeE9qTTRJRUZ0WlhKcFkyRXZURzl6WDBGdVoyVnNaWE1pT3dvSkluVnVhWEYxWlMxcFpHVnVkR2xtYVdWeUlpQTlJQ0kwTW1NeFlqTmtORFUxTmpNNE1qQmtaRGxoTlRsak56bGhOelUyTkRFd01ERm1ZemcxWlRNNUlqc0tDU0p2Y21sbmFXNWhiQzEwY21GdWMyRmpkR2x2YmkxcFpDSWdQU0FpTVRBd01EQXdNREExTmpFMk1UYzJOQ0k3Q2draVluWnljeUlnUFNBaU1TNHdJanNLQ1NKMGNtRnVjMkZqZEdsdmJpMXBaQ0lnUFNBaU1UQXdNREF3TURBMU5qRTJNVGMyTkNJN0Nna2ljWFZoYm5ScGRIa2lJRDBnSWpFaU93b0pJbTl5YVdkcGJtRnNMWEIxY21Ob1lYTmxMV1JoZEdVdGJYTWlJRDBnSWpFek5EZ3hPVEV3T1RneE9USWlPd29KSW5CeWIyUjFZM1F0YVdRaUlEMGdJa0poZEhSc1pVZHZiR1ExTUNJN0Nna2lhWFJsYlMxcFpDSWdQU0FpTlRVME5EazVNekExSWpzS0NTSmlhV1FpSUQwZ0ltTnZiUzUyWVc1cGJHeGhZbkpsWlhwbExtbG5kVzVpWVhSMGJHVWlPd29KSW5CMWNtTm9ZWE5sTFdSaGRHVXRiWE1pSUQwZ0lqRXpORGd4T1RFd09UZ3hPVElpT3dvSkluQjFjbU5vWVhObExXUmhkR1VpSUQwZ0lqSXdNVEl0TURrdE1qRWdNREU2TXpFNk16Z2dSWFJqTDBkTlZDSTdDZ2tpY0hWeVkyaGhjMlV0WkdGMFpTMXdjM1FpSUQwZ0lqSXdNVEl0TURrdE1qQWdNVGc2TXpFNk16Z2dRVzFsY21sallTOU1iM05mUVc1blpXeGxjeUk3Q2draWIzSnBaMmx1WVd3dGNIVnlZMmhoYzJVdFpHRjBaU0lnUFNBaU1qQXhNaTB3T1MweU1TQXdNVG96TVRvek9DQkZkR012UjAxVUlqc0tmUT09IjsKCSJlbnZpcm9ubWVudCIgPSAiU2FuZGJveCI7CgkicG9kIiA9ICIxMDAiOwoJInNpZ25pbmctc3RhdHVzIiA9ICIwIjsKfQ=='''
with itunesiap.env.sandbox:
    LEGACY_RESPONSE = itunesiap.verify(LEGACY_RAW_RECEIPT)._
LEGACY_RESPONSE2 = {
    u'status': 0,
    u'receipt': {
        u'purchase_date_pst': u'2013-01-01 00:00:00 America/Los_Angeles',
        u'product_id': u'TestProduction1',
        u'original_transaction_id': u'1000000012345678',
        u'unique_identifier': u'bcbdb3d45543920dd9sd5c79a72948001fc22a39',
        u'original_purchase_date_pst': u'2013-01-01 00:00:00 America/Los_Angeles',
        u'original_purchase_date': u'2013-01-01 00:00:00 Etc/GMT',
        u'bvrs': u'1.0',
        u'original_purchase_date_ms': u'1348200000000',
        u'purchase_date': u'2013-01-01 00:00:00 Etc/GMT',
        u'item_id': u'500000000',
        u'purchase_date_ms': u'134820000000',
        u'bid': u'org.youknowone.itunesiap',
예제 #11
0
def test_shortcut():
    from testdata import sandbox_receipt
    verify(sandbox_receipt)
예제 #12
0
파일: models.py 프로젝트: aehlke/manabi
    def process_itunes_receipt(
        self, user, itunes_receipt, log_purchase=True,
    ):
        '''
        Subscribes if valid.

        If log_purchase is True, will log only if the receipt didn't already
        exist.

        Will raise InvalidReceipt error if invalid. Raises
        OutOfDateReceiptError if not the latest receipt on file.
        '''
        try:
            response = itunesiap.verify(
                itunes_receipt,
                password=settings.ITUNES_SHARED_SECRET,
                env=itunesiap.env.review)
            latest_receipt_info = response.latest_receipt_info[-1]
        except Exception as e:
            InAppPurchaseLogItem.objects.get_or_create(
                subscriber=user,
                itunes_receipt=itunes_receipt,
            )
            raise e from None

        original_transaction_id = (
            latest_receipt_info['original_transaction_id'])
        is_trial_period = (
            latest_receipt_info['is_trial_period'].lower() == 'true')
        purchase_date = _receipt_date_to_datetime(
            latest_receipt_info['purchase_date_ms'])

        # Confirm this incoming receipt isn't older than one on file.
        try:
            existing_subscription = Subscription.objects.get(
                original_transaction_id=original_transaction_id)

            existing_purchase_date = existing_subscription.purchase_date
            if (
                existing_purchase_date is not None
                and purchase_date > existing_purchase_date
            ):
                raise OutOfDateReceiptError()
        except Subscription.DoesNotExist:
            pass

        if log_purchase:
            InAppPurchaseLogItem.objects.get_or_create(
                subscriber=user,
                itunes_receipt=itunes_receipt,
                original_transaction_id=original_transaction_id,
            )

        self.model.objects.subscribe(
            user,
            original_transaction_id,
            _receipt_date_to_datetime(latest_receipt_info['expires_date_ms']),
            purchase_date,
            is_trial_period=is_trial_period,
        )

        logger.info('Processed iTunes receipt')
예제 #13
0
파일: models.py 프로젝트: aehlke/manabi
    def process_itunes_subscription_update_notification(self, notification):
        '''
        Will raise InvalidReceipt error if invalid.
        '''
        shared_secret = notification['password']
        if shared_secret != settings.ITUNES_SHARED_SECRET:
            raise PermissionDenied('Invalid iTunes shared secret.')

        try:
            receipt_info = notification['latest_receipt_info']
        except KeyError:
            receipt_info = notification['latest_expired_receipt_info']

        notification_type = notification['notification_type']

        SubscriptionUpdateNotificationLogItem.objects.create(
            production_environment=(notification['environment'] == 'PROD'),
            notification_type=notification_type,
            receipt_info=receipt_info,
            original_transaction_id=
                receipt_info['original_transaction_id'])

        if notification['environment'] == 'PROD':
            environment = itunesiap.env.production
        else:
            environment = itunesiap.env.sandbox

        if notification_type in [
            'RENEWAL', 'INTERACTIVE_RENEWAL',
        ]:
            receipt = notification['latest_receipt']
            itunesiap.verify(receipt, password=settings.ITUNES_SHARED_SECRET)

            original_transaction_id = receipt_info['original_transaction_id']

            subscription = Subscription.objects.get(
                original_transaction_id=original_transaction_id)
            subscription.active = True
        elif notification_type == 'CANCEL':
            receipt = itunes_receipt['latest_expired_receipt']

            itunesiap.verify(receipt, password=settings.ITUNES_SHARED_SECRET)

            original_transaction_id = receipt_info['original_transaction_id']

            subscription = Subscription.objects.get(
                original_transaction_id=original_transaction_id)
            subscription.active = False
        elif notification_type == 'DID_CHANGE_RENEWAL_PREF':
            # Customer changed the plan that takes affect at the next
            # subscription renewal. Current active plan is not affected.
            return
        elif notification_type == 'INITIAL_BUY':
            # Doesn't have an original_transaction_id yet so it's useless.
            # See https://forums.developer.apple.com/thread/98799
            return
        elif notification_type == 'DID_CHANGE_RENEWAL_STATUS':
            # Indicates a change in the subscription renewal status.
            return

        subscription.sandbox = environment == itunesiap.env.sandbox
        subscription.latest_itunes_receipt = receipt
        subscription.expires_date = _receipt_date_to_datetime(
            receipt_info['expires_date'])
        subscription.is_trial_period = (
            receipt_info['is_trial_period'].lower() == 'true')
        subscription.save()

        logger.info('Processed iTunes subscription update notification')
예제 #14
0
def test_shortcut(raw_receipt_legacy):
    """Test shortcuts"""
    itunesiap.verify(raw_receipt_legacy, env=itunesiap.env.sandbox)
예제 #15
0
def test_timeout():
    with pytest.raises(itunesiap.exceptions.ItunesServerNotReachable):
        itunesiap.verify('DummyReceipt', timeout=0.0001)
예제 #16
0
def test_shortcut():
    from testdata import sandbox_receipt
    verify(sandbox_receipt)
예제 #17
0
def iap_verify_receipt(self, verify_from, appid, amount, app_order_id,
                       good_name, pay_channel, userid, **kwargs):
    '''使用rawdata作为凭证请求苹果的服务器,获取支付回执信息'''
    args_string = '\t'.join([
        verify_from, appid, amount, app_order_id, good_name, pay_channel,
        userid
    ])  # for logging
    raw_data = kwargs.get('raw_data')

    raw_data_digest = hashlib.sha1(
        raw_data).hexdigest()  # 用于判断是否重复使用了一个支付凭证,如果重复直接拒绝
    iap_receipt_history, created = IAPReceiptHistory2.objects.get_or_create(
        iap_digest=raw_data_digest)

    # 本处理逻辑中涉及到的重要事件
    IAP_VERIFY_ERROR = settings.API_IMPORTANT_EVENTS.IAP_VERIFY_ERROR
    IAP_VERIFY_INFO = settings.API_IMPORTANT_EVENTS.IAP_VERIFY_INFO
    REUQEST_U8 = settings.API_IMPORTANT_EVENTS.REUQEST_U8
    raw_args = {
        'appid': appid,
        'amount': amount,
        'app_order_id': app_order_id,
        'good_name': good_name,
        'pay_channel': pay_channel,
        'userid': userid,
    }
    context = {}
    context['args_map'] = raw_args
    context['pay_channel'] = pay_channel

    if (not created) and (iap_receipt_history.state == 1):
        context['reason'] = 'duplicated receipt'
        _track(IAP_VERIFY_ERROR, context)
        return

    if verify_from != '1':
        context['reason'] = 'verify_from should be 1'
        _track(IAP_VERIFY_ERROR, context)
        return

    try:
        IS_SANDBOX = True
        response = None
        try:
            with itunesiap.env.review:
                response = itunesiap.verify(raw_data)
        except itunesiap.exceptions.InvalidReceipt as e:
            context['reason'] = 'exception when request iap endpoint %s' % str(
                e)
            _track(IAP_VERIFY_ERROR, context)

        if not response:
            context['reason'] = 'response from iap is none'
            _track(IAP_VERIFY_ERROR, context)
            return

        if response.status == 0:
            IS_SANDBOX = response['environment'].lower() == 'sandbox'
            NEED_NOTIFY = True

            try:
                app = App.objects.get(appid=appid)
            except App.DoesNotExist:
                context['reason'] = 'app not exists %s' % appid
                _track(IAP_VERIFY_ERROR, context)
                return

            ###### 校验包名
            try:
                response.receipt.in_app.sort(
                    key=lambda x: int(getattr(x, 'original_purchase_date_ms')))
                last_in_app = response.receipt.last_in_app
                ios_receipt_logger.info('{}\t{}\t{}\t{}'.format(
                    raw_data_digest, raw_data, args_string,
                    response))  # 记录支付凭证摘要何其原始值的对应关系到日志
                # 通过original_transaction_id防止重复发货
                try:
                    _original_transaction_id = getattr(
                        last_in_app, 'original_transaction_id')
                except:
                    _original_transaction_id = None
                original_transaction_ids = IAPReceiptHistory2.objects.filter(
                    original_transaction_id=_original_transaction_id)
                if original_transaction_ids.exists():
                    context['reason'] = 'duplicated original_transaction_id'
                    context[
                        'original_transaction_id'] = _original_transaction_id
                    _track(IAP_VERIFY_ERROR, context)
                    return
                # 通过original_transaction_id防止重复发货 END
            except IndexError:
                context['reason'] = 'no last_in_app found'
                _track(IAP_VERIFY_ERROR, context)
                return

            try:
                bundle_id = response.receipt['bundle_id']
            except:
                bundle_id = None

            if not bundle_id:
                try:
                    bundle_id = last_in_app.bid
                except AttributeError as _:
                    bundle_id = None

            if not bundle_id:
                context['reason'] = 'bundle_id is empty'
                _track(IAP_VERIFY_ERROR, context)
                return
            else:
                package_names = app.package_names
                try:
                    package_names_info = json.loads(package_names)
                except Exception as e:
                    context['reason'] = 'bundle_id not configured properly'
                    _track(IAP_VERIFY_ERROR, context)
                    return

                if bundle_id not in package_names_info:  # 首先,确保包名是合法的
                    context['reason'] = 'invalid bundle_id'
                    _track(IAP_VERIFY_ERROR, context)
                    return
                else:
                    # 包名(bundle_id)确定是合法的,就要再进一步从product_id(bundleid-currency-goodid-realmoney)中获取到,此支付订单的真实的订单价格
                    SEP = '_'
                    product_id = last_in_app.product_id
                    try:
                        _bundleid, _currency, _goodid, realmoney = product_id.split(
                            SEP)
                    except:
                        context[
                            'reason'] = 'cannot extract the 4 parts from product_id %s' % product_id
                        _track(IAP_VERIFY_ERROR, context)
                        return

                    if bundle_id != _bundleid:
                        context[
                            'info'] = 'bundle_id from iap mismatch bundle_id extracted from product_id %s %s' % (
                                bundle_id, _bundleid)
                        _track(IAP_VERIFY_INFO, context)
                    try:
                        realmoney = float(realmoney)  # 单位为元
                        real_amount = int(realmoney * 100)  # 元转换为分
                    except Exception as _:
                        context[
                            'reason'] = 'error when reading realmony from product_id'
                        _track(IAP_VERIFY_ERROR, context)
                        return
            ###### 校验包名 END
            ###### 校验包的审核状态,如果过审,则禁用沙箱支付
            package_online = package_names_info[bundle_id]['production'] == '1'
            if not IS_SANDBOX:
                order_status = 'S'
            else:
                if not package_online:
                    order_status = 'SS'
                else:
                    NEED_NOTIFY = False  # 如果已经上线,禁用沙箱支付
                    order_status = 'E'  # 同时将订单状态设置为异常
            ###### 校验包的审核状态,如果过审,则禁用沙箱支付 END

            try:
                user = User.objects.get(id=userid)
            except User.DoesNotExist:
                context['reason'] = 'user not exists'
                _track(IAP_VERIFY_ERROR, context)
                return

            if pay_channel != '99':  # 苹果iTunes支付
                context['reason'] = 'invalid pay_channel'
                _track(IAP_VERIFY_ERROR, context)
                return

            orders = UserGameOrder.objects.filter(game_order_id=app_order_id)
            if not orders.exists():  # 如果订单不存在,创建订单
                platform = 2  # 手游
                passthrough = kwargs.get('passthrough', '')
                game_callback_url = kwargs.get('game_callback_url', '')
                # 创建本地订单
                order = UserGameOrder.create_order(
                    user=user,
                    real_amount=real_amount,
                    currency=_currency,
                    app=app,
                    game_order_id=app_order_id,
                    amount=amount,
                    callback_url=game_callback_url,
                    good_name=good_name,
                    passthrough=passthrough,
                    platform=platform,
                    pay_channel=pay_channel)
                # 本地系统为本订单生成trade id
                order.trade_id = uuid.uuid4().get_hex()
            else:
                order = orders[0]
            order.order_status = order_status  # 根据上下文信息修改订单状态

            try:  # 保存订单
                order.save()

                # 防止应用内购买重复刷单状态更新
                def _getattr(name):
                    try:
                        return getattr(last_in_app, name)
                    except AttributeError:
                        return None

                attr_names = [
                    'quantity', 'product_id', 'transaction_id',
                    'purchase_date_ms', 'original_transaction_id',
                    'original_purchase_date_ms'
                ]
                attr_values = map(_getattr, attr_names)
                for item in zip(attr_names, attr_values):
                    setattr(iap_receipt_history, item[0], item[1])

                iap_receipt_history.bundle_id = bundle_id
                iap_receipt_history.trade_id = order.trade_id
                iap_receipt_history.is_sandbox = IS_SANDBOX
                iap_receipt_history.state = 0  # 当前处于未验证状态
                iap_receipt_history.save()
                # 防止应用内购买重复刷单状态更新 END
            except Exception as save_exc:
                context['info'] = 'failed to create local order'
                _track(IAP_VERIFY_INFO, context)
                # 虽然本地订单保存不成功,但是还是要通知U8服务器,故此处不返回

            if not NEED_NOTIFY:
                context[
                    'reason'] = 'sandbox receipt trying to buy in production envronment'
                _track(IAP_VERIFY_ERROR, context)
                return
            request_args = get_callback_arg_tuples(order,
                                                   others=[
                                                       ('ProductID',
                                                        product_id)
                                                   ])  # 获取回调参数,用于请求U8服务器
            request_query_str = '&'.join(
                ['='.join(item) for item in request_args])
            pay_callback_url = app.pay_callback_url
            context['pay_callback_url'] = pay_callback_url  # 日志记录
            parsed_u8_callback_url = urlparse.urlparse(pay_callback_url)
            new_u8_parsed_callback_url = urlparse.ParseResult(
                scheme=parsed_u8_callback_url.scheme,
                netloc=parsed_u8_callback_url.netloc,
                path=parsed_u8_callback_url.path,
                params=parsed_u8_callback_url.params,
                query=request_query_str,
                fragment=parsed_u8_callback_url.fragment)
            new_u8_callback_url = urlparse.urlunparse(
                new_u8_parsed_callback_url)
            callback_sign = get_signature(app.appsecret.encode('utf-8'),
                                          new_u8_callback_url)
            request_args.append(('Sign', callback_sign))
            args_map = dict(request_args)
            request_obj = urllib2.Request(pay_callback_url)  # 创建请求对象
            request_obj.add_data(urllib.urlencode(args_map))  # 添加请求参数

            response = urllib2.urlopen(
                request_obj, timeout=settings.PAY_CALLBACK_TIMEOUT).read()
            response_map = json.loads(response)
            context['response_map'] = response_map  # 日志记录
            if response_map['status'] == 'success':
                _track(REUQEST_U8, context)
                iap_receipt_history.state = 1  # 标记为验证成功
                iap_receipt_history.save()
                set_user_ispay_cache(app.appid, user.id, real_amount)  # 设置付费标记
                event_name = settings.API_IMPORTANT_EVENTS.PAY_SUCCESS
                _track(event_name, context)
            else:
                iap_receipt_history.state = 2  # 标记为验证失败
                iap_receipt_history.save()
                raise U8ResponseException(
                    response_map['description'])  # 向外层传播本异常,以引入重试机制
        else:
            context['reason'] = 'iap endpoint return none zero code'
            _track(IAP_VERIFY_ERROR, context)
    except Exception as ee:
        # 有异常的情况下,重试机制介入
        raise self.retry(
            exc=ee,
            max_retries=settings.CELERY_TASK_RETRY_POLICY_MAX_RETRIES,
            countdown=settings.CELERY_TASK_RETRY_POLICY[self.request.retries])
예제 #18
0
 def test_shortcut(self):
     mode = itunesiap.get_verification_mode()
     itunesiap.set_verification_mode('sandbox')
     itunesiap.verify(sandbox_receipt)
     itunesiap.set_verification_mode(mode)