130 lines
4.1 KiB
Python
130 lines
4.1 KiB
Python
|
#!/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)
|