#!/usr/bin/env python3 """ mchip.cc Tag Writer fuer USB-NFC-Reader (ACR122U etc.) via nfcpy. Flow: Tag auflegen -> UID lesen -> GET /api/chip?uid=... -> NDEF-URL schreiben Setup (Windows): pip install nfcpy requests ACR122U: libusb-Treiber via Zadig installieren (einmalig) Usage: python write_chip.py --user USERNAME --key API_KEY [--base https://mchip.cc] Der API-Key wird auf /chips fuer 1 Stunde freigeschaltet ("Enable API"). """ import argparse import requests import nfc import nfc.ndef def main(): ap = argparse.ArgumentParser() ap.add_argument('--user', required=True, help='mchip.cc username') ap.add_argument('--key', required=True, help='Writer API key (enabled on /chips)') ap.add_argument('--mchip', default=None, help='M-Chip id/slug to activate the chip for') ap.add_argument('--base', default='https://mtag.cc') ap.add_argument('--url-mode', choices=['token', 'virtual', 'uid'], default='token', help='token=write random public_id hash (default), virtual=mint UID-free token per tag, uid=write raw hardware UID') ap.add_argument('--lock', action='store_true', help='Set permanent read-only lock bit after writing (IRREVERSIBLE!)') args = ap.parse_args() base, key, user = args.base.rstrip('/'), args.key, args.user extra = {'mchip': args.mchip} if args.mchip else {} extra['url_mode'] = 'uid' if args.url_mode == 'uid' else 'token' mode_info = 'WITH permanent Lock-Bit (--lock)' if args.lock else 'without Lock-Bit (re-writable)' print(f'Hold a tag to the reader (url-mode={args.url_mode}, {mode_info}; Ctrl+C to quit).') with nfc.ContactlessFrontend('usb') as clf: while True: tag = clf.connect(rdwr={'on-connect': lambda t: False, 'beep-on-connect': False}) if tag is None: continue uid = 'virtual' if args.url_mode == 'virtual' else tag.identifier.hex().upper() print('Tag:', uid if uid != 'virtual' else f'UID-free (hw={tag.identifier.hex().upper()})') try: r = requests.get(f'{base}/api/chip', params={'user': user, 'key': key, 'uid': uid, **extra}, timeout=10) except requests.RequestException as e: print('lookup failed:', e); continue if r.status_code == 401: print(' API disabled/invalid — enable the key on /chips'); continue if r.status_code not in (200,): print(' error:', r.json().get('error')); continue data = r.json() print(' status:', data['status']) url = data['url'] print(' writing:', url) if not tag.ndef or not tag.ndef.is_writeable: print(' tag not NDEF-writeable'); continue tag.ndef.message = nfc.ndef.Message(nfc.ndef.UriRecord(url)) if args.lock: tag.ndef.is_writeable = False print(' OK — tag written + LOCKED (permanent read-only).') else: print(' OK — tag written (re-writable).') if __name__ == '__main__': main()