148 lines
3.6 KiB
Python
148 lines
3.6 KiB
Python
|
import nfc
|
||
|
from nfc.clf import RemoteTarget
|
||
|
import logging
|
||
|
from time import time
|
||
|
import os.path
|
||
|
import coloredlogs
|
||
|
coloredlogs.install()
|
||
|
from base64 import b16encode, b16decode
|
||
|
import sys
|
||
|
import ndef
|
||
|
import binascii
|
||
|
from badge import Badge
|
||
|
from os import system
|
||
|
|
||
|
CONFIG_PAGES = {
|
||
|
"NXP NTAG213": (0x29, 0x2A, 0x2B, 0x2C),
|
||
|
"NXP NTAG215": (0x83, 0x84, 0x85, 0x86),
|
||
|
"NXP NTAG216": (0xE3, 0xE4, 0xE5, 0xE6),
|
||
|
}
|
||
|
|
||
|
session_start = time()
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
|
||
|
log = logging.getLogger('nfc')
|
||
|
|
||
|
nfc_type = sys.argv[1]
|
||
|
balance = 0
|
||
|
if len(sys.argv) > 2:
|
||
|
balance = sys.argv[2]
|
||
|
elif nfc_type == 'coin':
|
||
|
log.error("You cannot create empty coins.")
|
||
|
exit()
|
||
|
|
||
|
clf = nfc.ContactlessFrontend()
|
||
|
|
||
|
log.info(f"Enrolling mode: {nfc_type}")
|
||
|
log.info(f"Initial balance: {balance}")
|
||
|
|
||
|
try:
|
||
|
assert clf.open('tty:USB0:pn532')
|
||
|
except TimeoutError:
|
||
|
log.error('Got TimeoutError on reader connection attempt.')
|
||
|
except AssertionError:
|
||
|
log.error('There is no reader connected.')
|
||
|
exit()
|
||
|
|
||
|
# Set baud rate to 115200 to prevent reader from dying
|
||
|
clf.device.chipset.set_serial_baudrate(115200)
|
||
|
clf.device.chipset.transport.baudrate = 115200
|
||
|
|
||
|
try:
|
||
|
while 1:
|
||
|
target = clf.sense(RemoteTarget('106A'), iterations=10)
|
||
|
if not target: continue
|
||
|
|
||
|
start = time()
|
||
|
|
||
|
tag = nfc.tag.activate(clf, target)
|
||
|
if not tag:
|
||
|
print("Tag was gone while writing.")
|
||
|
break
|
||
|
|
||
|
if tag.product not in ["NXP NTAG215"]:
|
||
|
raise Exception(f"This tag ({tag.product}) is not compatible with the barcard system.")
|
||
|
|
||
|
#print("\n".join(tag.dump()))
|
||
|
#break
|
||
|
|
||
|
badge = Badge(tag)
|
||
|
|
||
|
password = badge.password()
|
||
|
try:
|
||
|
has_password = tag.read(CONFIG_PAGES[tag.product][0])[3] < 0xFF
|
||
|
except:
|
||
|
break
|
||
|
|
||
|
if has_password:
|
||
|
log.warning("TAG has a password already! Trying to re-enroll anyway.")
|
||
|
tag.authenticate(password)
|
||
|
|
||
|
#tx = Transaction(tag_id=tag.identifier)
|
||
|
|
||
|
try:
|
||
|
# Disable the mirror, for now
|
||
|
page_addr = CONFIG_PAGES[tag.product][0]
|
||
|
page = tag.read(page_addr)[:4]
|
||
|
page[0] &= 0b111111 # Disable UID + COUNT mirror
|
||
|
tag.write(page_addr, page)
|
||
|
except:
|
||
|
break
|
||
|
|
||
|
# Activate it again
|
||
|
tag = nfc.tag.activate(clf, target)
|
||
|
if has_password:
|
||
|
tag.authenticate(password)
|
||
|
|
||
|
# Write the correct url depending on the type of wanted badge
|
||
|
if nfc_type == 'badge':
|
||
|
url = "https://go.foxo.me/fz23/bxxxxxxxxxxxxxxxxxxxxx"
|
||
|
else:
|
||
|
url = f"https://go.foxo.me/fz23/cxxxxxxxxxxxxxxxxxxxxx"
|
||
|
|
||
|
tag.format()
|
||
|
tag.ndef.records = [ndef.uri.UriRecord(url), ]
|
||
|
if tag.ndef.records[0].uri != url:
|
||
|
raise Exception("Written uri is different than expected.")
|
||
|
|
||
|
boundary = tag.read(0x08)
|
||
|
if not boundary.startswith(b"e/fz23/"):
|
||
|
raise Exception(f"This tag does not seem to correctly store ndef data. Got wrong {boundary}")
|
||
|
|
||
|
try:
|
||
|
page_addr = CONFIG_PAGES[tag.product][0]
|
||
|
page = tag.read(page_addr)[:4]
|
||
|
page[0] |= 0b11 << 6 # Enable UID + COUNT mirror
|
||
|
if tag.product == 'NXP NTAG215':
|
||
|
page[2] = 0x0A # Location of UID + COUNT
|
||
|
elif tag.product == 'NXP NTAG213':
|
||
|
page[2] = 0x0B
|
||
|
tag.write(page_addr, page)
|
||
|
log.info("UID + COUNT mirror enabled.")
|
||
|
except:
|
||
|
raise
|
||
|
break
|
||
|
|
||
|
print('EC')
|
||
|
badge.enable_count()
|
||
|
tag = nfc.tag.activate(clf, target)
|
||
|
if not has_password:
|
||
|
print('PRT')
|
||
|
badge.protect()
|
||
|
|
||
|
with open(f'log_{int(session_start)}.txt', 'a') as f:
|
||
|
f.write(f"{b16encode(tag.identifier).decode()},{nfc_type},{balance}\n")
|
||
|
|
||
|
system('mpv success.wav')
|
||
|
log.info(f"{time()-start:.2f} tag write done.")
|
||
|
while clf.sense(RemoteTarget('106A')): pass
|
||
|
|
||
|
system
|
||
|
|
||
|
except KeyboardInterrupt:
|
||
|
pass
|
||
|
|
||
|
clf.close()
|
||
|
|