device: Remove local storage prints if they've been removed from device

If a print we have stored locally is not available in device anymore, we
need to cleanup the local database.

We do not get a proper DATA_NOT_FOUND error for most devices (indeed, at
this point no device does this properly). As such, do this when we see a
DATA_NOT_FOUND error and the first time that we get a verify-no-match
results on a device which is capable of listing all known prints.

Co-Authored-by: Marco Trevisan (Treviño) <mail@3v1n0.net>
This commit is contained in:
Benjamin Berg
2021-07-30 18:38:35 +02:00
parent 0bba073dff
commit 626128a0fa
2 changed files with 138 additions and 0 deletions

View File

@ -101,6 +101,8 @@ typedef struct
FpDevice *dev; FpDevice *dev;
SessionData *_session; SessionData *_session;
gboolean local_storage_checked;
guint verify_stop_wait_timeout_id; guint verify_stop_wait_timeout_id;
PolkitAuthority *auth; PolkitAuthority *auth;
@ -1273,6 +1275,93 @@ report_verify_status (FprintDevice *rdev,
session->verify_status_reported = TRUE; session->verify_status_reported = TRUE;
} }
static void
check_local_storage (FprintDevice *rdev,
gboolean found_match,
GError *error)
{
g_autoptr(GError) err = NULL;
g_autoptr(GPtrArray) device_prints = NULL;
g_autoptr(GPtrArray) host_prints = NULL;
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
unsigned i;
g_return_if_fail (priv->current_action == ACTION_VERIFY ||
priv->current_action == ACTION_IDENTIFY);
/* This only ever sense if the device can list prints. */
if (!fp_device_has_feature (priv->dev, FP_DEVICE_FEATURE_STORAGE_LIST))
return;
/* We do not have any proper driver that correctly reports DATA_NOT_FOUND
* errors. Only synaptics, but there the feature is being disabled on the
* firmware side.
* As such, just always run a test the first time we get a match failure.
*/
if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_NOT_FOUND))
{
if (priv->local_storage_checked)
g_warning ("Device %s reported that a passed print did not exist during action %d, but we verified the local storage!",
fp_device_get_name (priv->dev), priv->current_action);
else
g_debug ("Device %s reported that a passed print did not exist during action %d",
fp_device_get_name (priv->dev), priv->current_action);
}
else if (error || priv->local_storage_checked)
{
return;
}
else if (!found_match)
{
g_debug ("Device %s failed to match during action %d, verifying local storage",
fp_device_get_name (priv->dev), priv->current_action);
}
else
{
return;
}
priv->local_storage_checked = TRUE;
device_prints = fp_device_list_prints_sync (priv->dev, NULL, &err);
if (!device_prints)
{
g_warning ("Failed to query prints: %s", err->message);
return;
}
host_prints = load_all_prints (rdev);
for (i = 0; i < host_prints->len; i++)
{
FpPrint *print = g_ptr_array_index (host_prints, i);
int r;
if (g_ptr_array_find_with_equal_func (device_prints,
print,
(GEqualFunc) fp_print_equal,
NULL))
continue;
/* Print not known by device, remove locally */
if ((r = store.print_data_delete (priv->dev,
fp_print_get_finger (print),
fp_print_get_username (print))) == 0)
{
g_message ("Deleted stored finger %d for user %s as it is unknown to device.",
fp_print_get_finger (print),
fp_print_get_username (print));
}
else
{
g_warning ("Error deleting finger %d for user %s that is unknown to device: %d!",
fp_print_get_finger (print),
fp_print_get_username (print),
r);
}
}
}
static gboolean static gboolean
can_start_action (FprintDevice *rdev, GError **error) can_start_action (FprintDevice *rdev, GError **error)
{ {
@ -1489,6 +1578,8 @@ verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
error->message); error->message);
} }
check_local_storage (rdev, match, error);
stoppable_action_completed (rdev); stoppable_action_completed (rdev);
} }
} }
@ -1532,6 +1623,8 @@ identify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
error->message); error->message);
} }
check_local_storage (rdev, match != NULL, error);
stoppable_action_completed (rdev); stoppable_action_completed (rdev);
} }
} }

View File

@ -1086,6 +1086,51 @@ class FPrintdVirtualStorageDeviceTests(FPrintdVirtualStorageDeviceBaseTest):
prints = self.get_stored_prints() prints = self.get_stored_prints()
self.assertEqual(set(prints), set(garbage_prints)) self.assertEqual(set(prints), set(garbage_prints))
def test_local_storage_cleanup_data_error(self):
# Enroll a print and delete it
self.enroll_print('deleted-print', finger='left-thumb')
self.send_command('REMOVE', 'deleted-print')
# Note: would be thrown anyway by the storage device if we scan something
self.send_error(FPrint.DeviceError.DATA_NOT_FOUND)
self.device.VerifyStart('(s)', 'any')
self.wait_for_result('verify-no-match')
self.device.VerifyStop()
# At this point, there is no print left
with self.assertFprintError('NoEnrolledPrints'):
self.device.ListEnrolledFingers('(s)', 'testuser')
def test_local_storage_cleanup_no_match(self):
# Enroll a print and delete it
self.enroll_print('existing-print', finger='right-index-finger')
self.enroll_print('deleted-print', finger='left-thumb')
self.send_command('REMOVE', 'deleted-print')
# We need to send a print that is known to the device
self.send_image('other-print')
self.device.VerifyStart('(s)', 'right-index-finger')
self.wait_for_result('verify-no-match')
self.device.VerifyStop()
# At this point, the deleted print has disappeared
self.assertEqual(set(self.device.ListEnrolledFingers('(s)', 'testuser')), {'right-index-finger'})
# Now, do the same thing, and the print will not be deleted
self.enroll_print('deleted-print', finger='left-thumb')
self.send_command('REMOVE', 'deleted-print')
self.send_image('other-print')
self.device.VerifyStart('(s)', 'right-index-finger')
self.wait_for_result('verify-no-match')
self.device.VerifyStop()
# At this point, the deleted print is still there
self.assertEqual(set(self.device.ListEnrolledFingers('(s)', 'testuser')), {'right-index-finger', 'left-thumb'})
def test_enroll_with_one_stage_only(self): def test_enroll_with_one_stage_only(self):
self._maybe_reduce_enroll_stages(stages=1) self._maybe_reduce_enroll_stages(stages=1)