@@ -20,7 +20,7 @@ def extract_transaction_id_from_app_receipt(self, app_receipt: str) -> Optional[
2020 :param appReceipt: The unmodified app receipt
2121 :return: A transaction id from the array of in-app purchases, null if the receipt contains no in-app purchases
2222 """
23- decoder = asn1 . Decoder ()
23+ decoder = IndefiniteFormAwareDecoder ()
2424 decoder .start (b64decode (app_receipt , validate = True ))
2525 tag = decoder .peek ()
2626 if tag .typ != asn1 .Types .Constructed or tag .nr != asn1 .Numbers .Sequence :
@@ -39,6 +39,11 @@ def extract_transaction_id_from_app_receipt(self, app_receipt: str) -> Optional[
3939 decoder .read ()
4040 decoder .enter ()
4141 tag , value = decoder .read ()
42+ # Xcode uses nested OctetStrings, we extract the inner string in this case
43+ if tag .typ == asn1 .Types .Constructed and tag .nr == asn1 .Numbers .OctetString :
44+ inner_decoder = asn1 .Decoder ()
45+ inner_decoder .start (value )
46+ tag , value = inner_decoder .read ()
4247 if tag .typ != asn1 .Types .Primitive or tag .nr != asn1 .Numbers .OctetString :
4348 raise ValueError ()
4449 decoder = asn1 .Decoder ()
@@ -92,4 +97,20 @@ def extract_transaction_id_from_transaction_receipt(self, transaction_receipt: s
9297 inner_matching_result = re .search ('"transaction-id"\s+=\s+"([a-zA-Z0-9+/=]+)";' , decoded_inner_level )
9398 if inner_matching_result :
9499 return inner_matching_result .group (1 )
95- return None
100+ return None
101+
102+ class IndefiniteFormAwareDecoder (asn1 .Decoder ):
103+ def _read_length (self ) -> int :
104+ index , input_data = self .m_stack [- 1 ]
105+ try :
106+ byte = input_data [index ]
107+ except IndexError :
108+ raise asn1 .Error ('Premature end of input.' )
109+ if byte == 0x80 :
110+ # Xcode receipts use indefinite length encoding, not supported by all parsers
111+ # Indefinite length encoding is only entered, but never left during parsing for receipts
112+ # We therefore round up indefinite length encoding to be the remaining length
113+ self ._read_byte ()
114+ index , input_data = self .m_stack [- 1 ]
115+ return len (input_data ) - index
116+ return super ()._read_length ()
0 commit comments