mirror of
https://gitlab.com/mishakmak/pam-fprint-grosshack.git
synced 2026-04-08 20:03:34 +02:00
device: Add duplicate checking during enroll
Always do an identify step before starting an enroll. If we find an existing print, delete or throw an error depending on what is appropriate. Doing this ensures that we should not get duplicate prints system wide. This means we will be able to identify the user that is trying to log in. But more importantly, we need to do these checks for MoC devices, which always run "identify" against all device stored prints rather than the passed gallery.
This commit is contained in:
committed by
Marco Trevisan (Treviño)
parent
b7b91e77bb
commit
5785dc65b4
128
src/device.c
128
src/device.c
@ -306,7 +306,8 @@ on_nr_enroll_stages_changed (FprintDevice *rdev,
|
||||
FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev);
|
||||
gint nr_enroll_stages;
|
||||
|
||||
nr_enroll_stages = fp_device_get_nr_enroll_stages (device);
|
||||
/* One extra step for our internal identification. */
|
||||
nr_enroll_stages = fp_device_get_nr_enroll_stages (device) + 1;
|
||||
|
||||
g_debug ("Device %s enroll stages changed to %d",
|
||||
fp_device_get_name (device),
|
||||
@ -1637,6 +1638,7 @@ enroll_progress_cb (FpDevice *dev,
|
||||
|
||||
g_debug ("enroll_stage_cb: result %s", name);
|
||||
|
||||
/* NOTE: We add one more step internally, but we can ignore that here. */
|
||||
if (completed_stages < fp_device_get_nr_enroll_stages (dev))
|
||||
g_signal_emit (rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, FALSE);
|
||||
}
|
||||
@ -1827,6 +1829,103 @@ enroll_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
stoppable_action_completed (rdev);
|
||||
}
|
||||
|
||||
static void
|
||||
enroll_identify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(FpPrint) matched_print = NULL;
|
||||
g_autoptr(FpPrint) found_print = NULL;
|
||||
FprintDevice *rdev = user_data;
|
||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||
const char *name;
|
||||
|
||||
fp_device_identify_finish (dev, res, &matched_print, &found_print, &error);
|
||||
|
||||
if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_NOT_FOUND))
|
||||
{
|
||||
g_clear_object (&found_print);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
/* We may need to retry or error out. */
|
||||
if (error)
|
||||
{
|
||||
gboolean retry = error->domain == FP_DEVICE_RETRY;
|
||||
|
||||
name = enroll_result_to_name (!retry, FALSE, error);
|
||||
g_signal_emit (rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, !retry);
|
||||
|
||||
/* Retry or clean up. */
|
||||
if (retry)
|
||||
{
|
||||
g_autoptr(GPtrArray) all_prints = NULL;
|
||||
|
||||
all_prints = load_all_prints (rdev);
|
||||
fp_device_identify (priv->dev,
|
||||
all_prints,
|
||||
priv->current_cancellable,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) enroll_identify_cb,
|
||||
rdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
g_warning ("Device reported an error during identify for enroll: %s", error->message);
|
||||
|
||||
stoppable_action_completed (rdev);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Identify has finished (successfully), there are three possible cases:
|
||||
* 1. Match found in the gallery, in this case, we error out.
|
||||
* 2. No match found, but on-device print returned, we should delete it
|
||||
* 3. None of the above, we can just continue.
|
||||
*/
|
||||
|
||||
if (matched_print)
|
||||
{
|
||||
g_signal_emit (rdev, signals[SIGNAL_ENROLL_STATUS], 0, "enroll-duplicate", TRUE);
|
||||
|
||||
stoppable_action_completed (rdev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (found_print && fp_device_has_storage (priv->dev))
|
||||
{
|
||||
if (!fp_print_get_device_stored (found_print))
|
||||
g_critical ("libfprint driver bug: Returned device print not marked as stored on device.");
|
||||
|
||||
/* Try to delete the print (synchronously), and continue if it succeeds. */
|
||||
if (!fp_device_delete_print_sync (priv->dev,
|
||||
found_print,
|
||||
priv->current_cancellable,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Failed to garbage collect duplicate print, cannot continue with enroll.");
|
||||
g_signal_emit (rdev, signals[SIGNAL_ENROLL_STATUS], 0, "enroll-duplicate", TRUE);
|
||||
|
||||
stoppable_action_completed (rdev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_emit (rdev, signals[SIGNAL_ENROLL_STATUS], 0, "enroll-stage-passed", FALSE);
|
||||
|
||||
/* We are good and can start to enroll. */
|
||||
fp_device_enroll (priv->dev,
|
||||
fprint_device_create_enroll_template (rdev, priv->enroll_data),
|
||||
priv->current_cancellable,
|
||||
enroll_progress_cb,
|
||||
rdev,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) enroll_cb,
|
||||
rdev);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fprint_device_enroll_start (FprintDBusDevice *dbus_dev,
|
||||
@ -1834,6 +1933,7 @@ fprint_device_enroll_start (FprintDBusDevice *dbus_dev,
|
||||
const char *finger_name)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GPtrArray) all_prints = NULL;
|
||||
FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
|
||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||
FpFinger finger = finger_name_to_fp_finger (finger_name);
|
||||
@ -1862,17 +1962,25 @@ fprint_device_enroll_start (FprintDBusDevice *dbus_dev,
|
||||
|
||||
priv->current_cancellable = g_cancellable_new ();
|
||||
priv->enroll_data = finger;
|
||||
fp_device_enroll (priv->dev,
|
||||
fprint_device_create_enroll_template (rdev, priv->enroll_data),
|
||||
priv->current_cancellable,
|
||||
enroll_progress_cb,
|
||||
rdev,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) enroll_cb,
|
||||
rdev);
|
||||
|
||||
priv->current_action = ACTION_ENROLL;
|
||||
|
||||
/* We (now) have the policy that there must be no duplicate prints.
|
||||
* We need to do this for MoC devices, as their "identify" function
|
||||
* will generally just identify across all device stored prints.
|
||||
* For MoH, we also do it. For consistency and because it allows us
|
||||
* to implement new features in the future (i.e. logging in/unlocking
|
||||
* the correct user without selecting it first).
|
||||
*/
|
||||
all_prints = load_all_prints (rdev);
|
||||
fp_device_identify (priv->dev,
|
||||
all_prints,
|
||||
priv->current_cancellable,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) enroll_identify_cb,
|
||||
rdev);
|
||||
|
||||
fprint_dbus_device_complete_enroll_start (dbus_dev, invocation);
|
||||
|
||||
return TRUE;
|
||||
|
||||
@ -882,9 +882,10 @@ class FPrintdVirtualStorageDeviceBaseTest(FPrintdVirtualDeviceBaseTest):
|
||||
def _maybe_reduce_enroll_stages(self, stages=-1):
|
||||
# Reduce the number of default enroll stages, we can go a bit faster
|
||||
stages = stages if stages > 0 else self.enroll_stages
|
||||
stages += 1 # Adding the extra stage for duplicates-check
|
||||
if self.num_enroll_stages == stages:
|
||||
return
|
||||
self.send_command('SET_ENROLL_STAGES', stages)
|
||||
self.send_command('SET_ENROLL_STAGES', stages - 1)
|
||||
while self.num_enroll_stages != stages:
|
||||
ctx.iteration(True)
|
||||
self.assertIn({'num-enroll-stages': stages}, self._changed_properties)
|
||||
@ -918,6 +919,7 @@ class FPrintdVirtualStorageDeviceTests(FPrintdVirtualStorageDeviceBaseTest):
|
||||
self.assertEqual(set(prints), set(garbage_collect + list(enrolled_prints.keys())))
|
||||
|
||||
def trigger_garbagecollect():
|
||||
self.send_image('some-other-print')
|
||||
self.send_command('ERROR', int(FPrint.DeviceError.DATA_FULL))
|
||||
self.device.EnrollStart('(s)', 'right-thumb')
|
||||
self.device.EnrollStop()
|
||||
@ -1003,6 +1005,10 @@ class FPrintdVirtualNoStorageDeviceBaseTest(FPrintdVirtualStorageDeviceBaseTest)
|
||||
device_driver = 'virtual_device'
|
||||
driver_name = 'Virtual device for debugging'
|
||||
|
||||
def enroll_image(self, img, device=None, finger='right-index-finger',
|
||||
expected_result='enroll-completed', claim_user=None):
|
||||
self.skipTest('Identification not supported, thus is the enrolling')
|
||||
|
||||
class FPrintdVirtualNoStorageDeviceTest(FPrintdVirtualNoStorageDeviceBaseTest):
|
||||
|
||||
def check_verify_finger_match(self, image, expect_match, finger):
|
||||
@ -1107,7 +1113,7 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
||||
self.driver_name)
|
||||
|
||||
def test_enroll_stages_property(self):
|
||||
self.assertEqual(self.device.get_cached_property('num-enroll-stages').unpack(), 5)
|
||||
self.assertEqual(self.device.get_cached_property('num-enroll-stages').unpack(), 6)
|
||||
|
||||
def test_scan_type(self):
|
||||
self.assertEqual(self.device.get_cached_property('scan-type').unpack(),
|
||||
@ -2206,6 +2212,8 @@ class FPrintdVirtualDeviceEnrollTests(FPrintdVirtualDeviceBaseTest):
|
||||
self.assertEnrollError(FPrint.DeviceError.DATA_INVALID, 'enroll-unknown-error')
|
||||
|
||||
def test_enroll_error_data_not_found(self):
|
||||
self.assertEnrollError(
|
||||
FPrint.DeviceError.DATA_NOT_FOUND, 'enroll-stage-passed')
|
||||
self.assertEnrollError(FPrint.DeviceError.DATA_NOT_FOUND, 'enroll-unknown-error')
|
||||
|
||||
def test_enroll_error_data_full(self):
|
||||
@ -3009,6 +3017,9 @@ class FPrintdUtilsTest(FPrintdVirtualStorageDeviceBaseTest):
|
||||
self.send_image('print-id')
|
||||
out.check_line('Enroll result: enroll-stage-passed', get_timeout())
|
||||
|
||||
self.send_image('print-id')
|
||||
out.check_line('Enroll result: enroll-stage-passed', get_timeout())
|
||||
|
||||
self.send_retry(FPrint.DeviceRetry.CENTER_FINGER)
|
||||
out.check_line('Enroll result: enroll-finger-not-centered', get_timeout())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user