/mrz/checker/td1.py

https://github.com/Arg0s1080/mrz · Python · 140 lines · 103 code · 15 blank · 22 comment · 3 complexity · b640c407e7c02f2cf35828585ce89614 MD5 · raw file

  1. #!/usr/bin/python3
  2. # -*- coding: UTF-8 -*-
  3. # GNU General Public License v3.0
  4. #
  5. # Permissions of this strong copyleft license are conditioned on making available
  6. # complete source code of licensed works and modifications, which include larger works
  7. # using a licensed work, under the same license. Copyright and license notices must be
  8. # preserved. Contributors provide an express grant of patent rights.
  9. #
  10. # For more information on this, and how to apply and follow the GNU GPL, see:
  11. # http://www.gnu.org/licenses
  12. #
  13. # (ɔ) Iván Rincón 2019
  14. from ..base.countries_ops import *
  15. from ..base.functions import hash_is_ok, namedtuple_maker, anset
  16. from ._hash_fields import _HashChecker
  17. from ._fields import _FieldsChecker
  18. import mrz.base.string_checkers as check
  19. __all__ = ["TD1CodeChecker", "code_list", "countries_list", "countries_code_list", "code_country_list",
  20. "is_country", "is_code", "get_code", "get_country", "find_country"]
  21. class _TD1HashChecker(_HashChecker):
  22. def __init__(self, document_number: str, document_number_hash: str, birth_date: str, birth_date_hash: str,
  23. expiry_date: str, expiry_date_hash: str, optional_data: str, optional_data_2: str,
  24. final_hash: str):
  25. self._optional_data = optional_data
  26. self._optional_data_2 = optional_data_2
  27. self._final_hash = final_hash
  28. _HashChecker.__init__(self, document_number, document_number_hash, birth_date, birth_date_hash,
  29. expiry_date, expiry_date_hash)
  30. @property
  31. def final_hash(self) -> bool:
  32. """Return True if final hash is True, False otherwise"""
  33. ok = hash_is_ok(self._document_number +
  34. self._document_number_hash +
  35. self._optional_data +
  36. self._birth_date +
  37. self._birth_date_hash +
  38. self._expiry_date +
  39. self._expiry_date_hash +
  40. self._optional_data_2, self._final_hash)
  41. return self.report.add("final hash", ok)
  42. def _all_hashes(self) -> bool:
  43. return (self.final_hash &
  44. self.document_number_hash &
  45. self.birth_date_hash &
  46. self.expiry_date_hash)
  47. def __repr__(self) -> str:
  48. return str(self._all_hashes())
  49. class TD1CodeChecker(_TD1HashChecker, _FieldsChecker):
  50. """
  51. Check the string code of the machine readable zone for official travel documents of size 1
  52. __bool__() returns True if all fields are validated, False otherwise
  53. Params:
  54. mrz_string (str): MRZ string of TD1's. Must be 90 uppercase characters long
  55. check_expiry (bool): If it's set to True, it is verified and reported as warning that the
  56. document is not expired and that expiry_date is not greater than 10 years
  57. compute_warnings (bool): If it's set True, warnings compute as False
  58. """
  59. def __init__(self, mrz_code: str, check_expiry=False, compute_warnings=False, precheck=True):
  60. precheck and check.precheck("TD1", mrz_code, 92)
  61. lines = mrz_code.splitlines()
  62. self._document_type = lines[0][0: 2]
  63. self._country = lines[0][2: 5]
  64. self._identifier = lines[2]
  65. self._document_number = lines[0][5: 14]
  66. self._document_number_hash = lines[0][14]
  67. self._nationality = lines[1][15: 18]
  68. self._birth_date = lines[1][0: 6]
  69. self._birth_date_hash = lines[1][6]
  70. self._sex = lines[1][7]
  71. self._expiry_date = lines[1][8: 14]
  72. self._expiry_date_hash = lines[1][14]
  73. self._optional_data = lines[0][15: 30]
  74. self._optional_data_2 = lines[1][18: 29]
  75. self._final_hash = lines[1][29]
  76. _TD1HashChecker.__init__(self,
  77. self._document_number,
  78. self._document_number_hash,
  79. self._birth_date,
  80. self._birth_date_hash,
  81. self._expiry_date,
  82. self._expiry_date_hash,
  83. self._optional_data,
  84. self._optional_data_2,
  85. self._final_hash)
  86. _FieldsChecker.__init__(self,
  87. self._document_type,
  88. self._country,
  89. self._identifier,
  90. self._document_number,
  91. self._nationality,
  92. self._birth_date,
  93. self._sex,
  94. self._expiry_date,
  95. self._optional_data,
  96. self._optional_data_2,
  97. check_expiry,
  98. compute_warnings,
  99. mrz_code)
  100. self.result = self._all_hashes() & self._all_fields()
  101. def fields(self, zeroes_fill=False):
  102. """Returns a namedtuple with all fields strings
  103. Available strings for ID Cards and others TD1's:
  104. surname, name, country, nationality, birth_date, expiry_date, sex, document_type,
  105. document_number, optional_data, birth_date_hash, expiry_date_hash, document_number_hash,
  106. optional_data_2 and final_hash
  107. Params:
  108. zero_fill (bool): Replace '<' char by '0' in alphanum fields (document_number,
  109. optional_data and optional_data_2)
  110. """
  111. extra_fields = anset(self._optional_data_2, zeroes_fill), self._final_hash
  112. extra_names = "optional_data_2 final_hash"
  113. return namedtuple_maker(self._str_common_fields(zeroes_fill), self._str_common_hashes(),
  114. extra_fields, extra_names)
  115. def __repr__(self):
  116. return str(self.result)
  117. def __bool__(self):
  118. return self.result