device: Support deleting a single fingerprint for user

Add a method to delete only a Fingerprint for a device, this is required
by they g-c-c UI design and at the same time it reflects the libfprint
API, where so far only a fingerprint at time can be deleted.
This commit is contained in:
Marco Trevisan (Treviño)
2020-12-06 17:50:48 +01:00
parent 1835d99265
commit fd72c0b81b
3 changed files with 147 additions and 9 deletions

View File

@ -574,6 +574,10 @@ get_permissions_for_invocation (GDBusMethodInvocation *invocation)
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY; required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL; required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
} }
else if (g_str_equal (method_name, "DeleteEnrolledFinger"))
{
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
}
else if (g_str_equal (method_name, "DeleteEnrolledFingers")) else if (g_str_equal (method_name, "DeleteEnrolledFingers"))
{ {
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL; required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
@ -1838,12 +1842,18 @@ fprint_device_list_enrolled_fingers (FprintDBusDevice *dbus_dev,
} }
static void static void
delete_enrolled_fingers (FprintDevice *rdev, const char *user) delete_enrolled_fingers (FprintDevice *rdev,
const char *user,
FpFinger finger)
{ {
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev); FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
guint i; guint i;
g_debug ("Deleting enrolled fingers for user %s", user); if (finger != FP_FINGER_UNKNOWN)
g_debug ("Deleting enrolled finger %s for user %s",
fp_finger_to_name (finger), user);
else
g_debug ("Deleting enrolled fingers for user %s", user);
/* First try deleting the print from the device, we don't consider it /* First try deleting the print from the device, we don't consider it
* fatal if this does not work. */ * fatal if this does not work. */
@ -1867,6 +1877,9 @@ delete_enrolled_fingers (FprintDevice *rdev, const char *user)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
if (finger != FP_FINGER_UNKNOWN && fp_print_get_finger (print) != finger)
continue;
if (!fp_device_delete_print_sync (priv->dev, print, NULL, &error)) if (!fp_device_delete_print_sync (priv->dev, print, NULL, &error))
{ {
g_warning ("Error deleting print from device: %s", error->message); g_warning ("Error deleting print from device: %s", error->message);
@ -1876,8 +1889,15 @@ delete_enrolled_fingers (FprintDevice *rdev, const char *user)
} }
} }
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++) if (finger != FP_FINGER_UNKNOWN)
store.print_data_delete (priv->dev, i, user); {
store.print_data_delete (priv->dev, finger, user);
}
else
{
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++)
store.print_data_delete (priv->dev, i, user);
}
} }
#ifdef __linux__ #ifdef __linux__
@ -1982,7 +2002,7 @@ fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_dev,
g_assert (user); g_assert (user);
g_assert (g_str_equal (username, "") || g_str_equal (user, username)); g_assert (g_str_equal (username, "") || g_str_equal (user, username));
delete_enrolled_fingers (rdev, user); delete_enrolled_fingers (rdev, user, FP_FINGER_UNKNOWN);
if (!opened && fp_device_has_storage (priv->dev)) if (!opened && fp_device_has_storage (priv->dev))
fp_device_close_sync (priv->dev, NULL, NULL); fp_device_close_sync (priv->dev, NULL, NULL);
@ -2020,13 +2040,59 @@ fprint_device_delete_enrolled_fingers2 (FprintDBusDevice *dbus_dev,
session = session_data_get (priv); session = session_data_get (priv);
delete_enrolled_fingers (rdev, session->username); delete_enrolled_fingers (rdev, session->username, FP_FINGER_UNKNOWN);
fprint_dbus_device_complete_delete_enrolled_fingers2 (dbus_dev, fprint_dbus_device_complete_delete_enrolled_fingers2 (dbus_dev,
invocation); invocation);
return TRUE; return TRUE;
} }
static gboolean
fprint_device_delete_enrolled_finger (FprintDBusDevice *dbus_dev,
GDBusMethodInvocation *invocation,
const gchar *finger_name)
{
FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
FpFinger finger = finger_name_to_fp_finger (finger_name);
g_autoptr(SessionData) session = NULL;
g_autoptr(GError) error = NULL;
if (!_fprint_device_check_claimed (rdev, invocation, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
if (finger == FP_FINGER_UNKNOWN)
{
g_dbus_method_invocation_return_error_literal (invocation,
FPRINT_ERROR,
FPRINT_ERROR_INVALID_FINGERNAME,
"Invalid finger name");
return TRUE;
}
if (!can_start_action (rdev, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
priv->current_action = ACTION_DELETE;
session = session_data_get (priv);
/* FIXME: Should we return an error if the requested finger is not enrolled?! */
delete_enrolled_fingers (rdev, session->username, finger);
priv->current_action = ACTION_NONE;
fprint_dbus_device_complete_delete_enrolled_finger (dbus_dev, invocation);
return TRUE;
}
static gboolean static gboolean
handle_unauthorized_access (FprintDevice *rdev, handle_unauthorized_access (FprintDevice *rdev,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
@ -2104,6 +2170,7 @@ static void
fprint_device_dbus_skeleton_iface_init (FprintDBusDeviceIface *iface) fprint_device_dbus_skeleton_iface_init (FprintDBusDeviceIface *iface)
{ {
iface->handle_claim = fprint_device_claim; iface->handle_claim = fprint_device_claim;
iface->handle_delete_enrolled_finger = fprint_device_delete_enrolled_finger;
iface->handle_delete_enrolled_fingers = fprint_device_delete_enrolled_fingers; iface->handle_delete_enrolled_fingers = fprint_device_delete_enrolled_fingers;
iface->handle_delete_enrolled_fingers2 = fprint_device_delete_enrolled_fingers2; iface->handle_delete_enrolled_fingers2 = fprint_device_delete_enrolled_fingers2;
iface->handle_enroll_start = fprint_device_enroll_start; iface->handle_enroll_start = fprint_device_enroll_start;

View File

@ -247,7 +247,7 @@
<doc:definition> <doc:definition>
No further prints can be enrolled on this device, <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref> should now be called. No further prints can be enrolled on this device, <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref> should now be called.
<doc:ref type="method" to="DeleteEnrolledFingers2">Delete other prints</doc:ref> from the device first to continue <doc:ref type="method" to="DeleteEnrolledFinger">Delete other prints</doc:ref> from the device first to continue
(e.g. from other users). Note that old prints or prints from other operating systems may be deleted automatically (e.g. from other users). Note that old prints or prints from other operating systems may be deleted automatically
to resolve this error without any notification. to resolve this error without any notification.
</doc:definition> </doc:definition>
@ -307,7 +307,8 @@
<doc:para> <doc:para>
This call only exists for compatibility reasons, you should instead claim the device using This call only exists for compatibility reasons, you should instead claim the device using
<doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref> and then call <doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref> and then call
<doc:ref type="method" to="DeleteEnrolledFingers2">DeleteEnrolledFingers2</doc:ref>. <doc:ref type="method" to="DeleteEnrolledFingers2">DeleteEnrolledFingers2</doc:ref> or
<doc:ref type="method" to="DeleteEnrolledFinger">DeleteEnrolledFinger</doc:ref>.
</doc:para> </doc:para>
</doc:description> </doc:description>
@ -335,6 +336,31 @@
<!-- ************************************************************ --> <!-- ************************************************************ -->
<method name="DeleteEnrolledFinger">
<arg type="s" name="finger_name" direction="in">
<doc:doc>
<doc:summary>A string representing the finger to delete. See
<doc:ref type="description" to="fingerprint-names">Fingerprint names</doc:ref>.
Note that "any" is not a valid finger name for this method.</doc:summary>
</doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>
Delete the enrolled fingerprint for the user currently claiming the device with <doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref>.
</doc:para>
</doc:description>
<doc:errors>
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
<doc:error name="&ERROR_CLAIM_DEVICE;">if the device was not claimed</doc:error>
<doc:error name="&ERROR_INVALID_FINGERNAME;">if the finger name passed is invalid</doc:error>
</doc:errors>
</doc:doc>
</method>
<!-- ************************************************************ -->
<method name="Claim"> <method name="Claim">
<arg type="s" name="username" direction="in"> <arg type="s" name="username" direction="in">
<doc:doc><doc:summary>The username for whom to claim the device. See <doc:ref type="description" to="usernames">Usernames</doc:ref>.</doc:summary></doc:doc> <doc:doc><doc:summary>The username for whom to claim the device. See <doc:ref type="description" to="usernames">Usernames</doc:ref>.</doc:summary></doc:doc>

View File

@ -894,6 +894,13 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
with self.assertFprintError('PermissionDenied'): with self.assertFprintError('PermissionDenied'):
self.device.DeleteEnrolledFingers2() self.device.DeleteEnrolledFingers2()
def test_unallowed_delete_single_with_verify_claim(self):
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
self.device.Claim('(s)', '')
with self.assertFprintError('PermissionDenied'):
self.device.DeleteEnrolledFingers('(s)', 'right-thumb')
def test_unallowed_verify_with_enroll_claim(self): def test_unallowed_verify_with_enroll_claim(self):
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll']) self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
self.device.Claim('(s)', '') self.device.Claim('(s)', '')
@ -948,6 +955,10 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
def test_unclaimed_delete_enrolled_fingers(self): def test_unclaimed_delete_enrolled_fingers(self):
self.device.DeleteEnrolledFingers('(s)', 'testuser') self.device.DeleteEnrolledFingers('(s)', 'testuser')
def test_unclaimed_delete_enrolled_finger(self):
with self.assertFprintError('ClaimDevice'):
self.device.DeleteEnrolledFinger('(s)', 'left-index-finger')
def test_unclaimed_delete_enrolled_fingers2(self): def test_unclaimed_delete_enrolled_fingers2(self):
with self.assertFprintError('ClaimDevice'): with self.assertFprintError('ClaimDevice'):
self.device.DeleteEnrolledFingers2() self.device.DeleteEnrolledFingers2()
@ -1107,10 +1118,22 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
raise(e) raise(e)
super().tearDown() super().tearDown()
def test_wrong_finger_enroll_start(self): def test_any_finger_enroll_start(self):
with self.assertFprintError('InvalidFingername'): with self.assertFprintError('InvalidFingername'):
self.device.EnrollStart('(s)', 'any') self.device.EnrollStart('(s)', 'any')
def test_wrong_finger_enroll_start(self):
with self.assertFprintError('InvalidFingername'):
self.device.EnrollStart('(s)', 'sixth-right-finger')
def test_any_finger_delete_print(self):
with self.assertFprintError('InvalidFingername'):
self.device.DeleteEnrolledFinger('(s)', 'any')
def test_wrong_finger_delete_print(self):
with self.assertFprintError('InvalidFingername'):
self.device.DeleteEnrolledFinger('(s)', 'sixth-left-finger')
def test_verify_with_no_enrolled_prints(self): def test_verify_with_no_enrolled_prints(self):
with self.assertFprintError('NoEnrolledPrints'): with self.assertFprintError('NoEnrolledPrints'):
self.device.VerifyStart('(s)', 'any') self.device.VerifyStart('(s)', 'any')
@ -1189,6 +1212,21 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser'))) self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser')))
self.assertTrue(os.path.exists(self.state_dir)) self.assertTrue(os.path.exists(self.state_dir))
def test_enroll_delete_single(self):
self.enroll_image('whorl', finger='right-index-finger')
self.enroll_image('tented_arch', finger='left-index-finger')
self.assertTrue(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
self.assertTrue(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/2')))
self.device.DeleteEnrolledFinger('(s)', 'right-index-finger')
self.assertTrue(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/2')))
self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
self.device.DeleteEnrolledFinger('(s)', 'left-index-finger')
self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/2')))
self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
def test_enroll_invalid_storage_dir(self): def test_enroll_invalid_storage_dir(self):
# Directory will not exist yet # Directory will not exist yet
os.makedirs(self.state_dir, mode=0o500) os.makedirs(self.state_dir, mode=0o500)
@ -1423,6 +1461,13 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
with self.assertFprintError('PermissionDenied'): with self.assertFprintError('PermissionDenied'):
self.device.DeleteEnrolledFingers2() self.device.DeleteEnrolledFingers2()
def test_unallowed_delete_enrolled_finger(self):
self.enroll_image('whorl')
self._polkitd_obj.SetAllowed([''])
with self.assertFprintError('PermissionDenied'):
self.device.DeleteEnrolledFinger('(s)', 'left-little-finger')
def test_delete_enrolled_fingers_from_other_client(self): def test_delete_enrolled_fingers_from_other_client(self):
with self.assertFprintError('AlreadyInUse'): with self.assertFprintError('AlreadyInUse'):
self.call_device_method_from_other_client('DeleteEnrolledFingers', ['testuser']) self.call_device_method_from_other_client('DeleteEnrolledFingers', ['testuser'])