diff --git a/.config.json-sample b/.config.json-sample new file mode 100644 index 0000000..88f67f3 --- /dev/null +++ b/.config.json-sample @@ -0,0 +1,7 @@ +{ + "mode": "capture", + "domain": { + "name": "UCTH", + "code": "ucth" + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9b8cc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.config.json diff --git a/README.md b/README.md index 4a305a9..3e5f369 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ This service uses the libfprint library (version 2 and newwer) to capture finger ## PIP Packages 1. pip3 install python-socketio -2. pip3 install eventlet +2. pip3 install simple-websocket +3. pip3 install flask +4. pip3 install requests # How to run ```python3 app.py``` \ No newline at end of file diff --git a/app.py b/app.py index fde8605..08d0ece 100644 --- a/app.py +++ b/app.py @@ -1,21 +1,36 @@ -import eventlet +import json import socketio import uuid import base64 import os - +import requests +from flask import Flask + import gi gi.require_version("FPrint", "2.0") gi.require_version("Gio", "2.0") from gi.repository import FPrint, GLib, Gio - -sio = socketio.Server() -static_files = { - '/assets': './public', - '/': {'filename': './public/index.html'} +config = { + 'domain': { + 'name': 'UNICAL', + 'code': 'uc' + }, + 'mode': 'capture' } -app = socketio.WSGIApp(sio, static_files=static_files) + +configFileExists = os.path.exists('.config.json'); +if configFileExists: + with open('.config.json') as reader: + config = json.loads(reader.read()); + +sio = socketio.Server(async_mode="threading") +app = Flask(__name__) +static_files = { + '/assets': './public/{}'.format(config['mode']), + '/': { 'filename': './public/{}/index.html'.format(config['mode']) } +} +app.wsgi_app = socketio.WSGIApp(sio, static_files=static_files) stopEnrollment = False def progress(device, completed_stages, prnt, sessionId, error): @@ -57,29 +72,20 @@ def enroll(sessionId, data): sio.emit('fprint-enroll-done', { 'ok': False, 'message': e}) finally: device.close_sync() + +is_verify_active = False +device = None; -def open_dev(sessionId): - device = None; - ctx = FPrint.Context() - devices = ctx.get_devices() - if (len(devices) == 0): - print("There is no attached device.") - else: - device = devices[0] - if (not device): - print("There is no attached device") - - if (not device.is_open()): - device.open_sync() - while (not device.is_open()): - print('Opening...') - return device - -def verify(sessionId, data): +def verify_start(sessionId, data): + global device; + global is_verify_active; + ctx = FPrint.Context() devices = ctx.get_devices() if (len(devices) == 0): print("There is no attached device.") + sio.emit('fprint-verify-start-error', "There is no attached device."); + return; else: device = devices[0] if (not device): @@ -90,36 +96,127 @@ def verify(sessionId, data): while (not device.is_open()): print('Opening...') - with open('adebisi-fa.jpg', 'r+b') as f: - img = f.read() - prtRecord = FPrint.Print.deserialize(img) - canceller = Gio.Cancellable.new() - (match, prtFound) = device.verify_sync(prtRecord, canceller, None) - if (match): - sio.emit('fprint-verify-done', { 'ok': True, 'data': data }, room=sessionId) - else: - sio.emit('fprint-verify-done', { 'ok': False }, room=sessionId) - device.close_sync() - -def verify_short(sessionId, data): - d = open_dev(sessionId) - with open('adebisi-fa.jpg', 'r+b') as f: - img = f.read() - prtRecord = FPrint.Print.deserialize(img) - (match, print) = d.verify_sync(prtRecord, None, None) - if (match): - sio.emit('fprint-verify-done', { 'ok': True, 'data': data }, room=sessionId) + while True: + with open('adebisi-fa.jpg', 'r+b') as f: + img = f.read() + prtRecord = FPrint.Print.deserialize(img) + (match, prtFound) = device.verify_sync(prtRecord, Gio.Cancellable.new(), None) + if (match): + sio.emit('fprint-verify-start-done', { 'ok': True, 'data': data }, room=sessionId) + else: + sio.emit('fprint-verify-start-done', { 'ok': False }, room=sessionId) + + if not is_verify_active: + break; + + if device.is_open(): + device.close_sync() + pass + +is_identify_active = False +identify_canceller = None +raw_prints = None +def identify_start(sessionId, data): + global device; + global is_identify_active; + global identify_canceller; + global raw_prints; + + ctx = FPrint.Context() + devices = ctx.get_devices() + if (len(devices) == 0): + print("There is no attached device.") + sio.emit('fprint-identify-start-error', "There is no attached device."); + return; else: - sio.emit('fprint-verify-done', { 'ok': False }, room=sessionId) - d.close_sync() + device = devices[0] + if (not device): + print("There is no attached device") + + if (not device.is_open()): + device.open_sync() + while (not device.is_open()): + print('Opening...') + + sio.emit('fprint-identify-start-done', room=sessionId) + is_identify_active = True + while True: + prtRecords = []; + with open('adebisi-fa.jpg', 'r+b') as f: + img = f.read() + prtRecords = [FPrint.Print.deserialize(img)] + + try: + identify_canceller = Gio.Cancellable.new(); + (match, prtFound) = device.identify_sync(prtRecords, identify_canceller, None) + if (match): + sio.emit('fprint-identify-done', { 'ok': True, 'name': 'Adebisi Foluso A.', 'phone': "+2348068287222" }, room=sessionId) + print('Found.') + else: + sio.emit('fprint-identify-done', { 'ok': False }, room=sessionId) + print('Not found.') + except: + print("Identification stopped due to error.") + sio.emit("fprint-identify-stop-done", { 'ok': True, 'message': 'Identification stopped due to error.' }) + is_identify_active = False; + finally: + if not is_identify_active: + print('Identification is active. Quiting...') + break; + pass + + if device.is_open(): + try: + device.close_sync() + except: + print('An error occured while closing device.'); + finally: + print('It appears device has already been removed.') # events -@sio.on("fprint-verify") -def fprint_verify(sid, data): - verify_short(sid, data) +@sio.on("fprint-verify-stop") +def fprint_verify_stop(sid, data): + global is_verify_active; + + if (device.is_open()): + try: + device.close_sync(); + sio.emit("fprint-verify-stop-done", { 'ok': True, 'message': 'Verifycation stopped.' }) + return; + except: + print('An error occured while closing device.'); + finally: + print("It appears device has already been removed.") + else: + sio.emit("fprint-verify-stop-done", { 'ok': False, 'message': 'Verifycation was inactive.' }) + + is_verify_active = False; pass + +@sio.on("fprint-verify-start") +def fprint_verify_start(sid, data): + verify_start(sid, data) + +def stop_fprint_identify(): + global is_identify_active; + global identify_canceller; + + if identify_canceller: + identify_canceller.cancel() + + sio.emit("fprint-identify-stop-done", { 'ok': True, 'message': 'Identification stopped.' }) + is_identify_active = False; + +@sio.on("fprint-identify-start") +def fprint_identify_start(sid, data): + identify_start(sid, data) + +@sio.on("fprint-identify-stop") +def fprint_identify_stop(sid, data): + stop_fprint_identify() + @sio.on("fprint-enroll") def fprint_enroll(sid, data): print('Enrolling {}'.format(data['finger'])) @@ -133,7 +230,32 @@ def capture(sid, data): @sio.event def connect(sid, data): - # print({ 'sid': sid, 'event': 'connect', 'data': data}); + global config; + if config['mode'] == 'clockio': + global raw_prints; + stop_fprint_identify(); + config['started'] = is_identify_active + domain_code = config['domain']['code']; + response = requests.get("https://apis.a2loft.net/identity/{}/units".format(domain_code)) + responseJson = json.loads(response.text) + if responseJson['ok']: + config['departments'] = responseJson['data']; + domain_fprint_file = '{}/fprint-sync/.{}-fprint-data.json'.format(os.getenv("HOME"), domain_code); + print(domain_fprint_file); + if os.path.exists(domain_fprint_file): + with open(domain_fprint_file) as f: + records = json.loads(f.read()); + raw_prints = records['profiles']; + prints_dict = {}; + for profile in raw_prints: + for fp in profile['fingerprints']: + prints_dict[fp] = profile + config['records'] = { + 'length': len(records['profiles']), + 'timestamp': records['timestamp'] + }; + + sio.emit('config', config); pass @sio.event @@ -141,7 +263,6 @@ def disconnect(sid): print({ 'sid': sid, 'event': 'disconnect'}); pass - @sio.on('capture-other') def capture_other(sid, data): print({ "event": "capture_other", "data": data }) @@ -150,4 +271,5 @@ def capture_other(sid, data): with open('/tmp/libfprint-server', 'w') as f: f.write(str(os.getpid())); -eventlet.wsgi.server(eventlet.listen(('127.0.0.1', 9000), reuse_port=False), app) +if __name__ == '__main__': + app.run(port=9000) \ No newline at end of file diff --git a/public/app.js b/public/capture/app.js similarity index 93% rename from public/app.js rename to public/capture/app.js index 147bc8f..aa5ddaf 100644 --- a/public/app.js +++ b/public/capture/app.js @@ -4,6 +4,7 @@ var app = new Vue({ data: { step: 0, phone: '', + domain: { code: 'uc', name: 'UNICAL' }, errorMessage: '', otp: '', busy: { @@ -34,6 +35,10 @@ var app = new Vue({ this.socket.on("connect", () => { }) + this.socket.on("config", (data) => { + this.domain = data.domain; + }); + this.socket.on("fprint-enroll-error", (data) => { console.log({ event: 'enroll-error', data }); swal("Oops!", `Operation failed. ${data}.`, "error"); @@ -81,7 +86,7 @@ var app = new Vue({ this.busy.login = true; try { var { data } = await axios.get( - this.authenticateUrl(`/uc/${this.staff.reference}`) + this.authenticateUrl(`/${this.domain.code}/${this.staff.reference}`) ); if (!data.ok) { swal("Oops!", `Operation failed. ${data.message}.` + this.staff.reference, "error"); @@ -121,7 +126,7 @@ var app = new Vue({ } var { data } = await axios.post( - this.authenticateUrl(`/uc/fingerprints/${this.staff.reference}`), + this.authenticateUrl(`/${this.domain.code}/fingerprints/${this.staff.reference}`), { fingerprints } ); diff --git a/public/index.html b/public/capture/index.html similarity index 99% rename from public/index.html rename to public/capture/index.html index 47b0044..e3e1c5c 100644 --- a/public/index.html +++ b/public/capture/index.html @@ -18,7 +18,7 @@