import bitstring # Reference for H10301 card format: # https://www.hidglobal.com/sites/default/files/hid-understanding_card_data_formats-wp-en.pdf class Credential: def __init__(self, code=None, hex=None): if code is None and hex is None: raise TypeError("Must set either code or hex for a Credential") elif code is not None and hex is not None: raise TypeError("Cannot set both code and hex for a Credential") elif code is not None: self.bits = bitstring.pack( "0b000000, 0b0, uint:8=facility, uint:16=number, 0b0", facility=code[0], number=code[1], ) self.bits[6] = self.bits[7:19].count(1) % 2 # even parity self.bits[31] = not (self.bits[19:31].count(1) % 2) # odd parity elif hex is not None: self.bits = bitstring.Bits(hex=hex) def __repr__(self): return f"Credential({self.code})" def __eq__(self, other): return self.bits == other.bits def __hash__(self): return self.bits.int @property def code(self): facility = self.bits[7:15].uint code = self.bits[15:31].uint return (facility, code) @property def hex(self): return self.bits.hex.upper()