Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 2

build:
os: "ubuntu-20.04"
tools:
python: "3.11"
jobs:
pre_build:
- sphinx-apidoc -F -H "App Store Server Library" -A "Apple Inc." -V "0.1.0" -e -a -o _staging . tests setup.py

sphinx:
configuration: _staging/conf.py

python:
install:
- requirements: docs/requirements.txt
- requirements: requirements.txt
- method: pip
path: .
109 changes: 54 additions & 55 deletions appstoreserverlibrary/api_client.py

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions appstoreserverlibrary/promotional_offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ def create_signature(self, product_identifier: str, subscription_offer_id: str,

https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/generating_a_signature_for_promotional_offers

:param product_identifier The subscription product identifier
:param subscription_offer_id The subscription discount identifier
:param application_username An optional string value that you define; may be an empty string
:param nonce A one-time UUID value that your server generates. Generate a new nonce for every signature.
:param timestamp A timestamp your server generates in UNIX time format, in milliseconds. The timestamp keeps the offer active for 24 hours.
:return The Base64 encoded signature
:param product_identifier: The subscription product identifier
:param subscription_offer_id: The subscription discount identifier
:param application_username: An optional string value that you define; may be an empty string
:param nonce: A one-time UUID value that your server generates. Generate a new nonce for every signature.
:param timestamp: A timestamp your server generates in UNIX time format, in milliseconds. The timestamp keeps the offer active for 24 hours.
:return: The Base64 encoded signature
"""
payload = self._bundle_id + '\u2063' + \
self._key_id + '\u2063' + \
Expand Down
8 changes: 4 additions & 4 deletions appstoreserverlibrary/receipt_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def extract_transaction_id_from_app_receipt(self, app_receipt: str) -> Optional[
Extracts a transaction id from an encoded App Receipt. Throws if the receipt does not match the expected format.
*NO validation* is performed on the receipt, and any data returned should only be used to call the App Store Server API.

:param appReceipt The unmodified app receipt
:returns A transaction id from the array of in-app purchases, null if the receipt contains no in-app purchases
:param appReceipt: The unmodified app receipt
:return: A transaction id from the array of in-app purchases, null if the receipt contains no in-app purchases
"""
decoder = asn1.Decoder()
decoder.start(b64decode(app_receipt, validate=True))
Expand Down Expand Up @@ -82,8 +82,8 @@ def extract_transaction_id_from_transaction_receipt(self, transaction_receipt: s
"""
Extracts a transaction id from an encoded transactional receipt. Throws if the receipt does not match the expected format.
*NO validation* is performed on the receipt, and any data returned should only be used to call the App Store Server API.
:param transactionReceipt The unmodified transactionReceipt
:returns A transaction id, or null if no transactionId is found in the receipt
:param transactionReceipt: The unmodified transactionReceipt
:return: A transaction id, or null if no transactionId is found in the receipt
"""
decoded_top_level = base64.b64decode(transaction_receipt).decode('utf-8')
matching_result = re.search('"purchase-info"\s+=\s+"([a-zA-Z0-9+/=]+)";', decoded_top_level)
Expand Down
24 changes: 12 additions & 12 deletions appstoreserverlibrary/signed_data_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,19 @@ def verify_and_decode_renewal_info(self, signed_renewal_info: str) -> JWSRenewal
"""
Verifies and decodes a signedRenewalInfo obtained from the App Store Server API, an App Store Server Notification, or from a device

:param signed_renewal_info The signedRenewalInfo field
:return The decoded renewal info after verification
:throws VerificationException Thrown if the data could not be verified
:param signed_renewal_info: The signedRenewalInfo field
:return: The decoded renewal info after verification
:throws VerificationException: Thrown if the data could not be verified
"""
return cattrs.structure(self._decode_signed_object(signed_renewal_info), JWSRenewalInfoDecodedPayload)

def verify_and_decode_signed_transaction(self, signed_transaction: str) -> JWSTransactionDecodedPayload:
"""
Verifies and decodes a signedTransaction obtained from the App Store Server API, an App Store Server Notification, or from a device

:param signed_transaction The signedRenewalInfo field
:return The decoded transaction info after verification
:throws VerificationException Thrown if the data could not be verified
:param signed_transaction: The signedRenewalInfo field
:return: The decoded transaction info after verification
:throws VerificationException: Thrown if the data could not be verified
"""
decoded_transaction_info = cattrs.structure(self._decode_signed_object(signed_transaction), JWSTransactionDecodedPayload)
if decoded_transaction_info.bundleId != self._bundle_id:
Expand All @@ -72,9 +72,9 @@ def verify_and_decode_notification(self, signed_payload: str) -> ResponseBodyV2D
"""
Verifies and decodes an App Store Server Notification signedPayload

:param signedPayload The payload received by your server
:return The decoded payload after verification
:throws VerificationException Thrown if the data could not be verified
:param signedPayload: The payload received by your server
:return: The decoded payload after verification
:throws VerificationException: Thrown if the data could not be verified
"""
decoded_dict = self._decode_signed_object(signed_payload)
decoded_signed_notification = cattrs.structure(decoded_dict, ResponseBodyV2DecodedPayload)
Expand All @@ -99,9 +99,9 @@ def verify_and_decode_app_transaction(self, signed_app_transaction: str) -> AppT
"""
Verifies and decodes a signed AppTransaction

:param signed_app_transaction The signed AppTransaction
:return The decoded AppTransaction after validation
:throws VerificationException Thrown if the data could not be verified
:param signed_app_transaction: The signed AppTransaction
:return: The decoded AppTransaction after validation
:throws VerificationException: Thrown if the data could not be verified
"""
decoded_dict = self._decode_signed_object(signed_app_transaction)
decoded_app_transaction = cattrs.structure(decoded_dict, AppTransaction)
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sphinx == 7.0.1
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ requests >= 2.28.0, < 3
cryptography >= 40.0.0, < 42
pyOpenSSL >= 23.1.1, < 24
asn1==2.7.0
cattrs==23.1.2
cattrs==23.1.2