AppleInAppPurchaseSubscriptionObject.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. from Ansjer.config import LOGGER, CONFIG_INFO, CONFIG_TEST, BASE_DIR, IN_APP_CONFIG
  2. from appstoreserverlibrary.api_client import AppStoreServerAPIClient
  3. from appstoreserverlibrary.models.Environment import Environment
  4. from appstoreserverlibrary.receipt_utility import ReceiptUtility
  5. from appstoreserverlibrary.signed_data_verifier import SignedDataVerifier
  6. from Model.models import Order_Model, DeviceApplePackage
  7. ENV = Environment.SANDBOX if CONFIG_INFO == CONFIG_TEST else Environment.PRODUCTION
  8. class InAppConfig:
  9. def __init__(self, bundle_id: str):
  10. """
  11. 初始化 AppConfig,加载与指定 bundle_id 对应的配置。
  12. :param bundle_id: 应用的 bundle ID,用于检索相关配置。
  13. """
  14. config = IN_APP_CONFIG.get(bundle_id)
  15. if not config:
  16. raise ValueError(f"没有找到与 bundle_id '{bundle_id}' 对应的配置")
  17. self.key_id = config['key_id']
  18. self.issuer_id = config['issuer_id']
  19. self.key_filename = config['key_filename']
  20. self.cert_names = config['cert_names']
  21. self.app_apple_id = config.get("app_apple_id")
  22. self.environment = ENV
  23. class InAppPurchase:
  24. def __init__(self, bundle_id):
  25. """
  26. 初始化 InAppSubscription,加载私钥并初始化客户端和解码器。
  27. :param app_config: 包含内购相关配置的 AppConfig 实例。
  28. """
  29. app_config = InAppConfig(bundle_id)
  30. self.bundle_id = bundle_id
  31. self.config = app_config
  32. self.private_key = self._load_private_key(self.config.key_filename)
  33. self.client = self._initialize_client()
  34. self.verifier = self._initialize_verifier()
  35. self.receipt_util = self._initialize_receipt_util()
  36. def _load_private_key(self, key_filename: str) -> bytes:
  37. """
  38. 加载私钥文件并返回其内容。
  39. :param key_filename: 私钥文件的名称。
  40. :return: 返回私钥文件的内容,类型为 bytes。
  41. """
  42. key_path = f'{BASE_DIR}/Ansjer/file/in_app_purchase/{key_filename}'
  43. try:
  44. with open(key_path, 'rb') as file:
  45. return file.read()
  46. except FileNotFoundError:
  47. raise ValueError(f"Private key file not found: {key_path}")
  48. def _initialize_client(self) -> AppStoreServerAPIClient:
  49. """
  50. 初始化 AppStoreServerAPIClient 实例,用于与 App Store 进行通信。
  51. :return: 返回初始化后的 AppStoreServerAPIClient 实例。
  52. """
  53. return AppStoreServerAPIClient(
  54. self.private_key,
  55. self.config.key_id,
  56. self.config.issuer_id,
  57. self.bundle_id,
  58. self.config.environment
  59. )
  60. def _initialize_verifier(self) -> SignedDataVerifier:
  61. """
  62. 初始化 SignedDataVerifier 实例,用于内购验证签名数据。
  63. :return: 返回初始化后的 SignedDataVerifier 实例。
  64. """
  65. root_certificates = [
  66. self._load_certificate(cert_name)
  67. for cert_name in self.config.cert_names
  68. ]
  69. enable_online_checks = True # 根据需要设定在线检查是否启用
  70. app_apple_id = None if CONFIG_INFO == CONFIG_TEST else self.config.app_apple_id
  71. return SignedDataVerifier(
  72. root_certificates,
  73. enable_online_checks,
  74. self.config.environment,
  75. self.bundle_id,
  76. app_apple_id
  77. )
  78. def _load_certificate(self, cert_name: str) -> bytes:
  79. """
  80. 加载指定的根证书文件并返回其内容。
  81. :param cert_name: 根证书文件的名称。
  82. :return: 返回根证书文件的内容,类型为 bytes。
  83. """
  84. cert_path = f'{BASE_DIR}/Ansjer/file/in_app_purchase/{cert_name}'
  85. try:
  86. with open(cert_path, 'rb') as file:
  87. return file.read()
  88. except FileNotFoundError:
  89. raise ValueError(f"Certificate file not found: {cert_path}")
  90. def _initialize_receipt_util(self):
  91. receipt_util = ReceiptUtility()
  92. return receipt_util
  93. def check_subscriptions(self, uid: str, subscription_group_id: str) -> bool:
  94. try:
  95. has_order = self._get_last_order(uid)
  96. if not has_order:
  97. return False
  98. subscription_status = self._get_subscription_status(has_order, subscription_group_id)
  99. return subscription_status
  100. except Exception as e:
  101. LOGGER.error(f"Error checking subscriptions: {str(e)}")
  102. return False
  103. def _get_last_order(self, uid: str) -> dict:
  104. return Order_Model.objects.filter(UID=uid, payType=5).exclude(
  105. original_transaction_id=""
  106. ).values(
  107. 'transaction_id', 'original_transaction_id', 'orderID', 'addTime'
  108. ).order_by('-addTime').first()
  109. def _get_subscription_status(self, order: dict, subscription_group_id: str) -> bool:
  110. device_apple_package = DeviceApplePackage.objects.filter(
  111. original_transaction_id=order['original_transaction_id']
  112. ).values("subscription_status").first()
  113. if not device_apple_package or device_apple_package['subscription_status'] != 1:
  114. return False
  115. subscription_statuses = self.client.get_all_subscription_statuses(order['transaction_id'])
  116. if not subscription_statuses.data:
  117. return False
  118. for subscription_status in subscription_statuses.data:
  119. if str(subscription_status.subscriptionGroupIdentifier) == subscription_group_id:
  120. if any(str(item.status) == "Status.ACTIVE" for item in subscription_status.lastTransactions):
  121. return True
  122. return False