1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
#!/usr/bin/env python3
# File: fprintd_tk_lib.py
# Location: https://bgstack15.cgit/fprintd-tk
# Author: bgstack15
# Startdate: 2024-09-22-1 15:33
# SPDX-License-Identifier: GPL-3.0-only
# Title: Backend for fprintd_tk that uses fprintd binaries
# Purpose: In case this gets rewritten to use dbus directly or something
# Project: fprintd-tk
# History:
# Usage:
# Reference:
# Improve:
# Dependencies:
# dep-devuan: fprintd
# /usr/bin/fprintd-*
# Documentation:
# README.md
import os, subprocess, re
_user = os.getenv("USER")
fre = re.compile ("^.* - #[0-9]+: ([^ ]+)$")
prevent_success_messages = [
"no-match",
"failed to claim",
"not enrolled for user",
"enroll-duplicate"
]
def get_enrolled_fingers(user = None, verbose = False):
"""
Returns list of full strings of fingers that are enrolled for the listed user.
"""
enrolled_fingers = []
if user is None:
user = _user
if verbose:
print(f"DEBUG (get_enrolled_fingers): user {user}")
proc = subprocess.Popen(
["fprintd-list",user],
stdout = subprocess.PIPE,
universal_newlines = True # or maybe text=True
)
while True:
line = proc.stdout.readline()
if verbose:
print(f"DEBUG (get_enrolled_fingers): line {line}")
if not line:
break
if fre.match(line):
enrolled_fingers.append(fre.match(line).groups()[0].strip())
elif re.match("^.*No devices available.*", line):
return []
elif re.match("^.*has no fingers enrolled.*", line):
return ["none"]
else:
pass
return enrolled_fingers
def fprintd_action(action, finger, status_function = None, user = None, verbose = False):
if user is None:
user = _user
if action == "enroll":
command = ["fprintd-enroll","-f",finger,user]
elif action == "verify":
command = ["fprintd-verify","-f",finger,user]
elif action == "delete":
command = ["fprintd-delete",user]
else:
if status_function:
status_function(f"Invalid action {action}")
return False
if verbose:
print(f"DEBUG (fprintd_action): command {command}")
proc = subprocess.Popen(
command,
stdout = subprocess.PIPE,
universal_newlines = True
)
old_line = "INITIAL_LINE"
dupe_count = 0
while True:
line = proc.stdout.readline()
if not line:
break
display_line = line
if line == old_line:
dupe_count = dupe_count + 1
display_line = line.strip() + str(f" (x{dupe_count})")
else:
dupe_count = 1
old_line = line
if status_function:
status_function(display_line)
# If you want to react to any lines.
#if re.match("^.*verify-match (done).*",line):
# proc.kill()
# return "verify-match"
# so the process has ended, now what?
proc.kill()
if status_function:
if display_line:
display = True
for i in prevent_success_messages:
if i in display_line:
display = False
break
if display:
status_function(f"Succeeded! {display_line}")
def check_setusername_permission(status_function = None, verbose = False):
"""
This permission depends on a rule like this in /etc/polkit-1/rules.d/80-fprintd.rules:
polkit.addRule(function(action, subject) {
if (
(
action.id.match("net.reactivated.fprint.device.setusername")
) && subject.active && subject.isInGroup("admins")) {
polkit.log("action=" + action);
polkit.log("subject=" + subject);
return polkit.Result.YES;
}
});
We need to check for the ability to run `fprintd-list root` and if it does not print "not authorized", we can allow the advanced actions.
"""
proc = subprocess.Popen(
["fprintd-list","root"],
stdout = subprocess.PIPE,
universal_newlines = True # or maybe text=True
)
has_setusername = True
while True:
line = proc.stdout.readline()
if verbose:
print(f"DEBUG (check_setusername_permission): line {line}")
if not line:
break
if re.match(".*Not Authorized.*",line):
if verbose:
print(f"DEBUG (check_setusername_permission): setting has_setusername to false...")
has_setusername = False
if status_function:
status_function(f"Have advanced permissions: {has_setusername}")
return has_setusername
|