diff --git a/examples/virtmissensor.py b/examples/virtmissensor.py new file mode 100755 index 00000000..854c10e3 --- /dev/null +++ b/examples/virtmissensor.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 + +# This script can be used together with the virtual_misdev to simulate an +# match-in-sensor device with internal storage. +# +# To use, set the FP_VIRTUAL_MISDEV environment variable for both the +# libfprint using program (e.g. fprintd) and this script. +# +# Usually this would work by adding it into the systemd unit file. The +# best way of doing so is to create +# /etc/systemd/system/fprintd.service.d/fprintd-test.conf +# +# [Service] +# RuntimeDirectory=fprint +# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock +# Environment=G_MESSAGES_DEBUG=all +# ReadWritePaths=$RUNTIME_DIR +# +# After that run: +# +# systemctl daemon-reload +# systemctl restart fprintd.service +# +# You may also need to disable selinux. +# +# Then run this script with e.g. +# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./virtmissensor.py /tmp/storage +# +# Please note that the storage file should be pre-created with a few lines +# Each line represents a slot, if a print is stored, then it will contain a +# UUID (defined by the driver) and a matching string to identify it again. +# Note that the last slot line should not end with a \n + +import sys +import os +import socket +import struct + +import argparse + +parser = argparse.ArgumentParser(description='Play virtual fingerprint device with internal storage.') +parser.add_argument('storage', metavar='storage', type=argparse.FileType('r+'), + help='The "storage" database (one line per slot)') +parser.add_argument('-e', dest='enroll', type=str, + help='Enroll a print using the string as identifier') +parser.add_argument('-v', dest='verify', type=str, + help='Verify print if the stored identifier matches the given identifier') + +args = parser.parse_args() + +cnt = 0 +if args.enroll: + cnt += 1 +if args.verify: + cnt += 1 + +assert cnt == 1, 'You need to give exactly one command argument, -e or -v' + +prints = [] +for slot in args.storage.read().split('\n'): + split = slot.split(' ', 1) + if len(split) == 2: + prints.append(split) + else: + prints.append(None) + + +# Send image through socket +sockaddr = os.environ['FP_VIRTUAL_MISDEV'] + +sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +sock.connect(sockaddr) + +# Assume we get a full message +msg = sock.recv(1024) +assert(msg[-1] == ord(b'\n')) + +if args.enroll: + if not msg.startswith(b'ENROLL '): + sys.stderr.write('Expected to enroll, but driver is not ready for enrolling (%s)\n' % str(msg.split(b' ', 1)[0])) + sys.exit(1) + uuid = msg[7:-1].decode('utf-8') + + for slot in prints: + if slot is not None and slot[0] == uuid: + sock.sendall(b'2\n') # ENROLL_FAIL + sys.stderr.write('Failed to enroll; UUID has already been stored!\n') + sys.exit(1) + + # Find an empty slot + for i, slot in enumerate(prints): + if slot is not None: + continue + + prints[i] = (uuid, args.enroll) + sock.sendall(b'1\n') # ENROLL_COMPLETE + break + else: + # TODO: 2: ENROLL_FAIL, but we should send no empty slot! + sock.sendall(b'2\n') # ENROLL_FAIL + sys.stderr.write('Failed to enroll, no free slots!\n') + sys.exit(1) + +elif args.verify: + if not msg.startswith(b'VERIFY '): + sys.stderr.write('Expected to verify, but driver is not ready for verifying (%s)\n' % str(msg.split(b' ', 1)[0])) + sys.exit(1) + uuid = msg[7:-1].decode('utf-8') + + for slot in prints: + if slot is not None and slot[0] == uuid: + if slot[1] == args.verify: + sock.sendall(b'1\n') # VERIFY_MATCH + else: + sock.sendall(b'0\n') # VERIFY_NO_MATCH + sys.exit(0) + else: + sys.stderr.write('Slot ID is unknown, returning error\n') + sock.sendall(b'-1') # error, need way to report that print is unkown + + +prints_str = '\n'.join('' if p is None else '%s %s' % (p[0], p[1]) for p in prints) +prints_human_str = '\n'.join('empty slot' if p is None else '%s %s' % (p[0], p[1]) for p in prints) + +print('Prints stored now:') +print(prints_human_str) +args.storage.seek(0) +args.storage.truncate() +args.storage.write(prints_str)