forked from CMS/memberPlumbing
39 lines
1.3 KiB
Python
39 lines
1.3 KiB
Python
|
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()
|