From a57b6ef29c8773e3c923e8deb193e2202c496fc5 Mon Sep 17 00:00:00 2001 From: Anjan <743179+t-anjan@users.noreply.github.com> Date: Wed, 31 Jul 2024 08:41:43 +0530 Subject: [PATCH 1/3] Formatting and spelling fixes. Also, adding some better error handling and debugging print statements. --- pyaadhaar/decode.py | 147 +++++++++++++++++++++++++++----------------- pyaadhaar/utils.py | 4 +- 2 files changed, 91 insertions(+), 60 deletions(-) diff --git a/pyaadhaar/decode.py b/pyaadhaar/decode.py index 316f8da..696b83c 100644 --- a/pyaadhaar/decode.py +++ b/pyaadhaar/decode.py @@ -3,7 +3,6 @@ from PIL import Image, ImageFile ImageFile.LOAD_TRUNCATED_IMAGES = True import xml.etree.ElementTree as ET -from io import BytesIO import base64 import zipfile from typing import Union @@ -17,19 +16,26 @@ class AadhaarSecureQr: def __init__(self, base10encodedstring:str) -> None: self.base10encodedstring = base10encodedstring - self.details = ["version","email_mobile_status","referenceid", "name", "dob", "gender", "careof", "district", "landmark", + self.details = ["version", "email_mobile_status", "reference_id", "name", "dob", "gender", "careof", "district", "landmark", "house", "location", "pincode", "postoffice", "state", "street", "subdistrict", "vtc", "last_4_digits_mobile_no"] - self.delimeter = [-1] + self.delimiter = [-1] self.data = {} self._convert_base10encoded_to_decompressed_array() self._check_aadhaar_version() - self._create_delimeter() + self._create_delimiter() self._extract_info_from_decompressed_array() # Converts base10encoded string to a decompressed array def _convert_base10encoded_to_decompressed_array(self) -> None: bytes_array = self.base10encodedstring.to_bytes(5000, 'big').lstrip(b'\x00') - self.decompressed_array = zlib.decompress(bytes_array, 16+zlib.MAX_WBITS) + # print(f"Bytes array (trimmed leading zeros): {bytes_array[:100]}") # Debugging: print the first 100 bytes + try: + self.decompressed_array = zlib.decompress(bytes_array, 16 + zlib.MAX_WBITS) + # print(f"Decompressed array: {self.decompressed_array[:100]}") # Debugging: print the first 100 bytes of decompressed array + except Exception as e: + print(f"Decompression error: {e}") + return + # This function will check for the new 2022 version-2 Aadhaar QRs # If not found it will remove the "version" key from self.details, Defaulting to normal Secure QRs @@ -39,24 +45,40 @@ def _check_aadhaar_version(self) -> None: self.details.pop() # Removing "Last_4_digits_of_mobile_no" # Creates the delimeter which is used to extract the information from the decompressed array - def _create_delimeter(self) -> None: + def _create_delimiter(self) -> None: for i in range(len(self.decompressed_array)): if self.decompressed_array[i] == 255: - self.delimeter.append(i) + self.delimiter.append(i) + + print(f"Delimiters: {self.delimiter}") + # Extracts the information from the decompressed array def _extract_info_from_decompressed_array(self) -> None: for i in range(len(self.details)): - self.data[self.details[i]] = self.decompressed_array[self.delimeter[i] + 1:self.delimeter[i+1]].decode("ISO-8859-1") - self.data['aadhaar_last_4_digit'] = self.data['referenceid'][:4] - self.data['aadhaar_last_digit'] = self.data['referenceid'][3] + aadhaar_prop_name = self.details[i] + start_idx = self.delimiter[i] + 1 + end_idx = self.delimiter[i + 1] + self.data[aadhaar_prop_name] = self.decompressed_array[start_idx : end_idx].decode("ISO-8859-1") + + # print(f"Extracted data before verification: {self.data}") + + reference_id = self.data.get('reference_id', '') + if len(reference_id) >= 4: + self.data['aadhaar_last_4_digit'] = reference_id[:4] + self.data['aadhaar_last_digit'] = reference_id[3] + else: + print(f"Reference ID is too short: {reference_id}") + print(f"Extracted data: {self.data}") + # Default values to 'email' and 'mobile self.data['email'] = False self.data['mobile'] = False # Updating the fields of 'email' and 'mobile' - if int(self.data['email_mobile_status']) in {3, 1}: + email_mobile_status = int(self.data.get('email_mobile_status', -1)) + if email_mobile_status in {3, 1}: self.data['email'] = True - if int(self.data['email_mobile_status']) in {3, 2}: + if email_mobile_status in {3, 2}: self.data['mobile'] = True # Returns the extracted data in a dictionary format @@ -79,27 +101,44 @@ def isMobileNoRegistered(self) -> bool: def isEmailRegistered(self) -> bool: return self.data['email'] - # Return hash of the email id + # Return hash of the email id. + # Check the value of Email_mobile_present_bit_indicator_value: + # * If its 3 then first read mobile from index (Byte array length - 1 - 256) and + # then email from index (Byte array length - 1 - 256 - 32) in reverse order. Each value will be of fix size of 32 byte. + # + # * If Email_mobile_present_bit_indicator_value is 1 then only mobile is present. + # + # * If Email_mobile_present_bit_indicator_value is 2 then only email is present. + # + # * If Email_mobile_present_bit_indicator_value is 0 then no mobile or email present. + # + # Email and Mobile value will available in byte. Convert into Hexadecimal String def sha256hashOfEMail(self) -> str: tmp = "" - if int(self.data['email_mobile_status']) == 3: - tmp = self.decompressed_array[len(self.decompressed_array)-256-32-32:len(self.decompressed_array)-256-32].hex() - elif int(self.data['email_mobile_status']) == 1: - tmp = self.decompressed_array[len(self.decompressed_array)-256-32:len(self.decompressed_array)-256].hex() + email_mobile_status = int(self.data.get('email_mobile_status', -1)) + + if email_mobile_status == 3: + start_idx = len(self.decompressed_array)-256-32-32 + end_idx = len(self.decompressed_array)-256-32 + tmp = self.decompressed_array[start_idx : end_idx].hex() + elif email_mobile_status == 2: + start_idx = len(self.decompressed_array)-256-32 + end_idx = len(self.decompressed_array)-256 + tmp = self.decompressed_array[start_idx : end_idx].hex() + return tmp # Return hash of the mobile number def sha256hashOfMobileNumber(self) -> str: - return ( - self.decompressed_array[ - len(self.decompressed_array) - - 256 - - 32 : len(self.decompressed_array) - - 256 - ].hex() - if int(self.data['email_mobile_status']) in {3, 2} - else "" - ) + tmp = "" + email_mobile_status = int(self.data.get('email_mobile_status', -1)) + + if email_mobile_status in {3, 1}: + start_idx = len(self.decompressed_array)-256-32 + end_idx = len(self.decompressed_array)-256 + tmp = self.decompressed_array[start_idx : end_idx].hex() + + return tmp # Check availability of image in the QR CODE def isImage(self, buffer = 10) -> bool: @@ -107,7 +146,7 @@ def isImage(self, buffer = 10) -> bool: return ( len( self.decompressed_array[ - self.delimeter[len(self.details)] + 1 : + self.delimiter[len(self.details)] + 1 : ] ) >= 256 + 32 + 32 + buffer @@ -116,7 +155,7 @@ def isImage(self, buffer = 10) -> bool: return ( len( self.decompressed_array[ - self.delimeter[len(self.details)] + 1 : + self.delimiter[len(self.details)] + 1 : ] ) >= 256 + 32 + buffer @@ -125,41 +164,33 @@ def isImage(self, buffer = 10) -> bool: return ( len( self.decompressed_array[ - self.delimeter[len(self.details)] + 1 : + self.delimiter[len(self.details)] + 1 : ] ) >= 256 + buffer ) - + # Return image stream - def image(self) -> Union[Image.Image,None]: - if int(self.data['email_mobile_status']) == 3: - return Image.open( - BytesIO( - self.decompressed_array[ - self.delimeter[len(self.details)] + 1 : - ] - ) - ) - elif int(self.data['email_mobile_status']) in {2, 1}: - return Image.open( - BytesIO( - self.decompressed_array[ - self.delimeter[len(self.details)] + 1 : - ] - ) - ) - elif int(self.data['email_mobile_status']) == 0: - return Image.open( - BytesIO( - self.decompressed_array[ - self.delimeter[len(self.details)] + 1 : - ] - ) - ) + def image(self, format='img') -> Union[Image.Image,None]: + email_mobile_status = int(self.data.get('email_mobile_status', -1)) + image_byte_data = None + num_aadhaar_props = len(self.details) + start_idx = self.delimiter[num_aadhaar_props] + 1 + + if email_mobile_status == 3: + image_byte_data = self.decompressed_array[start_idx : ] + elif email_mobile_status in {2, 1}: + image_byte_data = self.decompressed_array[start_idx : ] + elif email_mobile_status == 0: + image_byte_data = self.decompressed_array[start_idx : ] else: return None + if 'bytedata' == format: + return image_byte_data + else: + return Image.open(BytesIO(image_byte_data)) + # Save the image of the user def saveimage(self, filepath:str) -> None: image = self.image() @@ -173,7 +204,7 @@ def verifyEmail(self, emailid:str) -> bool: generated_sha_mail = utils.SHAGenerator(emailid, self.data['aadhaar_last_digit']) return generated_sha_mail == self.sha256hashOfEMail() - # Verify the mobile no + # Verify the mobile no def verifyMobileNumber(self, mobileno:str) -> bool: if type(mobileno) != str: raise TypeError("Mobile number should be string") @@ -318,4 +349,4 @@ def verifyMobileNumber(self, mobileno:str) -> bool: if generated_sha_mobile == self.sha256hashOfMobileNumber(): return True else: - return False \ No newline at end of file + return False diff --git a/pyaadhaar/utils.py b/pyaadhaar/utils.py index afa1f85..676d38b 100644 --- a/pyaadhaar/utils.py +++ b/pyaadhaar/utils.py @@ -19,9 +19,9 @@ def SHAGenerator(string, n): tmp_sha = str(string) if int(n) == 0 or int(n) == 1: - return sha256(tmp_sha.encode()).hexdigest() + return sha256(tmp_sha.encode("ISO-8859-1")).hexdigest() for i in range(int(n)): - tmp_sha = sha256(tmp_sha.encode()).hexdigest() + tmp_sha = sha256(tmp_sha.encode("ISO-8859-1")).hexdigest() return tmp_sha From 06b42088949610272acd3c647aa20f0b2e3486d9 Mon Sep 17 00:00:00 2001 From: Anjan <743179+t-anjan@users.noreply.github.com> Date: Wed, 31 Jul 2024 09:07:45 +0530 Subject: [PATCH 2/3] Adding a function which can validate the signature present in the QR. From Secure QR documentation (User_manulal_QR_Code_15032019.pdf): Validate (signature value and signed data value) by using public key with algorithm SHA256withRSA. The default public key is "pyaadhaar/uidai_publickey.pem", which is extracted from the certificate present in the offline KYC XML (uidai_certificate_from_xml.cer). > openssl x509 -inform PEM -in uidai_certificate_from_xml.cer -pubkey -noout > uidai_publickey.pem --- pyaadhaar.egg-info/PKG-INFO | 11 +++++++ pyaadhaar.egg-info/requires.txt | 1 + pyaadhaar/decode.py | 32 ++++++++++++++++++++ pyaadhaar/uidai_certificate_from_xml.cer | 37 ++++++++++++++++++++++++ pyaadhaar/uidai_publickey.pem | 9 ++++++ setup.py | 3 +- 6 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 pyaadhaar/uidai_certificate_from_xml.cer create mode 100644 pyaadhaar/uidai_publickey.pem diff --git a/pyaadhaar.egg-info/PKG-INFO b/pyaadhaar.egg-info/PKG-INFO index f9020b5..46f4a12 100644 --- a/pyaadhaar.egg-info/PKG-INFO +++ b/pyaadhaar.egg-info/PKG-INFO @@ -15,6 +15,17 @@ Classifier: Programming Language :: Python :: 3.8 Requires-Python: >=3.6 Description-Content-Type: text/markdown License-File: LICENSE +Requires-Dist: numpy +Requires-Dist: opencv-python +Requires-Dist: Pillow +Requires-Dist: pylibjpeg +Requires-Dist: pylibjpeg-openjpeg +Requires-Dist: python-dateutil +Requires-Dist: pytz +Requires-Dist: pyzbar +Requires-Dist: six +Requires-Dist: toml +Requires-Dist: pycryptodome ## PyAadhaar Library diff --git a/pyaadhaar.egg-info/requires.txt b/pyaadhaar.egg-info/requires.txt index de2f5c4..964a383 100644 --- a/pyaadhaar.egg-info/requires.txt +++ b/pyaadhaar.egg-info/requires.txt @@ -8,3 +8,4 @@ pytz pyzbar six toml +pycryptodome diff --git a/pyaadhaar/decode.py b/pyaadhaar/decode.py index 696b83c..cefa37b 100644 --- a/pyaadhaar/decode.py +++ b/pyaadhaar/decode.py @@ -7,6 +7,10 @@ import zipfile from typing import Union from . import utils +from Crypto.Signature import pkcs1_15 +from Crypto.Hash import SHA256 +from Crypto.PublicKey import RSA +from Crypto.Util.number import long_to_bytes class AadhaarSecureQr: # This is the class for Aadhaar Secure Qr code.. In this version of code the data is in encrypted format @@ -93,6 +97,34 @@ def signature(self) -> bytes: def signedData(self) -> bytes: return self.decompressed_array[:len(self.decompressed_array)-256] + def verify_signature(self, cert_file_path: str = 'pyaadhaar/uidai_publickey.pem') -> bool: + """ + Verifies the signature of the Aadhaar Secure QR code. + From Secure QR documentation (User_manulal_QR_Code_15032019.pdf): + Validate (signature value and signed data value) by using public key with algorithm SHA256withRSA. + The default public key is "pyaadhaar/uidai_publickey.pem", which is extracted from the certificate + present in the offline KYC XML (uidai_certificate_from_xml.cer). + > openssl x509 -inform PEM -in uidai_certificate_from_xml.cer -pubkey -noout > uidai_publickey.pem + + Args: + cert_file_path (str, optional): The path to the certificate file. Defaults to 'pyaadhaar/uidai_publickey.pem'. + + Returns: + bool: True if the signature is valid, False otherwise. + """ + with open(cert_file_path, 'rb') as key_file: + public_key = RSA.import_key(key_file.read()) + + h = SHA256.new(self.signedData()) + verifier = pkcs1_15.new(public_key) + + try: + verifier.verify(h, self.signature()) + return True + except (ValueError, TypeError) as e: + print(f"Signature verification failed: {e}") + return False + # Check whether mobile no is registered or not def isMobileNoRegistered(self) -> bool: return self.data['mobile'] diff --git a/pyaadhaar/uidai_certificate_from_xml.cer b/pyaadhaar/uidai_certificate_from_xml.cer new file mode 100644 index 0000000..d85086f --- /dev/null +++ b/pyaadhaar/uidai_certificate_from_xml.cer @@ -0,0 +1,37 @@ +-----BEGIN CERTIFICATE----- +MIIHwjCCBqqgAwIBAgIEU5laMzANBgkqhkiG9w0BAQsFADCB/DELMAkGA1UEBhMCSU4xQTA/BgNV +BAoTOEd1amFyYXQgTmFybWFkYSBWYWxsZXkgRmVydGlsaXplcnMgYW5kIENoZW1pY2FscyBMaW1p +dGVkMR0wGwYDVQQLExRDZXJ0aWZ5aW5nIEF1dGhvcml0eTEPMA0GA1UEERMGMzgwMDU0MRAwDgYD +VQQIEwdHdWphcmF0MSYwJAYDVQQJEx1Cb2Rha2RldiwgUyBHIFJvYWQsIEFobWVkYWJhZDEcMBoG +A1UEMxMTMzAxLCBHTkZDIEluZm90b3dlcjEiMCAGA1UEAxMZKG4pQ29kZSBTb2x1dGlvbnMgQ0Eg +MjAxNDAeFw0yMTAyMjYxMTU0MjRaFw0yNDAyMjcwMDI3MTFaMIHdMQswCQYDVQQGEwJJTjExMC8G +A1UEChMoVU5JUVVFIElERU5USUZJQ0FUSU9OIEFVVEhPUklUWSBPRiBJTkRJQTEPMA0GA1UEERMG +MTEwMDAxMQ4wDAYDVQQIEwVEZWxoaTEbMBkGA1UECRMSQkVISU5EIEtBTEkgTUFORElSMSQwIgYD +VQQzExtBQURIQVIgSFEgQkFOR0xBIFNBSElCIFJPQUQxNzA1BgNVBAMTLkRTIFVOSVFVRSBJREVO +VElGSUNBVElPTiBBVVRIT1JJVFkgT0YgSU5ESUEgMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCiciwOXy3lunB+2T8DbsKx8LlVkyOQ+swPC8vyDIChXAiLSIaGa3LrJasL9Vov4Gtp +7b1cyDt0x3CdshQebAfGi834WdPa9/P87SQdByBV3BVIhHS0XCyYL6lUqlKqb/+ySBhhxlCF2Etk +FY6fQ9nzXKabSM6TAFIhAqTK4JO//UdLCNMtHQQG9of35VvSJqI4S/WKQcOEw5dPHHxRFYGckm3j +rfPsu5kExIbx9dUwOXe+pjWENnMptcFor9yVEhcx9/SNQ6988x9pseO755Sdx6ixDAvd66ur3r6g +dqHPgWat8GqKQd7fFDv/g129K9W7C2HSRywjSm1EEbybU2CVAgMBAAGjggNnMIIDYzAOBgNVHQ8B +Af8EBAMCBsAwKgYDVR0lBCMwIQYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCSqGSIb3LwEBBTCCAQIG +A1UdIASB+jCB9zCBhgYGYIJkZAICMHwwegYIKwYBBQUHAgIwbgxsQ2xhc3MgMiBjZXJ0aWZpY2F0 +ZXMgYXJlIHVzZWQgZm9yIGZvcm0gc2lnbmluZywgZm9ybSBhdXRoZW50aWNhdGlvbiBhbmQgc2ln +bmluZyBvdGhlciBsb3cgcmlzayB0cmFuc2FjdGlvbnMuMGwGBmCCZGQKATBiMGAGCCsGAQUFBwIC +MFQMUlRoaXMgY2VydGlmaWNhdGUgcHJvdmlkZXMgaGlnaGVyIGxldmVsIG9mIGFzc3VyYW5jZSBm +b3IgZG9jdW1lbnQgc2lnbmluZyBmdW5jdGlvbi4wDAYDVR0TAQH/BAIwADAjBgNVHREEHDAagRhy +YWh1bC5rdW1hckB1aWRhaS5uZXQuaW4wggFuBgNVHR8EggFlMIIBYTCCAR6gggEaoIIBFqSCARIw +ggEOMQswCQYDVQQGEwJJTjFBMD8GA1UEChM4R3VqYXJhdCBOYXJtYWRhIFZhbGxleSBGZXJ0aWxp +emVycyBhbmQgQ2hlbWljYWxzIExpbWl0ZWQxHTAbBgNVBAsTFENlcnRpZnlpbmcgQXV0aG9yaXR5 +MQ8wDQYDVQQREwYzODAwNTQxEDAOBgNVBAgTB0d1amFyYXQxJjAkBgNVBAkTHUJvZGFrZGV2LCBT +IEcgUm9hZCwgQWhtZWRhYmFkMRwwGgYDVQQzExMzMDEsIEdORkMgSW5mb3Rvd2VyMSIwIAYDVQQD +ExkobilDb2RlIFNvbHV0aW9ucyBDQSAyMDE0MRAwDgYDVQQDEwdDUkw1Njk0MD2gO6A5hjdodHRw +czovL3d3dy5uY29kZXNvbHV0aW9ucy5jb20vcmVwb3NpdG9yeS9uY29kZWNhMTQuY3JsMCsGA1Ud +EAQkMCKADzIwMjEwMjI2MTE1NDI0WoEPMjAyNDAyMjcwMDI3MTFaMBMGA1UdIwQMMAqACE0HvvGe +nfu9MB0GA1UdDgQWBBTpS5Cfqf2zdwqjupLAqMwk/bqX9DAZBgkqhkiG9n0HQQAEDDAKGwRWOC4x +AwIDKDANBgkqhkiG9w0BAQsFAAOCAQEAbTlOC4sonzb44+u5+VZ3wGz3OFg0uJGsufbBu5efh7kO +2DlYnx7okdEfayQQs6AUzDvsH1yBSBjsaZo3fwBgQUIMaNKdKSrRI0eOTDqilizldHqj113f4eUz +U2j4okcNSF7TxQWMjxwyM86QsQ6vxZK7arhBhVjwp443+pxfSIdFUu428K6yH4JBGhZSzWuqD6GN +hOhDzS+sS23MkwHFq0GX4erhVfN/W7XLeSjzF4zmjg+O77vTySCNe2VRYDrfFS8EAOcO4q7szc7+ +6xdg8RlgzoZHoRG/GqUp9inpJUn7OIzhHi2e8MllaMdtXo0nbr150tMe8ZSvY2fMiTCY1w== +-----END CERTIFICATE----- diff --git a/pyaadhaar/uidai_publickey.pem b/pyaadhaar/uidai_publickey.pem new file mode 100644 index 0000000..565e9e8 --- /dev/null +++ b/pyaadhaar/uidai_publickey.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAonIsDl8t5bpwftk/A27C +sfC5VZMjkPrMDwvL8gyAoVwIi0iGhmty6yWrC/VaL+Brae29XMg7dMdwnbIUHmwH +xovN+FnT2vfz/O0kHQcgVdwVSIR0tFwsmC+pVKpSqm//skgYYcZQhdhLZBWOn0PZ +81ymm0jOkwBSIQKkyuCTv/1HSwjTLR0EBvaH9+Vb0iaiOEv1ikHDhMOXTxx8URWB +nJJt463z7LuZBMSG8fXVMDl3vqY1hDZzKbXBaK/clRIXMff0jUOvfPMfabHju+eU +nceosQwL3eurq96+oHahz4FmrfBqikHe3xQ7/4NdvSvVuwth0kcsI0ptRBG8m1Ng +lQIDAQAB +-----END PUBLIC KEY----- diff --git a/setup.py b/setup.py index 53722cb..d555cb3 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,8 @@ 'pytz', 'pyzbar', 'six', - 'toml' + 'toml', + 'pycryptodome' ], ) From 5f4adde5084012528b5aba33f9165abe5b54e859 Mon Sep 17 00:00:00 2001 From: Anjan <743179+t-anjan@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:59:52 +0530 Subject: [PATCH 3/3] Fixing the logic of checking the 3, 2, 1 values of the email_mobile_status field. 3 and 2 have email. 3 and 1 have mobile. Also, using the isEmailRegistered() and isMobileNoRegistered() functions, instead of checking the email_mobile_status field everywhere. --- pyaadhaar/decode.py | 60 +++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/pyaadhaar/decode.py b/pyaadhaar/decode.py index cefa37b..df227da 100644 --- a/pyaadhaar/decode.py +++ b/pyaadhaar/decode.py @@ -80,9 +80,9 @@ def _extract_info_from_decompressed_array(self) -> None: self.data['mobile'] = False # Updating the fields of 'email' and 'mobile' email_mobile_status = int(self.data.get('email_mobile_status', -1)) - if email_mobile_status in {3, 1}: - self.data['email'] = True if email_mobile_status in {3, 2}: + self.data['email'] = True + if email_mobile_status in {3, 1}: self.data['mobile'] = True # Returns the extracted data in a dictionary format @@ -97,7 +97,7 @@ def signature(self) -> bytes: def signedData(self) -> bytes: return self.decompressed_array[:len(self.decompressed_array)-256] - def verify_signature(self, cert_file_path: str = 'pyaadhaar/uidai_publickey.pem') -> bool: + def verify_signature(self, cert_file_path:str = 'pyaadhaar/uidai_publickey.pem') -> bool: """ Verifies the signature of the Aadhaar Secure QR code. From Secure QR documentation (User_manulal_QR_Code_15032019.pdf): @@ -147,13 +147,12 @@ def isEmailRegistered(self) -> bool: # Email and Mobile value will available in byte. Convert into Hexadecimal String def sha256hashOfEMail(self) -> str: tmp = "" - email_mobile_status = int(self.data.get('email_mobile_status', -1)) - if email_mobile_status == 3: + if self.isEmailRegistered() and self.isMobileNoRegistered(): start_idx = len(self.decompressed_array)-256-32-32 end_idx = len(self.decompressed_array)-256-32 tmp = self.decompressed_array[start_idx : end_idx].hex() - elif email_mobile_status == 2: + elif self.isEmailRegistered() and not self.isMobileNoRegistered(): start_idx = len(self.decompressed_array)-256-32 end_idx = len(self.decompressed_array)-256 tmp = self.decompressed_array[start_idx : end_idx].hex() @@ -163,9 +162,8 @@ def sha256hashOfEMail(self) -> str: # Return hash of the mobile number def sha256hashOfMobileNumber(self) -> str: tmp = "" - email_mobile_status = int(self.data.get('email_mobile_status', -1)) - if email_mobile_status in {3, 1}: + if self.isMobileNoRegistered(): start_idx = len(self.decompressed_array)-256-32 end_idx = len(self.decompressed_array)-256 tmp = self.decompressed_array[start_idx : end_idx].hex() @@ -174,46 +172,28 @@ def sha256hashOfMobileNumber(self) -> str: # Check availability of image in the QR CODE def isImage(self, buffer = 10) -> bool: - if int(self.data['email_mobile_status']) == 3: - return ( - len( - self.decompressed_array[ - self.delimiter[len(self.details)] + 1 : - ] - ) - >= 256 + 32 + 32 + buffer - ) - elif int(self.data['email_mobile_status']) in {2, 1}: - return ( - len( - self.decompressed_array[ - self.delimiter[len(self.details)] + 1 : - ] - ) - >= 256 + 32 + buffer - ) - elif int(self.data['email_mobile_status']) == 0: - return ( - len( - self.decompressed_array[ - self.delimiter[len(self.details)] + 1 : - ] - ) - >= 256 + buffer - ) + num_aadhaar_props = len(self.details) + start_idx = self.delimiter[num_aadhaar_props] + 1 + len_image_bytes = len(self.decompressed_array[start_idx :]) + + if self.isEmailRegistered() and self.isMobileNoRegistered(): + return (len_image_bytes >= (256 + 32 + 32 + buffer)) + elif self.isEmailRegistered() or self.isMobileNoRegistered(): + return (len_image_bytes >= (256 + 32 + buffer)) + elif not self.isEmailRegistered() and not self.isMobileNoRegistered(): + return (len_image_bytes >= (256 + buffer)) # Return image stream - def image(self, format='img') -> Union[Image.Image,None]: - email_mobile_status = int(self.data.get('email_mobile_status', -1)) + def image(self, format:str = 'img') -> Union[Image.Image,None]: image_byte_data = None num_aadhaar_props = len(self.details) start_idx = self.delimiter[num_aadhaar_props] + 1 - if email_mobile_status == 3: + if self.isEmailRegistered() and self.isMobileNoRegistered(): image_byte_data = self.decompressed_array[start_idx : ] - elif email_mobile_status in {2, 1}: + elif self.isEmailRegistered() or self.isMobileNoRegistered(): image_byte_data = self.decompressed_array[start_idx : ] - elif email_mobile_status == 0: + elif not self.isEmailRegistered() and not self.isMobileNoRegistered(): image_byte_data = self.decompressed_array[start_idx : ] else: return None