2023-11-08 12:34:11 -05:00
|
|
|
import bitstring
|
|
|
|
|
|
|
|
# Reference for H10301 card format:
|
|
|
|
# https://www.hidglobal.com/sites/default/files/hid-understanding_card_data_formats-wp-en.pdf
|
|
|
|
|
|
|
|
|
|
|
|
class Credential:
|
2024-08-07 13:46:39 -04:00
|
|
|
def __init__(self, code=None, hex_code=None):
|
|
|
|
if code is None and hex_code is None:
|
2023-11-08 12:34:11 -05:00
|
|
|
raise TypeError("Must set either code or hex for a Credential")
|
2024-08-07 13:46:39 -04:00
|
|
|
elif code is not None and hex_code is not None:
|
2023-11-08 12:34:11 -05:00
|
|
|
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
|
2024-08-07 13:46:39 -04:00
|
|
|
elif hex_code is not None:
|
|
|
|
self.bits = bitstring.Bits(hex=hex_code)
|
2023-11-08 12:34:11 -05:00
|
|
|
|
|
|
|
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()
|