refactor!: rename to face-unlock
This commit is contained in:
1 parent
44449f103b
commit
6e6a6e6d03
66 files changed
+1709
-1709
No files matched your search
+70
-70
@@ -4,42 +4,42 @@
|
||||
#
|
||||
# The shell side never touches the camera or the face data. Those belong to
|
||||
# the daemon, and everything here that needs them asks it through
|
||||
# plasma-face-unlock-ctl. What this side does write is the user's own settings
|
||||
# face-unlock-ctl. What this side does write is the user's own settings
|
||||
# file, and (through sudo, and only when asked) the system settings and the
|
||||
# PAM files of sudo and polkit.
|
||||
|
||||
PFU_VERSION="@VERSION@"
|
||||
PFU_NAME="plasma-face-unlock"
|
||||
PFU_PRETTY="Plasma Face Unlock"
|
||||
FU_VERSION="@VERSION@"
|
||||
FU_NAME="face-unlock"
|
||||
FU_PRETTY="Face Unlock"
|
||||
|
||||
PFU_LIBDIR="${PFU_LIBDIR:-@LIBDIR@}"
|
||||
PFU_LIBEXECDIR="${PFU_LIBEXECDIR:-@LIBEXECDIR@}"
|
||||
PFU_LOCALEDIR="${PFU_LOCALEDIR:-@LOCALEDIR@}"
|
||||
PFU_PAMDIR="${PFU_PAMDIR:-@PAMDIR@}"
|
||||
FU_LIBDIR="${FU_LIBDIR:-@LIBDIR@}"
|
||||
FU_LIBEXECDIR="${FU_LIBEXECDIR:-@LIBEXECDIR@}"
|
||||
FU_LOCALEDIR="${FU_LOCALEDIR:-@LOCALEDIR@}"
|
||||
FU_PAMDIR="${FU_PAMDIR:-@PAMDIR@}"
|
||||
|
||||
PFU_CTL="${PFU_CTL:-$PFU_LIBEXECDIR/plasma-face-unlock-ctl}"
|
||||
PFU_AGENT="${PFU_AGENT:-$PFU_LIBEXECDIR/plasma-face-unlock-agent}"
|
||||
PFU_PAM_MODULE="${PFU_PAM_MODULE:-$PFU_PAMDIR/pam_plasma_face_unlock.so}"
|
||||
FU_CTL="${FU_CTL:-$FU_LIBEXECDIR/face-unlock-ctl}"
|
||||
FU_AGENT="${FU_AGENT:-$FU_LIBEXECDIR/face-unlock-agent}"
|
||||
FU_PAM_MODULE="${FU_PAM_MODULE:-$FU_PAMDIR/pam_face_unlock.so}"
|
||||
|
||||
PFU_XDG_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
PFU_CONFDIR="${PFU_CONFDIR:-${PFU_XDG_CONFIG}/${PFU_NAME}}"
|
||||
PFU_CONFIG="${PFU_CONFIG:-${PFU_CONFDIR}/config}"
|
||||
FU_XDG_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
FU_CONFDIR="${FU_CONFDIR:-${FU_XDG_CONFIG}/${FU_NAME}}"
|
||||
FU_CONFIG="${FU_CONFIG:-${FU_CONFDIR}/config}"
|
||||
|
||||
# The system settings. Only root writes them; see system.sh.
|
||||
PFU_SYSCONFIG="${PFU_SYSCONFIG:-/etc/${PFU_NAME}/config}"
|
||||
FU_SYSCONFIG="${FU_SYSCONFIG:-/etc/${FU_NAME}/config}"
|
||||
|
||||
PFU_UNIT_SOCKET="plasma-face-unlockd.socket"
|
||||
PFU_UNIT_AGENT="plasma-face-unlock-agent.service"
|
||||
FU_UNIT_SOCKET="face-unlockd.socket"
|
||||
FU_UNIT_AGENT="face-unlock-agent.service"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Translations
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
export TEXTDOMAIN="plasma-face-unlock"
|
||||
export TEXTDOMAINDIR="${PFU_LOCALEDIR}"
|
||||
export TEXTDOMAIN="face-unlock"
|
||||
export TEXTDOMAINDIR="${FU_LOCALEDIR}"
|
||||
|
||||
pfu_ui_locale() {
|
||||
local l="${PFU_UI_LOCALE:-}"
|
||||
fu_ui_locale() {
|
||||
local l="${FU_UI_LOCALE:-}"
|
||||
|
||||
if [[ -z $l ]]; then
|
||||
l="${LC_ALL:-}"
|
||||
@@ -63,53 +63,53 @@ pfu_ui_locale() {
|
||||
|
||||
# Every gettext lookup is a fork and the settings screen redraws a screenful of
|
||||
# labels per keypress, so results are memoized.
|
||||
declare -A PFU_MSG_CACHE=()
|
||||
declare -A FU_MSG_CACHE=()
|
||||
|
||||
PFU_MSG_RESULT=''
|
||||
FU_MSG_RESULT=''
|
||||
|
||||
# pfu_msg_into <locale> <msgid>
|
||||
# Plain lookup with the result in PFU_MSG_RESULT and no printf formatting, for
|
||||
# fu_msg_into <locale> <msgid>
|
||||
# Plain lookup with the result in FU_MSG_RESULT and no printf formatting, for
|
||||
# callers that would otherwise pay a fork per label per frame.
|
||||
pfu_msg_into() {
|
||||
fu_msg_into() {
|
||||
local locale="$1" msgid="$2" cachekey
|
||||
cachekey="${locale}"$'\x1f'"${msgid}"
|
||||
|
||||
if [[ -n ${PFU_MSG_CACHE[$cachekey]+set} ]]; then
|
||||
PFU_MSG_RESULT="${PFU_MSG_CACHE[$cachekey]}"
|
||||
if [[ -n ${FU_MSG_CACHE[$cachekey]+set} ]]; then
|
||||
FU_MSG_RESULT="${FU_MSG_CACHE[$cachekey]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
PFU_MSG_RESULT="$(LC_ALL="$locale" LANGUAGE="${locale%%.*}" gettext -- "$msgid" 2>/dev/null)"
|
||||
[[ -n $PFU_MSG_RESULT ]] || PFU_MSG_RESULT="$msgid"
|
||||
PFU_MSG_CACHE[$cachekey]="$PFU_MSG_RESULT"
|
||||
FU_MSG_RESULT="$(LC_ALL="$locale" LANGUAGE="${locale%%.*}" gettext -- "$msgid" 2>/dev/null)"
|
||||
[[ -n $FU_MSG_RESULT ]] || FU_MSG_RESULT="$msgid"
|
||||
FU_MSG_CACHE[$cachekey]="$FU_MSG_RESULT"
|
||||
return 0
|
||||
}
|
||||
|
||||
# pfu_msg_in <locale> <msgid> [printf args...]
|
||||
pfu_msg_in() {
|
||||
# fu_msg_in <locale> <msgid> [printf args...]
|
||||
fu_msg_in() {
|
||||
local locale="$1" msgid="$2"
|
||||
shift 2
|
||||
|
||||
pfu_msg_into "$locale" "$msgid"
|
||||
fu_msg_into "$locale" "$msgid"
|
||||
|
||||
# With no arguments the message is plain text, not a format string. Feeding
|
||||
# it to printf anyway would turn a literal percent sign in a translation
|
||||
# into an invalid conversion.
|
||||
if (( $# == 0 )); then
|
||||
printf '%s' "$PFU_MSG_RESULT"
|
||||
printf '%s' "$FU_MSG_RESULT"
|
||||
return
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2059 # the format string is the translated message
|
||||
printf -- "$PFU_MSG_RESULT" "$@"
|
||||
printf -- "$FU_MSG_RESULT" "$@"
|
||||
}
|
||||
|
||||
PFU_LOCALE_CACHED=''
|
||||
FU_LOCALE_CACHED=''
|
||||
|
||||
# pfu_msg <msgid> [printf args...]
|
||||
pfu_msg() {
|
||||
[[ -n $PFU_LOCALE_CACHED ]] || PFU_LOCALE_CACHED="$(pfu_ui_locale)"
|
||||
pfu_msg_in "$PFU_LOCALE_CACHED" "$@"
|
||||
# fu_msg <msgid> [printf args...]
|
||||
fu_msg() {
|
||||
[[ -n $FU_LOCALE_CACHED ]] || FU_LOCALE_CACHED="$(fu_ui_locale)"
|
||||
fu_msg_in "$FU_LOCALE_CACHED" "$@"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -119,45 +119,45 @@ pfu_msg() {
|
||||
# Decided once, while stdout is still whatever the process was started with:
|
||||
# testing -t 1 at the point of use is wrong for anything called through $(...),
|
||||
# which sees a pipe and would conclude nobody is watching.
|
||||
PFU_INTERACTIVE=''
|
||||
[[ -t 1 ]] && PFU_INTERACTIVE=1
|
||||
FU_INTERACTIVE=''
|
||||
[[ -t 1 ]] && FU_INTERACTIVE=1
|
||||
|
||||
if [[ -n $PFU_INTERACTIVE && -z ${NO_COLOR:-} ]]; then
|
||||
PFU_C_RESET=$'\033[0m'
|
||||
PFU_C_BOLD=$'\033[1m'
|
||||
PFU_C_DIM=$'\033[2m'
|
||||
PFU_C_BLUE=$'\033[38;2;52;153;255m'
|
||||
PFU_C_GREEN=$'\033[32m'
|
||||
PFU_C_YELLOW=$'\033[33m'
|
||||
PFU_C_RED=$'\033[31m'
|
||||
if [[ -n $FU_INTERACTIVE && -z ${NO_COLOR:-} ]]; then
|
||||
FU_C_RESET=$'\033[0m'
|
||||
FU_C_BOLD=$'\033[1m'
|
||||
FU_C_DIM=$'\033[2m'
|
||||
FU_C_BLUE=$'\033[38;2;52;153;255m'
|
||||
FU_C_GREEN=$'\033[32m'
|
||||
FU_C_YELLOW=$'\033[33m'
|
||||
FU_C_RED=$'\033[31m'
|
||||
else
|
||||
PFU_C_RESET='' PFU_C_BOLD='' PFU_C_DIM='' PFU_C_BLUE=''
|
||||
PFU_C_GREEN='' PFU_C_YELLOW='' PFU_C_RED=''
|
||||
FU_C_RESET='' FU_C_BOLD='' FU_C_DIM='' FU_C_BLUE=''
|
||||
FU_C_GREEN='' FU_C_YELLOW='' FU_C_RED=''
|
||||
fi
|
||||
|
||||
# What pfu_ok, pfu_bad and pfu_note printed. The menu redraws straight after an
|
||||
# What fu_ok, fu_bad and fu_note printed. The menu redraws straight after an
|
||||
# action, which wipes the screen, so it shows these again under the new frame
|
||||
# rather than holding everything up for a key press.
|
||||
PFU_UI_NOTICES=()
|
||||
FU_UI_NOTICES=()
|
||||
|
||||
pfu_say() { printf '%s\n' "$*"; }
|
||||
pfu_head() { printf '\n%s%s%s\n\n' "$PFU_C_BOLD$PFU_C_BLUE" "$*" "$PFU_C_RESET"; }
|
||||
pfu_ok() { PFU_UI_NOTICES+=("$PFU_C_GREEN✔$PFU_C_RESET $*"); printf '%s✔%s %s\n' "$PFU_C_GREEN" "$PFU_C_RESET" "$*"; }
|
||||
pfu_bad() { PFU_UI_NOTICES+=("$PFU_C_RED✘$PFU_C_RESET $*"); printf '%s✘%s %s\n' "$PFU_C_RED" "$PFU_C_RESET" "$*" >&2; }
|
||||
pfu_note() { PFU_UI_NOTICES+=("$PFU_C_DIM•$PFU_C_RESET $*"); printf '%s•%s %s\n' "$PFU_C_DIM" "$PFU_C_RESET" "$*"; }
|
||||
fu_say() { printf '%s\n' "$*"; }
|
||||
fu_head() { printf '\n%s%s%s\n\n' "$FU_C_BOLD$FU_C_BLUE" "$*" "$FU_C_RESET"; }
|
||||
fu_ok() { FU_UI_NOTICES+=("$FU_C_GREEN✔$FU_C_RESET $*"); printf '%s✔%s %s\n' "$FU_C_GREEN" "$FU_C_RESET" "$*"; }
|
||||
fu_bad() { FU_UI_NOTICES+=("$FU_C_RED✘$FU_C_RESET $*"); printf '%s✘%s %s\n' "$FU_C_RED" "$FU_C_RESET" "$*" >&2; }
|
||||
fu_note() { FU_UI_NOTICES+=("$FU_C_DIM•$FU_C_RESET $*"); printf '%s•%s %s\n' "$FU_C_DIM" "$FU_C_RESET" "$*"; }
|
||||
|
||||
pfu_have() { command -v "$1" > /dev/null 2>&1; }
|
||||
fu_have() { command -v "$1" > /dev/null 2>&1; }
|
||||
|
||||
# Human-readable "x minutes ago" for a unix timestamp. 0 or empty yields the
|
||||
# translated "never".
|
||||
#
|
||||
# Written with [[ ]] and a variable for each number on purpose: xgettext reads
|
||||
# the < of an (( )) as a redirection and loses every string after it.
|
||||
pfu_time_ago() {
|
||||
fu_time_ago() {
|
||||
local ts="$1" now delta n
|
||||
|
||||
if [[ ! $ts =~ ^[0-9]+$ || $ts -eq 0 ]]; then
|
||||
pfu_msg "never"
|
||||
fu_msg "never"
|
||||
printf '\n'
|
||||
return
|
||||
fi
|
||||
@@ -167,22 +167,22 @@ pfu_time_ago() {
|
||||
[[ $delta -lt 0 ]] && delta=0
|
||||
|
||||
if [[ $delta -lt 60 ]]; then
|
||||
pfu_msg "just now"
|
||||
fu_msg "just now"
|
||||
elif [[ $delta -lt 120 ]]; then
|
||||
pfu_msg "1 minute ago"
|
||||
fu_msg "1 minute ago"
|
||||
elif [[ $delta -lt 3600 ]]; then
|
||||
n=$(( delta / 60 ))
|
||||
pfu_msg "%d minutes ago" "$n"
|
||||
fu_msg "%d minutes ago" "$n"
|
||||
elif [[ $delta -lt 7200 ]]; then
|
||||
pfu_msg "1 hour ago"
|
||||
fu_msg "1 hour ago"
|
||||
elif [[ $delta -lt 86400 ]]; then
|
||||
n=$(( delta / 3600 ))
|
||||
pfu_msg "%d hours ago" "$n"
|
||||
fu_msg "%d hours ago" "$n"
|
||||
elif [[ $delta -lt 172800 ]]; then
|
||||
pfu_msg "1 day ago"
|
||||
fu_msg "1 day ago"
|
||||
else
|
||||
n=$(( delta / 86400 ))
|
||||
pfu_msg "%d days ago" "$n"
|
||||
fu_msg "%d days ago" "$n"
|
||||
fi
|
||||
printf '\n'
|
||||
}
|
||||
+34
-34
@@ -2,9 +2,9 @@
|
||||
#
|
||||
# Reading and writing the settings files.
|
||||
#
|
||||
# Two of them, in the same format: ~/.config/plasma-face-unlock/config for
|
||||
# Two of them, in the same format: ~/.config/face-unlock/config for
|
||||
# what this user wants from the lock screen and the bubble, and
|
||||
# /etc/plasma-face-unlock/config for what the daemon does (which camera, how
|
||||
# /etc/face-unlock/config for what the daemon does (which camera, how
|
||||
# strict), which only root writes. Neither is meant to be edited by hand:
|
||||
# every option is in the menu.
|
||||
#
|
||||
@@ -12,25 +12,25 @@
|
||||
# comments. The daemon and the agent read them with the same rules (see
|
||||
# src/core/keyvalue.cpp).
|
||||
|
||||
declare -A PFU_KV_CACHE=()
|
||||
declare -A FU_KV_CACHE=()
|
||||
|
||||
# _pfu_kv_lookup <file> <Key> [default]
|
||||
# Result in PFU_KV_VALUE. Assigning rather than printing matters on the
|
||||
# _fu_kv_lookup <file> <Key> [default]
|
||||
# Result in FU_KV_VALUE. Assigning rather than printing matters on the
|
||||
# settings screen, which reads every key on every frame: a command
|
||||
# substitution there is a fork, and forks are the whole cost of a redraw.
|
||||
PFU_KV_VALUE=''
|
||||
FU_KV_VALUE=''
|
||||
|
||||
_pfu_kv_lookup() {
|
||||
_fu_kv_lookup() {
|
||||
local file="$1" key="$2" default="${3:-}" val='' line content
|
||||
|
||||
PFU_KV_VALUE="$default"
|
||||
FU_KV_VALUE="$default"
|
||||
[[ -r $file ]] || return 0
|
||||
|
||||
if [[ -n ${PFU_KV_CACHE[$file]+set} ]]; then
|
||||
content="${PFU_KV_CACHE[$file]}"
|
||||
if [[ -n ${FU_KV_CACHE[$file]+set} ]]; then
|
||||
content="${FU_KV_CACHE[$file]}"
|
||||
else
|
||||
content="$(< "$file")"
|
||||
PFU_KV_CACHE[$file]="$content"
|
||||
FU_KV_CACHE[$file]="$content"
|
||||
fi
|
||||
|
||||
while IFS= read -r line; do
|
||||
@@ -45,19 +45,19 @@ _pfu_kv_lookup() {
|
||||
val="${val%\"}"
|
||||
val="${val#\"}"
|
||||
|
||||
[[ -n $val ]] && PFU_KV_VALUE="$val"
|
||||
[[ -n $val ]] && FU_KV_VALUE="$val"
|
||||
return 0
|
||||
}
|
||||
|
||||
pfu_is_true() {
|
||||
fu_is_true() {
|
||||
case "${1,,}" in
|
||||
yes|y|true|1|on|enabled) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# pfu_kv_set <file> <Key> <Value> <header line>
|
||||
pfu_kv_set() {
|
||||
# fu_kv_set <file> <Key> <Value> <header line>
|
||||
fu_kv_set() {
|
||||
local file="$1" key="$2" value="$3" header="$4" tmp
|
||||
|
||||
if [[ ! -e $file ]]; then
|
||||
@@ -65,7 +65,7 @@ pfu_kv_set() {
|
||||
{
|
||||
printf '# %s\n' "$header"
|
||||
printf '#\n'
|
||||
printf '# Written by `%s`. Nothing here needs editing by hand:\n' "$PFU_NAME"
|
||||
printf '# Written by `%s`. Nothing here needs editing by hand:\n' "$FU_NAME"
|
||||
printf '# every option is in the menu.\n'
|
||||
} > "$file" || return 1
|
||||
fi
|
||||
@@ -91,42 +91,42 @@ pfu_kv_set() {
|
||||
# Replaced, not rewritten in place: the agent watches the directory and
|
||||
# picks up the new file the moment it lands.
|
||||
mv -f "$tmp" "$file"
|
||||
unset 'PFU_KV_CACHE[$file]'
|
||||
unset 'FU_KV_CACHE[$file]'
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# This user's settings
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
pfu_config_get() {
|
||||
_pfu_kv_lookup "$PFU_CONFIG" "$@"
|
||||
printf '%s\n' "$PFU_KV_VALUE"
|
||||
fu_config_get() {
|
||||
_fu_kv_lookup "$FU_CONFIG" "$@"
|
||||
printf '%s\n' "$FU_KV_VALUE"
|
||||
}
|
||||
|
||||
pfu_config_set() {
|
||||
pfu_kv_set "$PFU_CONFIG" "$1" "$2" "$PFU_PRETTY"
|
||||
fu_config_set() {
|
||||
fu_kv_set "$FU_CONFIG" "$1" "$2" "$FU_PRETTY"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The system settings (read by anybody, written by root)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
pfu_sys_get() {
|
||||
_pfu_kv_lookup "$PFU_SYSCONFIG" "$@"
|
||||
printf '%s\n' "$PFU_KV_VALUE"
|
||||
fu_sys_get() {
|
||||
_fu_kv_lookup "$FU_SYSCONFIG" "$@"
|
||||
printf '%s\n' "$FU_KV_VALUE"
|
||||
}
|
||||
|
||||
# pfu_config_load
|
||||
# fu_config_load
|
||||
# Everything the menu shows, resolved once per screen.
|
||||
pfu_config_load() {
|
||||
PFU_KV_CACHE=()
|
||||
fu_config_load() {
|
||||
FU_KV_CACHE=()
|
||||
|
||||
_pfu_kv_lookup "$PFU_CONFIG" Enabled no; CFG_ENABLED=no; pfu_is_true "$PFU_KV_VALUE" && CFG_ENABLED=yes
|
||||
_pfu_kv_lookup "$PFU_CONFIG" LockScreen yes; CFG_LOCK=no; pfu_is_true "$PFU_KV_VALUE" && CFG_LOCK=yes
|
||||
_pfu_kv_lookup "$PFU_CONFIG" Sudo no; CFG_SUDO=no; pfu_is_true "$PFU_KV_VALUE" && CFG_SUDO=yes
|
||||
_pfu_kv_lookup "$PFU_CONFIG" Polkit no; CFG_POLKIT=no; pfu_is_true "$PFU_KV_VALUE" && CFG_POLKIT=yes
|
||||
_fu_kv_lookup "$FU_CONFIG" Enabled no; CFG_ENABLED=no; fu_is_true "$FU_KV_VALUE" && CFG_ENABLED=yes
|
||||
_fu_kv_lookup "$FU_CONFIG" LockScreen yes; CFG_LOCK=no; fu_is_true "$FU_KV_VALUE" && CFG_LOCK=yes
|
||||
_fu_kv_lookup "$FU_CONFIG" Sudo no; CFG_SUDO=no; fu_is_true "$FU_KV_VALUE" && CFG_SUDO=yes
|
||||
_fu_kv_lookup "$FU_CONFIG" Polkit no; CFG_POLKIT=no; fu_is_true "$FU_KV_VALUE" && CFG_POLKIT=yes
|
||||
|
||||
_pfu_kv_lookup "$PFU_SYSCONFIG" Liveness light; CFG_LIVENESS="$PFU_KV_VALUE"
|
||||
_pfu_kv_lookup "$PFU_SYSCONFIG" Camera auto; CFG_CAMERA="$PFU_KV_VALUE"
|
||||
_fu_kv_lookup "$FU_SYSCONFIG" Liveness light; CFG_LIVENESS="$FU_KV_VALUE"
|
||||
_fu_kv_lookup "$FU_SYSCONFIG" Camera auto; CFG_CAMERA="$FU_KV_VALUE"
|
||||
return 0
|
||||
}
|
||||
+103
-103
@@ -2,184 +2,184 @@
|
||||
#
|
||||
# Asking the daemon.
|
||||
#
|
||||
# Through plasma-face-unlock-ctl, which prints every message as a line of tab
|
||||
# Through face-unlock-ctl, which prints every message as a line of tab
|
||||
# separated key=value pairs (see src/ctl/main.cpp). What comes back is parsed
|
||||
# into plain variables and arrays here, so the rest of the shell code never
|
||||
# sees the wire format.
|
||||
|
||||
# _pfu_fields <line>
|
||||
# Splits one line of ctl output into the associative array PFU_F.
|
||||
declare -A PFU_F=()
|
||||
# _fu_fields <line>
|
||||
# Splits one line of ctl output into the associative array FU_F.
|
||||
declare -A FU_F=()
|
||||
|
||||
_pfu_fields() {
|
||||
_fu_fields() {
|
||||
local line="$1" field
|
||||
local -a parts
|
||||
PFU_F=()
|
||||
FU_F=()
|
||||
IFS=$'\t' read -r -a parts <<< "$line"
|
||||
for field in "${parts[@]}"; do
|
||||
PFU_F["${field%%=*}"]="${field#*=}"
|
||||
FU_F["${field%%=*}"]="${field#*=}"
|
||||
done
|
||||
}
|
||||
|
||||
pfu_ctl() {
|
||||
"$PFU_CTL" "$@"
|
||||
fu_ctl() {
|
||||
"$FU_CTL" "$@"
|
||||
}
|
||||
|
||||
# pfu_status_load
|
||||
# PFU_ST_REACHABLE is yes when the daemon answered at all. Everything else
|
||||
# fu_status_load
|
||||
# FU_ST_REACHABLE is yes when the daemon answered at all. Everything else
|
||||
# is only filled in then.
|
||||
pfu_status_load() {
|
||||
fu_status_load() {
|
||||
local out
|
||||
PFU_ST_REACHABLE=no
|
||||
PFU_ST_FACES=0
|
||||
PFU_ST_LOCKOUT=0
|
||||
PFU_ST_LAST=0
|
||||
PFU_ST_PURPOSE=''
|
||||
PFU_ST_CAMERA=''
|
||||
PFU_ST_CAMERA_NAME=''
|
||||
PFU_ST_CAMERA_PRESENT=no
|
||||
PFU_ST_MODELS=no
|
||||
FU_ST_REACHABLE=no
|
||||
FU_ST_FACES=0
|
||||
FU_ST_LOCKOUT=0
|
||||
FU_ST_LAST=0
|
||||
FU_ST_PURPOSE=''
|
||||
FU_ST_CAMERA=''
|
||||
FU_ST_CAMERA_NAME=''
|
||||
FU_ST_CAMERA_PRESENT=no
|
||||
FU_ST_MODELS=no
|
||||
|
||||
out="$(pfu_ctl status 2>/dev/null | tail -n1)"
|
||||
_pfu_fields "$out"
|
||||
[[ ${PFU_F[ok]:-} == true ]] || return 1
|
||||
out="$(fu_ctl status 2>/dev/null | tail -n1)"
|
||||
_fu_fields "$out"
|
||||
[[ ${FU_F[ok]:-} == true ]] || return 1
|
||||
|
||||
PFU_ST_REACHABLE=yes
|
||||
PFU_ST_FACES="${PFU_F[faces]:-0}"
|
||||
PFU_ST_LOCKOUT="${PFU_F[lockout]:-0}"
|
||||
PFU_ST_LAST="${PFU_F[lastUnlock]:-0}"
|
||||
PFU_ST_PURPOSE="${PFU_F[lastPurpose]:-}"
|
||||
PFU_ST_CAMERA="${PFU_F[cameraPath]:-}"
|
||||
PFU_ST_CAMERA_NAME="${PFU_F[cameraName]:-}"
|
||||
PFU_ST_CAMERA_PRESENT="${PFU_F[cameraPresent]:-false}"
|
||||
PFU_ST_MODELS="${PFU_F[models]:-false}"
|
||||
FU_ST_REACHABLE=yes
|
||||
FU_ST_FACES="${FU_F[faces]:-0}"
|
||||
FU_ST_LOCKOUT="${FU_F[lockout]:-0}"
|
||||
FU_ST_LAST="${FU_F[lastUnlock]:-0}"
|
||||
FU_ST_PURPOSE="${FU_F[lastPurpose]:-}"
|
||||
FU_ST_CAMERA="${FU_F[cameraPath]:-}"
|
||||
FU_ST_CAMERA_NAME="${FU_F[cameraName]:-}"
|
||||
FU_ST_CAMERA_PRESENT="${FU_F[cameraPresent]:-false}"
|
||||
FU_ST_MODELS="${FU_F[models]:-false}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# pfu_faces_load
|
||||
# fu_faces_load
|
||||
# The caller's faces, into parallel arrays.
|
||||
pfu_faces_load() {
|
||||
fu_faces_load() {
|
||||
local line
|
||||
PFU_FACE_IDS=() PFU_FACE_NAMES=() PFU_FACE_ON=() PFU_FACE_SAMPLES=() PFU_FACE_LEARNED=() PFU_FACE_CREATED=()
|
||||
FU_FACE_IDS=() FU_FACE_NAMES=() FU_FACE_ON=() FU_FACE_SAMPLES=() FU_FACE_LEARNED=() FU_FACE_CREATED=()
|
||||
|
||||
while IFS= read -r line; do
|
||||
_pfu_fields "$line"
|
||||
[[ ${PFU_F[event]:-} == item ]] || continue
|
||||
PFU_FACE_IDS+=("${PFU_F[id]}")
|
||||
PFU_FACE_NAMES+=("${PFU_F[name]}")
|
||||
PFU_FACE_ON+=("${PFU_F[enabled]}")
|
||||
PFU_FACE_SAMPLES+=("${PFU_F[samples]:-0}")
|
||||
PFU_FACE_LEARNED+=("${PFU_F[adaptive]:-0}")
|
||||
PFU_FACE_CREATED+=("${PFU_F[created]:-0}")
|
||||
done < <(pfu_ctl list 2>/dev/null)
|
||||
_fu_fields "$line"
|
||||
[[ ${FU_F[event]:-} == item ]] || continue
|
||||
FU_FACE_IDS+=("${FU_F[id]}")
|
||||
FU_FACE_NAMES+=("${FU_F[name]}")
|
||||
FU_FACE_ON+=("${FU_F[enabled]}")
|
||||
FU_FACE_SAMPLES+=("${FU_F[samples]:-0}")
|
||||
FU_FACE_LEARNED+=("${FU_F[adaptive]:-0}")
|
||||
FU_FACE_CREATED+=("${FU_F[created]:-0}")
|
||||
done < <(fu_ctl list 2>/dev/null)
|
||||
}
|
||||
|
||||
# pfu_cameras_load
|
||||
pfu_cameras_load() {
|
||||
# fu_cameras_load
|
||||
fu_cameras_load() {
|
||||
local line
|
||||
PFU_CAM_PATHS=() PFU_CAM_NAMES=() PFU_CAM_IR=()
|
||||
PFU_CAM_AUTO=''
|
||||
FU_CAM_PATHS=() FU_CAM_NAMES=() FU_CAM_IR=()
|
||||
FU_CAM_AUTO=''
|
||||
|
||||
while IFS= read -r line; do
|
||||
_pfu_fields "$line"
|
||||
case "${PFU_F[event]:-}" in
|
||||
_fu_fields "$line"
|
||||
case "${FU_F[event]:-}" in
|
||||
item)
|
||||
PFU_CAM_PATHS+=("${PFU_F[path]}")
|
||||
PFU_CAM_NAMES+=("${PFU_F[name]}")
|
||||
PFU_CAM_IR+=("${PFU_F[infrared]}")
|
||||
FU_CAM_PATHS+=("${FU_F[path]}")
|
||||
FU_CAM_NAMES+=("${FU_F[name]}")
|
||||
FU_CAM_IR+=("${FU_F[infrared]}")
|
||||
;;
|
||||
result)
|
||||
PFU_CAM_AUTO="${PFU_F[auto]:-}"
|
||||
FU_CAM_AUTO="${FU_F[auto]:-}"
|
||||
;;
|
||||
esac
|
||||
done < <(pfu_ctl cameras 2>/dev/null)
|
||||
done < <(fu_ctl cameras 2>/dev/null)
|
||||
}
|
||||
|
||||
# pfu_reason_text <reason>
|
||||
# fu_reason_text <reason>
|
||||
# What a daemon answer means, for people.
|
||||
pfu_reason_text() {
|
||||
fu_reason_text() {
|
||||
case "$1" in
|
||||
mismatch) pfu_msg "The face did not match." ;;
|
||||
spoof) pfu_msg "That looked like a photo or a screen." ;;
|
||||
liveness) pfu_msg "The face matched, but did not blink or move." ;;
|
||||
attention) pfu_msg "The face was not looking at the screen." ;;
|
||||
quality) pfu_msg "The picture was too dark, too blurry or too far away." ;;
|
||||
no-face) pfu_msg "No face in view." ;;
|
||||
lockout) pfu_msg "Face unlock is paused after too many tries. Unlock once with your password." ;;
|
||||
not-enrolled) pfu_msg "No face is set up yet." ;;
|
||||
camera) pfu_msg "The camera could not be used." ;;
|
||||
models) pfu_msg "The recognition models are missing. Reinstall the package." ;;
|
||||
lid-closed) pfu_msg "The lid is closed." ;;
|
||||
busy) pfu_msg "The camera is busy with another scan." ;;
|
||||
unreachable) pfu_msg "The face unlock service is not running." ;;
|
||||
denied) pfu_msg "Not allowed." ;;
|
||||
*) pfu_msg "Something went wrong (%s)." "$1" ;;
|
||||
mismatch) fu_msg "The face did not match." ;;
|
||||
spoof) fu_msg "That looked like a photo or a screen." ;;
|
||||
liveness) fu_msg "The face matched, but did not blink or move." ;;
|
||||
attention) fu_msg "The face was not looking at the screen." ;;
|
||||
quality) fu_msg "The picture was too dark, too blurry or too far away." ;;
|
||||
no-face) fu_msg "No face in view." ;;
|
||||
lockout) fu_msg "Face unlock is paused after too many tries. Unlock once with your password." ;;
|
||||
not-enrolled) fu_msg "No face is set up yet." ;;
|
||||
camera) fu_msg "The camera could not be used." ;;
|
||||
models) fu_msg "The recognition models are missing. Reinstall the package." ;;
|
||||
lid-closed) fu_msg "The lid is closed." ;;
|
||||
busy) fu_msg "The camera is busy with another scan." ;;
|
||||
unreachable) fu_msg "The face unlock service is not running." ;;
|
||||
denied) fu_msg "Not allowed." ;;
|
||||
*) fu_msg "Something went wrong (%s)." "$1" ;;
|
||||
esac
|
||||
printf '\n'
|
||||
}
|
||||
|
||||
# pfu_test
|
||||
# fu_test
|
||||
# One scan, with everything the checks see on one line that keeps updating.
|
||||
# The bubble shows it too, if the agent is running.
|
||||
pfu_test() {
|
||||
fu_test() {
|
||||
local line started=0 shown='' score='-' matched=0
|
||||
|
||||
pfu_say " $(pfu_msg "Look at the camera. Blink once, or turn your head a little.")"
|
||||
fu_say " $(fu_msg "Look at the camera. Blink once, or turn your head a little.")"
|
||||
printf '\n'
|
||||
|
||||
while IFS= read -r line; do
|
||||
_pfu_fields "$line"
|
||||
case "${PFU_F[event]:-}" in
|
||||
_fu_fields "$line"
|
||||
case "${FU_F[event]:-}" in
|
||||
started)
|
||||
started=1
|
||||
;;
|
||||
face)
|
||||
printf '\r\033[K %s\n' "$(pfu_msg "Face found.")"
|
||||
printf '\r\033[K %s\n' "$(fu_msg "Face found.")"
|
||||
;;
|
||||
hint)
|
||||
case "${PFU_F[hint]}" in
|
||||
blink) printf '\r\033[K %s\n' "$(pfu_msg "Recognised. Now blink once, or turn your head a little.")" ;;
|
||||
look) printf '\r\033[K %s\n' "$(pfu_msg "Look at the screen.")" ;;
|
||||
closer) printf '\r\033[K %s\n' "$(pfu_msg "Move closer to the camera.")" ;;
|
||||
light) printf '\r\033[K %s\n' "$(pfu_msg "It is too dark to see your face.")" ;;
|
||||
case "${FU_F[hint]}" in
|
||||
blink) printf '\r\033[K %s\n' "$(fu_msg "Recognised. Now blink once, or turn your head a little.")" ;;
|
||||
look) printf '\r\033[K %s\n' "$(fu_msg "Look at the screen.")" ;;
|
||||
closer) printf '\r\033[K %s\n' "$(fu_msg "Move closer to the camera.")" ;;
|
||||
light) printf '\r\033[K %s\n' "$(fu_msg "It is too dark to see your face.")" ;;
|
||||
esac
|
||||
;;
|
||||
frame)
|
||||
[[ -n ${PFU_F[score]:-} ]] && score="${PFU_F[score]}"
|
||||
matched="${PFU_F[matched]:-0}"
|
||||
[[ -n ${FU_F[score]:-} ]] && score="${FU_F[score]}"
|
||||
matched="${FU_F[matched]:-0}"
|
||||
# match, turn of the head, eyes, and how close each photo check is
|
||||
# to firing, as numbers for anybody tuning it.
|
||||
printf -v shown ' %s %-6s %s %5s° %s %-5s %s %-4s %s %-4s %s %-4s %s %-4s' \
|
||||
"$(pfu_msg "match")" "$score" "$(pfu_msg "turn")" "${PFU_F[yaw]:-0}" \
|
||||
"$(pfu_msg "eyes")" "${PFU_F[eyes]:-0}" \
|
||||
"$(pfu_msg "depth")" "${PFU_F[depth]:-0}" "$(pfu_msg "blink")" "${PFU_F[blink]:-0}" \
|
||||
"$(pfu_msg "glare")" "${PFU_F[glare]:-0}" "$(pfu_msg "edge")" "${PFU_F[device]:-0}"
|
||||
[[ -n $PFU_INTERACTIVE ]] && printf '\r\033[K%s%s%s' "$PFU_C_DIM" "$shown" "$PFU_C_RESET"
|
||||
"$(fu_msg "match")" "$score" "$(fu_msg "turn")" "${FU_F[yaw]:-0}" \
|
||||
"$(fu_msg "eyes")" "${FU_F[eyes]:-0}" \
|
||||
"$(fu_msg "depth")" "${FU_F[depth]:-0}" "$(fu_msg "blink")" "${FU_F[blink]:-0}" \
|
||||
"$(fu_msg "glare")" "${FU_F[glare]:-0}" "$(fu_msg "edge")" "${FU_F[device]:-0}"
|
||||
[[ -n $FU_INTERACTIVE ]] && printf '\r\033[K%s%s%s' "$FU_C_DIM" "$shown" "$FU_C_RESET"
|
||||
;;
|
||||
result)
|
||||
printf '\r\033[K'
|
||||
if [[ ${PFU_F[ok]} == true ]]; then
|
||||
if [[ ${FU_F[ok]} == true ]]; then
|
||||
local how=''
|
||||
case "${PFU_F[liveness]:-}" in
|
||||
blink) how="$(pfu_msg "blink")" ;;
|
||||
depth) how="$(pfu_msg "head turn")" ;;
|
||||
case "${FU_F[liveness]:-}" in
|
||||
blink) how="$(fu_msg "blink")" ;;
|
||||
depth) how="$(fu_msg "head turn")" ;;
|
||||
esac
|
||||
pfu_ok "$(pfu_msg "Recognised as %s (match %s) in %s ms." "${PFU_F[name]}" "${PFU_F[score]}" "${PFU_F[ms]}")"
|
||||
[[ -n $how ]] && pfu_say " $(pfu_msg "Sign of life: %s" "$how")"
|
||||
fu_ok "$(fu_msg "Recognised as %s (match %s) in %s ms." "${FU_F[name]}" "${FU_F[score]}" "${FU_F[ms]}")"
|
||||
[[ -n $how ]] && fu_say " $(fu_msg "Sign of life: %s" "$how")"
|
||||
else
|
||||
pfu_bad "$(pfu_reason_text "${PFU_F[reason]}")"
|
||||
[[ -n ${PFU_F[message]:-} ]] && pfu_say " ${PFU_F[message]}"
|
||||
if [[ -n ${PFU_F[lockout]:-} ]]; then
|
||||
pfu_note "$(pfu_msg "That was too many tries. Face unlock is paused until you unlock with your password.")"
|
||||
fu_bad "$(fu_reason_text "${FU_F[reason]}")"
|
||||
[[ -n ${FU_F[message]:-} ]] && fu_say " ${FU_F[message]}"
|
||||
if [[ -n ${FU_F[lockout]:-} ]]; then
|
||||
fu_note "$(fu_msg "That was too many tries. Face unlock is paused until you unlock with your password.")"
|
||||
fi
|
||||
fi
|
||||
(( started )) || true
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done < <(pfu_ctl test 2>/dev/null)
|
||||
done < <(fu_ctl test 2>/dev/null)
|
||||
|
||||
printf '\n'
|
||||
pfu_bad "$(pfu_reason_text unreachable)"
|
||||
fu_bad "$(fu_reason_text unreachable)"
|
||||
return 1
|
||||
}
|
||||
+265
-265
@@ -14,39 +14,39 @@
|
||||
# character, so the line discipline eats it instead of delivering it, and a
|
||||
# backspace typed while the interface was between reads simply vanishes.
|
||||
# Holding non-canonical mode for the whole interface removes the gap.
|
||||
PFU_TERM_SAVED=''
|
||||
FU_TERM_SAVED=''
|
||||
|
||||
pfu_ui_term_raw() {
|
||||
pfu_have stty || return 0
|
||||
fu_ui_term_raw() {
|
||||
fu_have stty || return 0
|
||||
[[ -t 0 ]] || return 0
|
||||
[[ -n $PFU_TERM_SAVED ]] && return 0
|
||||
[[ -n $FU_TERM_SAVED ]] && return 0
|
||||
|
||||
PFU_TERM_SAVED="$(stty -g 2>/dev/null)" || { PFU_TERM_SAVED=''; return 0; }
|
||||
FU_TERM_SAVED="$(stty -g 2>/dev/null)" || { FU_TERM_SAVED=''; return 0; }
|
||||
stty -icanon -echo min 1 time 0 2>/dev/null || true
|
||||
}
|
||||
|
||||
pfu_ui_term_restore() {
|
||||
[[ -n $PFU_TERM_SAVED ]] || return 0
|
||||
stty "$PFU_TERM_SAVED" 2>/dev/null || true
|
||||
PFU_TERM_SAVED=''
|
||||
fu_ui_term_restore() {
|
||||
[[ -n $FU_TERM_SAVED ]] || return 0
|
||||
stty "$FU_TERM_SAVED" 2>/dev/null || true
|
||||
FU_TERM_SAVED=''
|
||||
}
|
||||
|
||||
# Runs an action with the terminal handed back to normal line mode, so anything
|
||||
# it prints or prompts for (sudo's password prompt, above all) behaves the way
|
||||
# a program expects.
|
||||
pfu_ui_cooked() {
|
||||
pfu_ui_term_restore
|
||||
fu_ui_cooked() {
|
||||
fu_ui_term_restore
|
||||
"$@"
|
||||
local rc=$?
|
||||
pfu_ui_term_raw
|
||||
fu_ui_term_raw
|
||||
return $rc
|
||||
}
|
||||
|
||||
# pfu_read_key
|
||||
# fu_read_key
|
||||
# One keypress, resolved to a symbolic name. Arrow keys arrive as ESC [ A, so
|
||||
# the tail of the sequence is consumed here rather than being mistaken for
|
||||
# three separate presses.
|
||||
pfu_read_key() {
|
||||
fu_read_key() {
|
||||
local k rest
|
||||
|
||||
IFS= read -rsn1 k || return 1
|
||||
@@ -72,26 +72,26 @@ pfu_read_key() {
|
||||
esac
|
||||
}
|
||||
|
||||
# pfu_ui_read_line <initial>
|
||||
# A minimal line editor built on pfu_read_key, with the result in
|
||||
# PFU_LINE_RESULT. This exists instead of bash's own `read -r` because mixing
|
||||
# fu_ui_read_line <initial>
|
||||
# A minimal line editor built on fu_read_key, with the result in
|
||||
# FU_LINE_RESULT. This exists instead of bash's own `read -r` because mixing
|
||||
# line mode into a single-key interface breaks it: after one cooked-mode read
|
||||
# the following `read -sn1` stops receiving keystrokes entirely.
|
||||
PFU_LINE_RESULT=''
|
||||
FU_LINE_RESULT=''
|
||||
|
||||
pfu_ui_read_line() {
|
||||
fu_ui_read_line() {
|
||||
local buf="${1:-}" key
|
||||
|
||||
PFU_LINE_RESULT=''
|
||||
FU_LINE_RESULT=''
|
||||
printf '%s' "$buf"
|
||||
|
||||
while true; do
|
||||
key="$(pfu_read_key)" || { printf '\n'; return 1; }
|
||||
key="$(fu_read_key)" || { printf '\n'; return 1; }
|
||||
|
||||
case "$key" in
|
||||
enter)
|
||||
printf '\n'
|
||||
PFU_LINE_RESULT="$buf"
|
||||
FU_LINE_RESULT="$buf"
|
||||
return 0
|
||||
;;
|
||||
escape)
|
||||
@@ -118,88 +118,88 @@ pfu_ui_read_line() {
|
||||
done
|
||||
}
|
||||
|
||||
# _pfu_ui_take_notices
|
||||
# _fu_ui_take_notices
|
||||
# The messages the last action left, as lines for under a frame, in
|
||||
# PFU_UI_NOTICE_TEXT. Each is shown once.
|
||||
PFU_UI_NOTICE_TEXT=''
|
||||
# FU_UI_NOTICE_TEXT. Each is shown once.
|
||||
FU_UI_NOTICE_TEXT=''
|
||||
|
||||
_pfu_ui_take_notices() {
|
||||
_fu_ui_take_notices() {
|
||||
local n
|
||||
PFU_UI_NOTICE_TEXT=''
|
||||
(( ${#PFU_UI_NOTICES[@]} )) || return 0
|
||||
PFU_UI_NOTICE_TEXT=$'\n'
|
||||
for n in "${PFU_UI_NOTICES[@]}"; do
|
||||
PFU_UI_NOTICE_TEXT+=" $n"$'\n'
|
||||
FU_UI_NOTICE_TEXT=''
|
||||
(( ${#FU_UI_NOTICES[@]} )) || return 0
|
||||
FU_UI_NOTICE_TEXT=$'\n'
|
||||
for n in "${FU_UI_NOTICES[@]}"; do
|
||||
FU_UI_NOTICE_TEXT+=" $n"$'\n'
|
||||
done
|
||||
PFU_UI_NOTICES=()
|
||||
FU_UI_NOTICES=()
|
||||
}
|
||||
|
||||
# pfu_ui_confirm <question>
|
||||
pfu_ui_confirm() {
|
||||
# fu_ui_confirm <question>
|
||||
fu_ui_confirm() {
|
||||
local key hint yes
|
||||
# TRANSLATORS: the letter after "[" is the key for yes. y works too.
|
||||
hint="$(pfu_msg "[y/N]")"
|
||||
hint="$(fu_msg "[y/N]")"
|
||||
yes="${hint:1:1}"
|
||||
printf '\n %s %s ' "$1" "$hint"
|
||||
key="$(pfu_read_key)" || return 1
|
||||
key="$(fu_read_key)" || return 1
|
||||
printf '%s\n' "$key"
|
||||
[[ ${key,,} == y || ${key,,} == "${yes,,}" ]]
|
||||
}
|
||||
|
||||
# _pfu_width <text>
|
||||
# The columns the text takes, into PFU_WIDTH. ${#s} counts characters, but
|
||||
# _fu_width <text>
|
||||
# The columns the text takes, into FU_WIDTH. ${#s} counts characters, but
|
||||
# Chinese, Japanese and Korean ones take two columns each.
|
||||
PFU_WIDTH=0
|
||||
FU_WIDTH=0
|
||||
|
||||
_pfu_width() {
|
||||
_fu_width() {
|
||||
local wide="${1//[^ -〿-ヿ㐀-䶿一-鿿가-豈--⦆]/}"
|
||||
PFU_WIDTH=$(( ${#1} + ${#wide} ))
|
||||
FU_WIDTH=$(( ${#1} + ${#wide} ))
|
||||
}
|
||||
|
||||
# _pfu_row <label> <value>
|
||||
# _fu_row <label> <value>
|
||||
# printf's %-28s pads by bytes, so a label containing "ü" comes out one column
|
||||
# short. The padding is computed here instead.
|
||||
_pfu_row() {
|
||||
_fu_row() {
|
||||
local label="$1" value="$2" pad
|
||||
_pfu_width "$label"
|
||||
pad=$(( 30 - PFU_WIDTH ))
|
||||
_fu_width "$label"
|
||||
pad=$(( 30 - FU_WIDTH ))
|
||||
(( pad < 0 )) && pad=0
|
||||
printf ' %s%*s %s\n' "$label" "$pad" '' "$value"
|
||||
}
|
||||
|
||||
_pfu_onoff() {
|
||||
_fu_onoff() {
|
||||
if [[ $1 == yes ]]; then
|
||||
printf '%s%s%s' "$PFU_C_GREEN" "$(pfu_msg "ON")" "$PFU_C_RESET"
|
||||
printf '%s%s%s' "$FU_C_GREEN" "$(fu_msg "ON")" "$FU_C_RESET"
|
||||
else
|
||||
printf '%s%s%s' "$PFU_C_DIM" "$(pfu_msg "OFF")" "$PFU_C_RESET"
|
||||
printf '%s%s%s' "$FU_C_DIM" "$(fu_msg "OFF")" "$FU_C_RESET"
|
||||
fi
|
||||
}
|
||||
|
||||
_pfu_small_onoff() {
|
||||
_fu_small_onoff() {
|
||||
if [[ $1 == yes ]]; then
|
||||
printf '%s%s%s' "$PFU_C_GREEN" "$(pfu_msg "on")" "$PFU_C_RESET"
|
||||
printf '%s%s%s' "$FU_C_GREEN" "$(fu_msg "on")" "$FU_C_RESET"
|
||||
else
|
||||
printf '%s%s%s' "$PFU_C_DIM" "$(pfu_msg "off")" "$PFU_C_RESET"
|
||||
printf '%s%s%s' "$FU_C_DIM" "$(fu_msg "off")" "$FU_C_RESET"
|
||||
fi
|
||||
}
|
||||
|
||||
# pfu_value_label <Key> <value>
|
||||
# fu_value_label <Key> <value>
|
||||
# How a setting's value reads in the menu.
|
||||
pfu_value_label() {
|
||||
fu_value_label() {
|
||||
case "$1:$2" in
|
||||
Liveness:heavy) pfu_msg "strict" ;;
|
||||
Liveness:light) pfu_msg "basic" ;;
|
||||
Liveness:off) pfu_msg "off" ;;
|
||||
Strictness:normal) pfu_msg "normal" ;;
|
||||
Strictness:strict) pfu_msg "strict" ;;
|
||||
Strictness:relaxed) pfu_msg "relaxed" ;;
|
||||
BubbleStyle:full) pfu_msg "island with the face" ;;
|
||||
BubbleStyle:minimal) pfu_msg "small pill with a lock" ;;
|
||||
AnimationSpeed:normal) pfu_msg "normal" ;;
|
||||
AnimationSpeed:fast) pfu_msg "fast" ;;
|
||||
AnimationSpeed:slow) pfu_msg "slow" ;;
|
||||
ScanSeconds:*) pfu_msg "%s seconds" "$2" ;;
|
||||
Camera:auto) pfu_msg "automatic" ;;
|
||||
Liveness:heavy) fu_msg "strict" ;;
|
||||
Liveness:light) fu_msg "basic" ;;
|
||||
Liveness:off) fu_msg "off" ;;
|
||||
Strictness:normal) fu_msg "normal" ;;
|
||||
Strictness:strict) fu_msg "strict" ;;
|
||||
Strictness:relaxed) fu_msg "relaxed" ;;
|
||||
BubbleStyle:full) fu_msg "island with the face" ;;
|
||||
BubbleStyle:minimal) fu_msg "small pill with a lock" ;;
|
||||
AnimationSpeed:normal) fu_msg "normal" ;;
|
||||
AnimationSpeed:fast) fu_msg "fast" ;;
|
||||
AnimationSpeed:slow) fu_msg "slow" ;;
|
||||
ScanSeconds:*) fu_msg "%s seconds" "$2" ;;
|
||||
Camera:auto) fu_msg "automatic" ;;
|
||||
*) printf '%s' "$2" ;;
|
||||
esac
|
||||
}
|
||||
@@ -208,55 +208,55 @@ pfu_value_label() {
|
||||
# Status
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# pfu_ui_status
|
||||
# fu_ui_status
|
||||
# Shared by the `status` subcommand and the menu header.
|
||||
pfu_ui_status() {
|
||||
fu_ui_status() {
|
||||
local names='' i camera
|
||||
|
||||
pfu_config_load
|
||||
pfu_status_load
|
||||
fu_config_load
|
||||
fu_status_load
|
||||
|
||||
_pfu_row "$(pfu_msg "Face unlock")" "$(_pfu_onoff "$CFG_ENABLED")"
|
||||
_fu_row "$(fu_msg "Face unlock")" "$(_fu_onoff "$CFG_ENABLED")"
|
||||
printf '\n'
|
||||
|
||||
if [[ $PFU_ST_REACHABLE != yes ]]; then
|
||||
_pfu_row "$(pfu_msg "Service")" "${PFU_C_YELLOW}$(pfu_msg "not running")${PFU_C_RESET}"
|
||||
if [[ $FU_ST_REACHABLE != yes ]]; then
|
||||
_fu_row "$(fu_msg "Service")" "${FU_C_YELLOW}$(fu_msg "not running")${FU_C_RESET}"
|
||||
if [[ $CFG_ENABLED == yes ]]; then
|
||||
printf '\n %s%s%s\n' "$PFU_C_DIM" "$(pfu_msg "Turning face unlock on again starts it.")" "$PFU_C_RESET"
|
||||
printf '\n %s%s%s\n' "$FU_C_DIM" "$(fu_msg "Turning face unlock on again starts it.")" "$FU_C_RESET"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
pfu_faces_load
|
||||
for i in "${!PFU_FACE_NAMES[@]}"; do
|
||||
[[ ${PFU_FACE_ON[i]} == true ]] || continue
|
||||
names="${names:+$names, }${PFU_FACE_NAMES[i]}"
|
||||
fu_faces_load
|
||||
for i in "${!FU_FACE_NAMES[@]}"; do
|
||||
[[ ${FU_FACE_ON[i]} == true ]] || continue
|
||||
names="${names:+$names, }${FU_FACE_NAMES[i]}"
|
||||
done
|
||||
if (( ${#PFU_FACE_IDS[@]} == 0 )); then
|
||||
_pfu_row "$(pfu_msg "Faces")" "${PFU_C_YELLOW}$(pfu_msg "none set up yet")${PFU_C_RESET}"
|
||||
if (( ${#FU_FACE_IDS[@]} == 0 )); then
|
||||
_fu_row "$(fu_msg "Faces")" "${FU_C_YELLOW}$(fu_msg "none set up yet")${FU_C_RESET}"
|
||||
else
|
||||
_pfu_row "$(pfu_msg "Faces")" "${PFU_ST_FACES} ${PFU_C_DIM}(${names:-$(pfu_msg "all turned off")})${PFU_C_RESET}"
|
||||
_fu_row "$(fu_msg "Faces")" "${FU_ST_FACES} ${FU_C_DIM}(${names:-$(fu_msg "all turned off")})${FU_C_RESET}"
|
||||
fi
|
||||
|
||||
if [[ $PFU_ST_CAMERA_PRESENT == true ]]; then
|
||||
camera="${PFU_ST_CAMERA_NAME:-$PFU_ST_CAMERA}"
|
||||
if [[ $FU_ST_CAMERA_PRESENT == true ]]; then
|
||||
camera="${FU_ST_CAMERA_NAME:-$FU_ST_CAMERA}"
|
||||
else
|
||||
camera="${PFU_C_YELLOW}$(pfu_msg "none found")${PFU_C_RESET}"
|
||||
camera="${FU_C_YELLOW}$(fu_msg "none found")${FU_C_RESET}"
|
||||
fi
|
||||
_pfu_row "$(pfu_msg "Camera")" "$camera"
|
||||
_fu_row "$(fu_msg "Camera")" "$camera"
|
||||
|
||||
_pfu_row "$(pfu_msg "Lock screen")" "$(_pfu_small_onoff "$( [[ $CFG_ENABLED == yes && $CFG_LOCK == yes ]] && echo yes || echo no)")"
|
||||
_pfu_row "$(pfu_msg "sudo")" "$(_pfu_small_onoff "$(pfu_pam_enabled sudo && echo yes || echo no)")"
|
||||
_pfu_row "$(pfu_msg "Admin prompts")" "$(_pfu_small_onoff "$(pfu_pam_enabled polkit-1 && echo yes || echo no)")"
|
||||
_pfu_row "$(pfu_msg "Photo check")" "$(pfu_value_label Liveness "$CFG_LIVENESS")"
|
||||
_fu_row "$(fu_msg "Lock screen")" "$(_fu_small_onoff "$( [[ $CFG_ENABLED == yes && $CFG_LOCK == yes ]] && echo yes || echo no)")"
|
||||
_fu_row "$(fu_msg "sudo")" "$(_fu_small_onoff "$(fu_pam_enabled sudo && echo yes || echo no)")"
|
||||
_fu_row "$(fu_msg "Admin prompts")" "$(_fu_small_onoff "$(fu_pam_enabled polkit-1 && echo yes || echo no)")"
|
||||
_fu_row "$(fu_msg "Photo check")" "$(fu_value_label Liveness "$CFG_LIVENESS")"
|
||||
|
||||
if (( PFU_ST_LOCKOUT > 0 )); then
|
||||
_pfu_row "$(pfu_msg "Paused")" "${PFU_C_YELLOW}$(pfu_msg "for %d more minutes, or until the password is used" "$(( (PFU_ST_LOCKOUT + 59) / 60 ))")${PFU_C_RESET}"
|
||||
if (( FU_ST_LOCKOUT > 0 )); then
|
||||
_fu_row "$(fu_msg "Paused")" "${FU_C_YELLOW}$(fu_msg "for %d more minutes, or until the password is used" "$(( (FU_ST_LOCKOUT + 59) / 60 ))")${FU_C_RESET}"
|
||||
fi
|
||||
_pfu_row "$(pfu_msg "Last unlock")" "$(pfu_time_ago "$PFU_ST_LAST")"
|
||||
_fu_row "$(fu_msg "Last unlock")" "$(fu_time_ago "$FU_ST_LAST")"
|
||||
|
||||
if [[ $PFU_ST_MODELS != true ]]; then
|
||||
printf '\n %s%s%s\n' "$PFU_C_RED" "$(pfu_msg "The recognition models are missing. Reinstall the package.")" "$PFU_C_RESET"
|
||||
if [[ $FU_ST_MODELS != true ]]; then
|
||||
printf '\n %s%s%s\n' "$FU_C_RED" "$(fu_msg "The recognition models are missing. Reinstall the package.")" "$FU_C_RESET"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ pfu_ui_status() {
|
||||
# type bool, choice (steps through the choices) or camera
|
||||
# needs a bool setting this one does nothing without; it is dimmed while
|
||||
# that is off
|
||||
PFU_SETTINGS=(
|
||||
FU_SETTINGS=(
|
||||
"group|Lock screen"
|
||||
"user|LockScreen|bool|yes|Unlock with your face"
|
||||
"user|ScanOnWake|bool|yes|Scan when you come back||LockScreen"
|
||||
@@ -293,85 +293,85 @@ PFU_SETTINGS=(
|
||||
"user|BubbleForPrompts|bool|yes|Also for sudo and admin prompts||Bubble"
|
||||
)
|
||||
|
||||
# pfu_setting_help <Key> <value>
|
||||
# fu_setting_help <Key> <value>
|
||||
# What a setting does, shown under the list for the selected one.
|
||||
pfu_setting_help() {
|
||||
fu_setting_help() {
|
||||
case "$1:$2" in
|
||||
LockScreen:*) pfu_msg "Unlocks the lock screen when it sees your face. Off: only your password works there." ;;
|
||||
ScanOnWake:*) pfu_msg "Scans when you press a key or move the mouse on the lock screen, and when the computer wakes up." ;;
|
||||
ScanOnLock:*) pfu_msg "Scans as soon as the screen locks. Off by default: if you lock it yourself, it would unlock again right away." ;;
|
||||
sudo:*) pfu_msg "sudo takes your face instead of the password. No match: you type the password as usual." ;;
|
||||
polkit-1:*) pfu_msg "The password windows of Plasma and apps, for example when you install software. No match: you type the password." ;;
|
||||
Liveness:heavy) pfu_msg "You have to blink or turn your head a little. This also stops printed photos." ;;
|
||||
Liveness:off) pfu_msg "No check at all. Only for trying out a camera." ;;
|
||||
Liveness:*) pfu_msg "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. A matte printed photo can get through." ;;
|
||||
Strictness:strict) pfu_msg "Fewer wrong matches, but it may not know you with glasses or in bad light." ;;
|
||||
Strictness:relaxed) pfu_msg "Knows you more easily, but also somebody who looks a lot like you." ;;
|
||||
Strictness:*) pfu_msg "The default. Right for most people." ;;
|
||||
Attention:*) pfu_msg "Your eyes have to be open and on the screen. So it does not unlock while you look away or sleep." ;;
|
||||
Camera:*) pfu_msg "Automatic takes the first normal camera. After a change, set up your face again. An infrared camera needs its light on (linux-enable-ir-emitter)." ;;
|
||||
ScanSeconds:*) pfu_msg "How long the camera looks for your face before it gives up." ;;
|
||||
Adapt:*) pfu_msg "After a sure match it keeps how you look now. So a new haircut or glasses need no new setup." ;;
|
||||
SkipLidClosed:*) pfu_msg "No scan while the laptop is closed, for example at a desk with an external screen." ;;
|
||||
Bubble:*) pfu_msg "The bubble at the top of the screen shows what the camera is doing." ;;
|
||||
BubbleStyle:minimal) pfu_msg "A small pill with a lock that opens." ;;
|
||||
BubbleStyle:*) pfu_msg "An island with a face that looks around, then rings and a tick." ;;
|
||||
AnimationSpeed:*) pfu_msg "How fast the bubble moves." ;;
|
||||
BubbleForPrompts:*) pfu_msg "Shows the bubble when sudo or an admin prompt scans your face, too." ;;
|
||||
LockScreen:*) fu_msg "Unlocks the lock screen when it sees your face. Off: only your password works there." ;;
|
||||
ScanOnWake:*) fu_msg "Scans when you press a key or move the mouse on the lock screen, and when the computer wakes up." ;;
|
||||
ScanOnLock:*) fu_msg "Scans as soon as the screen locks. Off by default: if you lock it yourself, it would unlock again right away." ;;
|
||||
sudo:*) fu_msg "sudo takes your face instead of the password. No match: you type the password as usual." ;;
|
||||
polkit-1:*) fu_msg "The password windows of Plasma and apps, for example when you install software. No match: you type the password." ;;
|
||||
Liveness:heavy) fu_msg "You have to blink or turn your head a little. This also stops printed photos." ;;
|
||||
Liveness:off) fu_msg "No check at all. Only for trying out a camera." ;;
|
||||
Liveness:*) fu_msg "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. A matte printed photo can get through." ;;
|
||||
Strictness:strict) fu_msg "Fewer wrong matches, but it may not know you with glasses or in bad light." ;;
|
||||
Strictness:relaxed) fu_msg "Knows you more easily, but also somebody who looks a lot like you." ;;
|
||||
Strictness:*) fu_msg "The default. Right for most people." ;;
|
||||
Attention:*) fu_msg "Your eyes have to be open and on the screen. So it does not unlock while you look away or sleep." ;;
|
||||
Camera:*) fu_msg "Automatic takes the first normal camera. After a change, set up your face again. An infrared camera needs its light on (linux-enable-ir-emitter)." ;;
|
||||
ScanSeconds:*) fu_msg "How long the camera looks for your face before it gives up." ;;
|
||||
Adapt:*) fu_msg "After a sure match it keeps how you look now. So a new haircut or glasses need no new setup." ;;
|
||||
SkipLidClosed:*) fu_msg "No scan while the laptop is closed, for example at a desk with an external screen." ;;
|
||||
Bubble:*) fu_msg "The bubble at the top of the screen shows what the camera is doing." ;;
|
||||
BubbleStyle:minimal) fu_msg "A small pill with a lock that opens." ;;
|
||||
BubbleStyle:*) fu_msg "An island with a face that looks around, then rings and a tick." ;;
|
||||
AnimationSpeed:*) fu_msg "How fast the bubble moves." ;;
|
||||
BubbleForPrompts:*) fu_msg "Shows the bubble when sudo or an admin prompt scans your face, too." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# _pfu_wrap <width> <text>
|
||||
# Word wrap, into PFU_WRAP_LINES.
|
||||
PFU_WRAP_LINES=()
|
||||
# _fu_wrap <width> <text>
|
||||
# Word wrap, into FU_WRAP_LINES.
|
||||
FU_WRAP_LINES=()
|
||||
|
||||
_pfu_wrap() {
|
||||
_fu_wrap() {
|
||||
local width="$1" word line='' used=0 c i
|
||||
local -a words
|
||||
PFU_WRAP_LINES=()
|
||||
FU_WRAP_LINES=()
|
||||
read -r -a words <<< "$2"
|
||||
for word in "${words[@]}"; do
|
||||
_pfu_width "$word"
|
||||
if (( used > 0 && used + 1 + PFU_WIDTH > width )); then
|
||||
PFU_WRAP_LINES+=("$line")
|
||||
_fu_width "$word"
|
||||
if (( used > 0 && used + 1 + FU_WIDTH > width )); then
|
||||
FU_WRAP_LINES+=("$line")
|
||||
line='' used=0
|
||||
fi
|
||||
(( used > 0 )) && line+=' ' used=$(( used + 1 ))
|
||||
if (( used + PFU_WIDTH <= width )); then
|
||||
line+="$word" used=$(( used + PFU_WIDTH ))
|
||||
if (( used + FU_WIDTH <= width )); then
|
||||
line+="$word" used=$(( used + FU_WIDTH ))
|
||||
continue
|
||||
fi
|
||||
# Longer than a line: Chinese and Japanese have no spaces, so break
|
||||
# between any two characters.
|
||||
for (( i = 0; i < ${#word}; i++ )); do
|
||||
c="${word:i:1}"
|
||||
_pfu_width "$c"
|
||||
if (( used + PFU_WIDTH > width )); then
|
||||
PFU_WRAP_LINES+=("$line")
|
||||
_fu_width "$c"
|
||||
if (( used + FU_WIDTH > width )); then
|
||||
FU_WRAP_LINES+=("$line")
|
||||
line='' used=0
|
||||
fi
|
||||
line+="$c" used=$(( used + PFU_WIDTH ))
|
||||
line+="$c" used=$(( used + FU_WIDTH ))
|
||||
done
|
||||
done
|
||||
[[ -n $line ]] && PFU_WRAP_LINES+=("$line")
|
||||
[[ -n $line ]] && FU_WRAP_LINES+=("$line")
|
||||
return 0
|
||||
}
|
||||
|
||||
# _pfu_setting_value <scope> <Key> <default>
|
||||
# The current value, in PFU_SETTING_VALUE.
|
||||
PFU_SETTING_VALUE=''
|
||||
# _fu_setting_value <scope> <Key> <default>
|
||||
# The current value, in FU_SETTING_VALUE.
|
||||
FU_SETTING_VALUE=''
|
||||
|
||||
_pfu_setting_value() {
|
||||
_fu_setting_value() {
|
||||
case "$1" in
|
||||
user) _pfu_kv_lookup "$PFU_CONFIG" "$2" "$3"; PFU_SETTING_VALUE="$PFU_KV_VALUE" ;;
|
||||
sys) _pfu_kv_lookup "$PFU_SYSCONFIG" "$2" "$3"; PFU_SETTING_VALUE="$PFU_KV_VALUE" ;;
|
||||
pam) if pfu_pam_enabled "$2"; then PFU_SETTING_VALUE=yes; else PFU_SETTING_VALUE=no; fi ;;
|
||||
user) _fu_kv_lookup "$FU_CONFIG" "$2" "$3"; FU_SETTING_VALUE="$FU_KV_VALUE" ;;
|
||||
sys) _fu_kv_lookup "$FU_SYSCONFIG" "$2" "$3"; FU_SETTING_VALUE="$FU_KV_VALUE" ;;
|
||||
pam) if fu_pam_enabled "$2"; then FU_SETTING_VALUE=yes; else FU_SETTING_VALUE=no; fi ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# _pfu_step <current> <step> <choice>...
|
||||
# _fu_step <current> <step> <choice>...
|
||||
# The choice <step> (1 or -1) away from the current one, round at the ends.
|
||||
_pfu_step() {
|
||||
_fu_step() {
|
||||
local current="$1" step="$2" i
|
||||
shift 2
|
||||
local -a all=("$@")
|
||||
@@ -384,100 +384,100 @@ _pfu_step() {
|
||||
printf '%s\n' "${all[0]}"
|
||||
}
|
||||
|
||||
# _pfu_next_choice <current> <a,b,c> <step>
|
||||
_pfu_next_choice() {
|
||||
# _fu_next_choice <current> <a,b,c> <step>
|
||||
_fu_next_choice() {
|
||||
local -a choices
|
||||
IFS=',' read -r -a choices <<< "$2"
|
||||
_pfu_step "$1" "$3" "${choices[@]}"
|
||||
_fu_step "$1" "$3" "${choices[@]}"
|
||||
}
|
||||
|
||||
# _pfu_next_camera <current> <step>
|
||||
_pfu_next_camera() {
|
||||
pfu_cameras_load
|
||||
_pfu_step "$1" "$2" auto "${PFU_CAM_PATHS[@]}"
|
||||
# _fu_next_camera <current> <step>
|
||||
_fu_next_camera() {
|
||||
fu_cameras_load
|
||||
_fu_step "$1" "$2" auto "${FU_CAM_PATHS[@]}"
|
||||
}
|
||||
|
||||
_pfu_camera_label() {
|
||||
_fu_camera_label() {
|
||||
local value="$1" i
|
||||
if [[ $value == auto ]]; then
|
||||
for i in "${!PFU_CAM_PATHS[@]}"; do
|
||||
if [[ ${PFU_CAM_PATHS[i]} == "$PFU_CAM_AUTO" ]]; then
|
||||
pfu_msg "automatic (%s)" "${PFU_CAM_NAMES[i]}"
|
||||
for i in "${!FU_CAM_PATHS[@]}"; do
|
||||
if [[ ${FU_CAM_PATHS[i]} == "$FU_CAM_AUTO" ]]; then
|
||||
fu_msg "automatic (%s)" "${FU_CAM_NAMES[i]}"
|
||||
return
|
||||
fi
|
||||
done
|
||||
pfu_msg "automatic"
|
||||
fu_msg "automatic"
|
||||
return
|
||||
fi
|
||||
for i in "${!PFU_CAM_PATHS[@]}"; do
|
||||
if [[ ${PFU_CAM_PATHS[i]} == "$value" ]]; then
|
||||
printf '%s' "${PFU_CAM_NAMES[i]}"
|
||||
[[ ${PFU_CAM_IR[i]} == true ]] && printf ' %s' "$(pfu_msg "(infrared)")"
|
||||
for i in "${!FU_CAM_PATHS[@]}"; do
|
||||
if [[ ${FU_CAM_PATHS[i]} == "$value" ]]; then
|
||||
printf '%s' "${FU_CAM_NAMES[i]}"
|
||||
[[ ${FU_CAM_IR[i]} == true ]] && printf ' %s' "$(fu_msg "(infrared)")"
|
||||
return
|
||||
fi
|
||||
done
|
||||
printf '%s %s' "$value" "$(pfu_msg "(not connected)")"
|
||||
printf '%s %s' "$value" "$(fu_msg "(not connected)")"
|
||||
}
|
||||
|
||||
# _pfu_setting_change <scope> <Key> <type> <current> <choices> <step>
|
||||
_pfu_setting_change() {
|
||||
# _fu_setting_change <scope> <Key> <type> <current> <choices> <step>
|
||||
_fu_setting_change() {
|
||||
local scope="$1" key="$2" type="$3" current="$4" choices="$5" step="$6" next
|
||||
|
||||
case "$type" in
|
||||
bool) if pfu_is_true "$current"; then next=no; else next=yes; fi ;;
|
||||
choice) next="$(_pfu_next_choice "$current" "$choices" "$step")" ;;
|
||||
camera) next="$(_pfu_next_camera "$current" "$step")" ;;
|
||||
bool) if fu_is_true "$current"; then next=no; else next=yes; fi ;;
|
||||
choice) next="$(_fu_next_choice "$current" "$choices" "$step")" ;;
|
||||
camera) next="$(_fu_next_camera "$current" "$step")" ;;
|
||||
esac
|
||||
|
||||
case "$scope" in
|
||||
user)
|
||||
pfu_config_set "$key" "$next" || pfu_bad "$(pfu_msg "Could not save the setting.")"
|
||||
fu_config_set "$key" "$next" || fu_bad "$(fu_msg "Could not save the setting.")"
|
||||
;;
|
||||
sys)
|
||||
printf '\n'
|
||||
pfu_ui_cooked pfu_root set "$key" "$next" || pfu_bad "$(pfu_msg "Could not save the setting.")"
|
||||
PFU_KV_CACHE=()
|
||||
fu_ui_cooked fu_root set "$key" "$next" || fu_bad "$(fu_msg "Could not save the setting.")"
|
||||
FU_KV_CACHE=()
|
||||
;;
|
||||
pam)
|
||||
printf '\n'
|
||||
if [[ $next == yes ]]; then
|
||||
pfu_ui_cooked pfu_root pam-enable "$key" || pfu_bad "$(pfu_msg "Could not save the setting.")"
|
||||
fu_ui_cooked fu_root pam-enable "$key" || fu_bad "$(fu_msg "Could not save the setting.")"
|
||||
else
|
||||
pfu_ui_cooked pfu_root pam-disable "$key" || pfu_bad "$(pfu_msg "Could not save the setting.")"
|
||||
fu_ui_cooked fu_root pam-disable "$key" || fu_bad "$(fu_msg "Could not save the setting.")"
|
||||
fi
|
||||
# Remembered, so that turning face unlock off and on again brings
|
||||
# it back.
|
||||
case "$key" in
|
||||
sudo) pfu_config_set Sudo "$next" ;;
|
||||
polkit-1) pfu_config_set Polkit "$next" ;;
|
||||
sudo) fu_config_set Sudo "$next" ;;
|
||||
polkit-1) fu_config_set Polkit "$next" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# pfu_ui_settings
|
||||
# fu_ui_settings
|
||||
# A cursor list in groups, with what the selected setting does under it. The
|
||||
# frame is assembled in memory and written once, and everything constant is
|
||||
# resolved before the loop.
|
||||
pfu_ui_settings() {
|
||||
fu_ui_settings() {
|
||||
local -a scopes=() keys=() types=() defaults=() labels=() widths=() choices=() needs=() values=() rows=()
|
||||
local spec scope key type default label choice need locale i j frame row pad dirty=1 cursor=0 shown
|
||||
local width=0 wrap cols
|
||||
|
||||
locale="$(pfu_ui_locale)"
|
||||
for spec in "${PFU_SETTINGS[@]}"; do
|
||||
locale="$(fu_ui_locale)"
|
||||
for spec in "${FU_SETTINGS[@]}"; do
|
||||
IFS='|' read -r scope key type default label choice need <<< "$spec"
|
||||
# A heading has its label where the key would be.
|
||||
[[ $scope == group ]] && label="$key" key=''
|
||||
scopes+=("$scope"); keys+=("$key"); types+=("$type"); defaults+=("$default")
|
||||
choices+=("$choice"); needs+=("$need")
|
||||
pfu_msg_into "$locale" "$label"
|
||||
labels+=("$PFU_MSG_RESULT")
|
||||
_pfu_width "$PFU_MSG_RESULT"
|
||||
widths+=("$PFU_WIDTH")
|
||||
fu_msg_into "$locale" "$label"
|
||||
labels+=("$FU_MSG_RESULT")
|
||||
_fu_width "$FU_MSG_RESULT"
|
||||
widths+=("$FU_WIDTH")
|
||||
if [[ $scope != group ]]; then
|
||||
rows+=($(( ${#keys[@]} - 1 )))
|
||||
(( PFU_WIDTH > width )) && width=$PFU_WIDTH
|
||||
(( FU_WIDTH > width )) && width=$FU_WIDTH
|
||||
fi
|
||||
done
|
||||
local count=${#rows[@]}
|
||||
@@ -491,77 +491,77 @@ pfu_ui_settings() {
|
||||
rule="${rule// /─}"
|
||||
|
||||
local title hint shared l_on l_off
|
||||
pfu_msg_into "$locale" "Settings"; title="$PFU_MSG_RESULT"
|
||||
pfu_msg_into "$locale" "↑↓ select ←→ or Space: change q: back"; hint="$PFU_MSG_RESULT"
|
||||
pfu_msg_into "$locale" "for all users, asks for your password"; shared="$PFU_MSG_RESULT"
|
||||
pfu_msg_into "$locale" "ON"; l_on="$PFU_MSG_RESULT"
|
||||
pfu_msg_into "$locale" "OFF"; l_off="$PFU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "Settings"; title="$FU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "↑↓ select ←→ or Space: change q: back"; hint="$FU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "for all users, asks for your password"; shared="$FU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "ON"; l_on="$FU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "OFF"; l_off="$FU_MSG_RESULT"
|
||||
|
||||
local clearseq
|
||||
clearseq="$(clear 2>/dev/null)" || clearseq=$'\033[H\033[2J'
|
||||
|
||||
pfu_cameras_load
|
||||
fu_cameras_load
|
||||
|
||||
while true; do
|
||||
if (( dirty )); then
|
||||
PFU_KV_CACHE=()
|
||||
FU_KV_CACHE=()
|
||||
declare -A current=()
|
||||
for i in "${rows[@]}"; do
|
||||
_pfu_setting_value "${scopes[i]}" "${keys[i]}" "${defaults[i]}"
|
||||
values[i]="$PFU_SETTING_VALUE"
|
||||
current[${keys[i]}]="$PFU_SETTING_VALUE"
|
||||
_fu_setting_value "${scopes[i]}" "${keys[i]}" "${defaults[i]}"
|
||||
values[i]="$FU_SETTING_VALUE"
|
||||
current[${keys[i]}]="$FU_SETTING_VALUE"
|
||||
done
|
||||
dirty=0
|
||||
fi
|
||||
|
||||
frame="$clearseq"$'\n'"${PFU_C_BOLD}${PFU_C_BLUE} ${title}${PFU_C_RESET}"$'\n'
|
||||
frame="$clearseq"$'\n'"${FU_C_BOLD}${FU_C_BLUE} ${title}${FU_C_RESET}"$'\n'
|
||||
|
||||
local selected=${rows[cursor]} marker before after dim
|
||||
for i in "${!keys[@]}"; do
|
||||
if [[ ${scopes[i]} == group ]]; then
|
||||
frame+=$'\n'" ${PFU_C_BOLD}${labels[i]}${PFU_C_RESET}"
|
||||
frame+=$'\n'" ${FU_C_BOLD}${labels[i]}${FU_C_RESET}"
|
||||
# The next row says whose settings these are.
|
||||
[[ ${scopes[i + 1]} != user ]] && frame+=" ${PFU_C_DIM}${shared}${PFU_C_RESET}"
|
||||
[[ ${scopes[i + 1]} != user ]] && frame+=" ${FU_C_DIM}${shared}${FU_C_RESET}"
|
||||
frame+=$'\n'
|
||||
continue
|
||||
fi
|
||||
case "${types[i]}" in
|
||||
bool)
|
||||
if pfu_is_true "${values[i]}"; then
|
||||
shown="${PFU_C_GREEN}${l_on}${PFU_C_RESET}"
|
||||
if fu_is_true "${values[i]}"; then
|
||||
shown="${FU_C_GREEN}${l_on}${FU_C_RESET}"
|
||||
else
|
||||
shown="${PFU_C_DIM}${l_off}${PFU_C_RESET}"
|
||||
shown="${FU_C_DIM}${l_off}${FU_C_RESET}"
|
||||
fi
|
||||
;;
|
||||
camera) shown="$(_pfu_camera_label "${values[i]}")" ;;
|
||||
*) shown="$(pfu_value_label "${keys[i]}" "${values[i]}")" ;;
|
||||
camera) shown="$(_fu_camera_label "${values[i]}")" ;;
|
||||
*) shown="$(fu_value_label "${keys[i]}" "${values[i]}")" ;;
|
||||
esac
|
||||
# Arrows on the selected choice: left and right step through it.
|
||||
before=' ' after=''
|
||||
if (( i == selected )) && [[ ${types[i]} != bool ]]; then
|
||||
before="${PFU_C_BLUE}◂${PFU_C_RESET} " after=" ${PFU_C_BLUE}▸${PFU_C_RESET}"
|
||||
before="${FU_C_BLUE}◂${FU_C_RESET} " after=" ${FU_C_BLUE}▸${FU_C_RESET}"
|
||||
fi
|
||||
dim=''
|
||||
[[ -n ${needs[i]} ]] && ! pfu_is_true "${current[${needs[i]}]}" && dim="$PFU_C_DIM"
|
||||
[[ -n ${needs[i]} ]] && ! fu_is_true "${current[${needs[i]}]}" && dim="$FU_C_DIM"
|
||||
pad=$(( width + 2 - widths[i] ))
|
||||
if (( i == selected )); then marker="${PFU_C_BLUE}▸${PFU_C_RESET} "; else marker=' '; fi
|
||||
printf -v row ' %s%s%s%s%*s%s%s%s' "$marker" "$dim" "${labels[i]}" "$PFU_C_RESET" "$pad" '' "$before" "$dim$shown$PFU_C_RESET" "$after"
|
||||
if (( i == selected )); then marker="${FU_C_BLUE}▸${FU_C_RESET} "; else marker=' '; fi
|
||||
printf -v row ' %s%s%s%s%*s%s%s%s' "$marker" "$dim" "${labels[i]}" "$FU_C_RESET" "$pad" '' "$before" "$dim$shown$FU_C_RESET" "$after"
|
||||
frame+="$row"$'\n'
|
||||
done
|
||||
|
||||
# What the selected setting does, in a box of fixed height so the
|
||||
# screen does not jump while moving through the list.
|
||||
_pfu_wrap "$wrap" "$(pfu_setting_help "${keys[selected]}" "${values[selected]}")"
|
||||
frame+=$'\n'" ${PFU_C_DIM}${rule}${PFU_C_RESET}"$'\n'
|
||||
_fu_wrap "$wrap" "$(fu_setting_help "${keys[selected]}" "${values[selected]}")"
|
||||
frame+=$'\n'" ${FU_C_DIM}${rule}${FU_C_RESET}"$'\n'
|
||||
for j in 0 1 2; do
|
||||
frame+=" ${PFU_WRAP_LINES[j]:-}"$'\n'
|
||||
frame+=" ${FU_WRAP_LINES[j]:-}"$'\n'
|
||||
done
|
||||
frame+=$'\n'" ${PFU_C_DIM}${hint}${PFU_C_RESET}"$'\n'
|
||||
_pfu_ui_take_notices
|
||||
frame+="$PFU_UI_NOTICE_TEXT"
|
||||
frame+=$'\n'" ${FU_C_DIM}${hint}${FU_C_RESET}"$'\n'
|
||||
_fu_ui_take_notices
|
||||
frame+="$FU_UI_NOTICE_TEXT"
|
||||
printf '%s' "$frame"
|
||||
|
||||
key="$(pfu_read_key)" || return 0
|
||||
key="$(fu_read_key)" || return 0
|
||||
|
||||
case "$key" in
|
||||
up|k) cursor=$(( (cursor - 1 + count) % count )) ;;
|
||||
@@ -569,7 +569,7 @@ pfu_ui_settings() {
|
||||
space|enter|right|l|left|h)
|
||||
local step=1
|
||||
[[ $key == left || $key == h ]] && step=-1
|
||||
_pfu_setting_change "${scopes[selected]}" "${keys[selected]}" "${types[selected]}" "${values[selected]}" "${choices[selected]}" "$step"
|
||||
_fu_setting_change "${scopes[selected]}" "${keys[selected]}" "${types[selected]}" "${values[selected]}" "${choices[selected]}" "$step"
|
||||
dirty=1
|
||||
;;
|
||||
q|Q|escape) return 0 ;;
|
||||
@@ -582,72 +582,72 @@ pfu_ui_settings() {
|
||||
# Faces
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
pfu_ui_faces() {
|
||||
fu_ui_faces() {
|
||||
local key frame row pad i cursor=0 count locale shown
|
||||
|
||||
locale="$(pfu_ui_locale)"
|
||||
locale="$(fu_ui_locale)"
|
||||
local title hint empty l_on l_off
|
||||
pfu_msg_into "$locale" "Faces"; title="$PFU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "Faces"; title="$FU_MSG_RESULT"
|
||||
# TRANSLATORS: keep the letters, they are the keys.
|
||||
pfu_msg_into "$locale" "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back"; hint="$PFU_MSG_RESULT"
|
||||
pfu_msg_into "$locale" "No face is set up yet. Press a to add one."; empty="$PFU_MSG_RESULT"
|
||||
pfu_msg_into "$locale" "on"; l_on="$PFU_MSG_RESULT"
|
||||
pfu_msg_into "$locale" "off"; l_off="$PFU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back"; hint="$FU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "No face is set up yet. Press a to add one."; empty="$FU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "on"; l_on="$FU_MSG_RESULT"
|
||||
fu_msg_into "$locale" "off"; l_off="$FU_MSG_RESULT"
|
||||
|
||||
local clearseq
|
||||
clearseq="$(clear 2>/dev/null)" || clearseq=$'\033[H\033[2J'
|
||||
|
||||
while true; do
|
||||
pfu_faces_load
|
||||
count=${#PFU_FACE_IDS[@]}
|
||||
fu_faces_load
|
||||
count=${#FU_FACE_IDS[@]}
|
||||
(( cursor >= count )) && cursor=$(( count > 0 ? count - 1 : 0 ))
|
||||
|
||||
frame="$clearseq"$'\n'"${PFU_C_BOLD}${PFU_C_BLUE} ${title}${PFU_C_RESET}"$'\n\n'
|
||||
frame="$clearseq"$'\n'"${FU_C_BOLD}${FU_C_BLUE} ${title}${FU_C_RESET}"$'\n\n'
|
||||
if (( count == 0 )); then
|
||||
frame+=" ${PFU_C_DIM}${empty}${PFU_C_RESET}"$'\n'
|
||||
frame+=" ${FU_C_DIM}${empty}${FU_C_RESET}"$'\n'
|
||||
fi
|
||||
local marker selected="${PFU_C_BLUE}▸${PFU_C_RESET} " samples
|
||||
for i in "${!PFU_FACE_IDS[@]}"; do
|
||||
if [[ ${PFU_FACE_ON[i]} == true ]]; then shown="${PFU_C_GREEN}${l_on}${PFU_C_RESET}"; else shown="${PFU_C_DIM}${l_off}${PFU_C_RESET}"; fi
|
||||
samples="$(pfu_msg "%s samples, %s learned" "${PFU_FACE_SAMPLES[i]}" "${PFU_FACE_LEARNED[i]}")"
|
||||
_pfu_width "${PFU_FACE_NAMES[i]}"
|
||||
pad=$(( 30 - PFU_WIDTH ))
|
||||
local marker selected="${FU_C_BLUE}▸${FU_C_RESET} " samples
|
||||
for i in "${!FU_FACE_IDS[@]}"; do
|
||||
if [[ ${FU_FACE_ON[i]} == true ]]; then shown="${FU_C_GREEN}${l_on}${FU_C_RESET}"; else shown="${FU_C_DIM}${l_off}${FU_C_RESET}"; fi
|
||||
samples="$(fu_msg "%s samples, %s learned" "${FU_FACE_SAMPLES[i]}" "${FU_FACE_LEARNED[i]}")"
|
||||
_fu_width "${FU_FACE_NAMES[i]}"
|
||||
pad=$(( 30 - FU_WIDTH ))
|
||||
(( pad < 0 )) && pad=0
|
||||
if (( i == cursor )); then marker="$selected"; else marker=' '; fi
|
||||
printf -v row ' %s%s%*s %s %s%s%s' "$marker" "${PFU_FACE_NAMES[i]}" "$pad" '' "$shown" "$PFU_C_DIM" "$samples" "$PFU_C_RESET"
|
||||
printf -v row ' %s%s%*s %s %s%s%s' "$marker" "${FU_FACE_NAMES[i]}" "$pad" '' "$shown" "$FU_C_DIM" "$samples" "$FU_C_RESET"
|
||||
frame+="$row"$'\n'
|
||||
done
|
||||
frame+=$'\n'" ${PFU_C_DIM}${hint}${PFU_C_RESET}"$'\n'
|
||||
_pfu_ui_take_notices
|
||||
frame+="$PFU_UI_NOTICE_TEXT"
|
||||
frame+=$'\n'" ${FU_C_DIM}${hint}${FU_C_RESET}"$'\n'
|
||||
_fu_ui_take_notices
|
||||
frame+="$FU_UI_NOTICE_TEXT"
|
||||
printf '%s' "$frame"
|
||||
|
||||
key="$(pfu_read_key)" || return 0
|
||||
key="$(fu_read_key)" || return 0
|
||||
case "$key" in
|
||||
up|k) (( count )) && cursor=$(( (cursor - 1 + count) % count )) ;;
|
||||
down|j) (( count )) && cursor=$(( (cursor + 1) % count )) ;;
|
||||
space|enter)
|
||||
(( count )) || continue
|
||||
if [[ ${PFU_FACE_ON[cursor]} == true ]]; then
|
||||
pfu_ctl disable "${PFU_FACE_IDS[cursor]}" > /dev/null
|
||||
if [[ ${FU_FACE_ON[cursor]} == true ]]; then
|
||||
fu_ctl disable "${FU_FACE_IDS[cursor]}" > /dev/null
|
||||
else
|
||||
pfu_ctl enable "${PFU_FACE_IDS[cursor]}" > /dev/null
|
||||
fu_ctl enable "${FU_FACE_IDS[cursor]}" > /dev/null
|
||||
fi
|
||||
;;
|
||||
r|R)
|
||||
(( count )) || continue
|
||||
printf '\n %s ' "$(pfu_msg "New name:")"
|
||||
if pfu_ui_read_line "${PFU_FACE_NAMES[cursor]}" && [[ -n $PFU_LINE_RESULT ]]; then
|
||||
pfu_ctl rename "${PFU_FACE_IDS[cursor]}" "$PFU_LINE_RESULT" > /dev/null
|
||||
printf '\n %s ' "$(fu_msg "New name:")"
|
||||
if fu_ui_read_line "${FU_FACE_NAMES[cursor]}" && [[ -n $FU_LINE_RESULT ]]; then
|
||||
fu_ctl rename "${FU_FACE_IDS[cursor]}" "$FU_LINE_RESULT" > /dev/null
|
||||
fi
|
||||
;;
|
||||
d|D)
|
||||
(( count )) || continue
|
||||
if pfu_ui_confirm "$(pfu_msg "Delete \"%s\"?" "${PFU_FACE_NAMES[cursor]}")"; then
|
||||
pfu_ctl remove "${PFU_FACE_IDS[cursor]}" > /dev/null
|
||||
if fu_ui_confirm "$(fu_msg "Delete \"%s\"?" "${FU_FACE_NAMES[cursor]}")"; then
|
||||
fu_ctl remove "${FU_FACE_IDS[cursor]}" > /dev/null
|
||||
fi
|
||||
;;
|
||||
a|A) pfu_ui_cooked pfu_do_setup ;;
|
||||
a|A) fu_ui_cooked fu_do_setup ;;
|
||||
q|Q|escape) return 0 ;;
|
||||
*) ;;
|
||||
esac
|
||||
@@ -658,11 +658,11 @@ pfu_ui_faces() {
|
||||
# The menu
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
pfu_ui_menu() {
|
||||
fu_ui_menu() {
|
||||
local choice keep=0
|
||||
|
||||
pfu_ui_term_raw
|
||||
trap 'pfu_ui_term_restore' EXIT INT TERM
|
||||
fu_ui_term_raw
|
||||
trap 'fu_ui_term_restore' EXIT INT TERM
|
||||
|
||||
while true; do
|
||||
# After a test the menu goes under what the camera saw instead.
|
||||
@@ -671,21 +671,21 @@ pfu_ui_menu() {
|
||||
else
|
||||
clear 2>/dev/null || true
|
||||
fi
|
||||
pfu_head " $PFU_PRETTY"
|
||||
pfu_ui_status
|
||||
fu_head " $FU_PRETTY"
|
||||
fu_ui_status
|
||||
printf '\n'
|
||||
printf ' [1] %s\n' "$(pfu_msg "Turn face unlock on or off")"
|
||||
printf ' [2] %s\n' "$(pfu_msg "Add a face")"
|
||||
printf ' [3] %s\n' "$(pfu_msg "Faces")"
|
||||
printf ' [4] %s\n' "$(pfu_msg "Settings")"
|
||||
printf ' [5] %s\n' "$(pfu_msg "Try it")"
|
||||
printf ' [q] %s\n' "$(pfu_msg "Quit")"
|
||||
_pfu_ui_take_notices
|
||||
printf '%s' "$PFU_UI_NOTICE_TEXT"
|
||||
printf ' [1] %s\n' "$(fu_msg "Turn face unlock on or off")"
|
||||
printf ' [2] %s\n' "$(fu_msg "Add a face")"
|
||||
printf ' [3] %s\n' "$(fu_msg "Faces")"
|
||||
printf ' [4] %s\n' "$(fu_msg "Settings")"
|
||||
printf ' [5] %s\n' "$(fu_msg "Try it")"
|
||||
printf ' [q] %s\n' "$(fu_msg "Quit")"
|
||||
_fu_ui_take_notices
|
||||
printf '%s' "$FU_UI_NOTICE_TEXT"
|
||||
printf '\n > '
|
||||
|
||||
choice="$(pfu_read_key)" || {
|
||||
printf '\n'; pfu_ui_term_restore; trap - EXIT INT TERM; return 0
|
||||
choice="$(fu_read_key)" || {
|
||||
printf '\n'; fu_ui_term_restore; trap - EXIT INT TERM; return 0
|
||||
}
|
||||
case "$choice" in
|
||||
enter|space|up|down|left|right|escape) choice='' ;;
|
||||
@@ -694,24 +694,24 @@ pfu_ui_menu() {
|
||||
|
||||
case "$choice" in
|
||||
1)
|
||||
pfu_config_load
|
||||
fu_config_load
|
||||
if [[ $CFG_ENABLED == yes ]]; then
|
||||
pfu_ui_cooked pfu_do_disable
|
||||
fu_ui_cooked fu_do_disable
|
||||
else
|
||||
pfu_ui_cooked pfu_do_enable
|
||||
fu_ui_cooked fu_do_enable
|
||||
fi
|
||||
;;
|
||||
2) pfu_ui_cooked pfu_do_setup ;;
|
||||
3) pfu_ui_faces ;;
|
||||
4) pfu_ui_settings ;;
|
||||
2) fu_ui_cooked fu_do_setup ;;
|
||||
3) fu_ui_faces ;;
|
||||
4) fu_ui_settings ;;
|
||||
5)
|
||||
printf '\n'
|
||||
pfu_ui_cooked pfu_test
|
||||
fu_ui_cooked fu_test
|
||||
# Already on screen, with the rest of the test.
|
||||
PFU_UI_NOTICES=()
|
||||
FU_UI_NOTICES=()
|
||||
keep=1
|
||||
;;
|
||||
q|Q) pfu_ui_term_restore; trap - EXIT INT TERM; return 0 ;;
|
||||
q|Q) fu_ui_term_restore; trap - EXIT INT TERM; return 0 ;;
|
||||
# Anything else (Enter, arrow keys, stray characters) just
|
||||
# redraws. Escape is deliberately not a quit key, so a mistyped
|
||||
# arrow key cannot close the menu.
|
||||
|
||||
+49
-49
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# The line that goes in:
|
||||
#
|
||||
# -auth sufficient /usr/lib/security/pam_plasma_face_unlock.so
|
||||
# -auth sufficient /usr/lib/security/pam_face_unlock.so
|
||||
#
|
||||
# "sufficient": a match lets the person in, anything else falls through to the
|
||||
# lines below as if this one were not there. The dash makes PAM skip it
|
||||
@@ -26,24 +26,24 @@
|
||||
# an update to that file still counts.
|
||||
# Undoing takes out exactly those lines, or that file.
|
||||
|
||||
PFU_PAM_MARK="# plasma-face-unlock: the face first, the password if that does not work"
|
||||
PFU_PAM_WRAPPER_MARK="# Written by plasma-face-unlock."
|
||||
PFU_PAM_SERVICES=(sudo polkit-1)
|
||||
FU_PAM_MARK="# face-unlock: the face first, the password if that does not work"
|
||||
FU_PAM_WRAPPER_MARK="# Written by face-unlock."
|
||||
FU_PAM_SERVICES=(sudo polkit-1)
|
||||
|
||||
# Overridable for the tests only; the root side never takes them from the
|
||||
# environment (see the top of plasma-face-unlock).
|
||||
PFU_PAM_ETC_DIR="${PFU_PAM_ETC_DIR:-/etc/pam.d}"
|
||||
read -r -a PFU_PAM_VENDOR_DIRS <<< "${PFU_PAM_VENDOR_DIRS:-/usr/lib/pam.d /usr/share/pam.d /lib/pam.d}"
|
||||
# environment (see the top of face-unlock).
|
||||
FU_PAM_ETC_DIR="${FU_PAM_ETC_DIR:-/etc/pam.d}"
|
||||
read -r -a FU_PAM_VENDOR_DIRS <<< "${FU_PAM_VENDOR_DIRS:-/usr/lib/pam.d /usr/share/pam.d /lib/pam.d}"
|
||||
|
||||
pfu_pam_etc() {
|
||||
printf '%s/%s\n' "$PFU_PAM_ETC_DIR" "$1"
|
||||
fu_pam_etc() {
|
||||
printf '%s/%s\n' "$FU_PAM_ETC_DIR" "$1"
|
||||
}
|
||||
|
||||
# pfu_pam_vendor <service>
|
||||
# fu_pam_vendor <service>
|
||||
# The distribution's own copy, when it keeps one outside /etc.
|
||||
pfu_pam_vendor() {
|
||||
fu_pam_vendor() {
|
||||
local dir
|
||||
for dir in "${PFU_PAM_VENDOR_DIRS[@]}"; do
|
||||
for dir in "${FU_PAM_VENDOR_DIRS[@]}"; do
|
||||
if [[ -f $dir/$1 ]]; then
|
||||
printf '%s\n' "$dir/$1"
|
||||
return 0
|
||||
@@ -52,24 +52,24 @@ pfu_pam_vendor() {
|
||||
return 1
|
||||
}
|
||||
|
||||
pfu_pam_line() {
|
||||
printf -- '-auth sufficient %s\n' "$PFU_PAM_MODULE"
|
||||
fu_pam_line() {
|
||||
printf -- '-auth sufficient %s\n' "$FU_PAM_MODULE"
|
||||
}
|
||||
|
||||
# pfu_pam_enabled <service>
|
||||
pfu_pam_enabled() {
|
||||
# fu_pam_enabled <service>
|
||||
fu_pam_enabled() {
|
||||
local file
|
||||
file="$(pfu_pam_etc "$1")"
|
||||
[[ -r $file ]] && grep -q 'pam_plasma_face_unlock\.so' "$file"
|
||||
file="$(fu_pam_etc "$1")"
|
||||
[[ -r $file ]] && grep -q 'pam_face_unlock\.so' "$file"
|
||||
}
|
||||
|
||||
# pfu_pam_insert <file>
|
||||
# fu_pam_insert <file>
|
||||
# Prints the file with the line added before its first auth line. Debian and
|
||||
# Ubuntu have none in sudo's file, only "@include common-auth", and that
|
||||
# counts as one: after it the password has already been asked for. A file
|
||||
# with neither (which would be odd for either service) gets it at the end.
|
||||
pfu_pam_insert() {
|
||||
awk -v mark="$PFU_PAM_MARK" -v line="$(pfu_pam_line)" '
|
||||
fu_pam_insert() {
|
||||
awk -v mark="$FU_PAM_MARK" -v line="$(fu_pam_line)" '
|
||||
!done && ($0 ~ /^[[:space:]]*-?auth[[:space:]]/ || $0 ~ /^[[:space:]]*@include[[:space:]]+common-auth([[:space:]]|$)/) {
|
||||
print mark
|
||||
print line
|
||||
@@ -85,35 +85,35 @@ pfu_pam_insert() {
|
||||
' "$1"
|
||||
}
|
||||
|
||||
# pfu_pam_remove_lines <file>
|
||||
# fu_pam_remove_lines <file>
|
||||
# Prints the file without our comment and our line.
|
||||
pfu_pam_remove_lines() {
|
||||
awk -v mark="$PFU_PAM_MARK" '
|
||||
fu_pam_remove_lines() {
|
||||
awk -v mark="$FU_PAM_MARK" '
|
||||
$0 == mark { next }
|
||||
/pam_plasma_face_unlock\.so/ { next }
|
||||
/pam_face_unlock\.so/ { next }
|
||||
{ print }
|
||||
' "$1"
|
||||
}
|
||||
|
||||
pfu_pam_wrapper() {
|
||||
fu_pam_wrapper() {
|
||||
local vendor="$1"
|
||||
printf '#%%PAM-1.0\n'
|
||||
printf '%s The face first, then everything\n' "$PFU_PAM_WRAPPER_MARK"
|
||||
printf '%s The face first, then everything\n' "$FU_PAM_WRAPPER_MARK"
|
||||
printf '# %s does for this service. Removed again by\n' "$vendor"
|
||||
printf '# "plasma-face-unlock disable" or from its settings.\n\n'
|
||||
pfu_pam_line
|
||||
printf '# "face-unlock disable" or from its settings.\n\n'
|
||||
fu_pam_line
|
||||
printf 'auth include %s\n' "$vendor"
|
||||
printf 'account include %s\n' "$vendor"
|
||||
printf 'password include %s\n' "$vendor"
|
||||
printf 'session include %s\n' "$vendor"
|
||||
}
|
||||
|
||||
# _pfu_pam_replace <file> <content>
|
||||
# _fu_pam_replace <file> <content>
|
||||
# Writes the new file next to the old one and swaps it in, with the old one's
|
||||
# owner and mode. A half-written PAM file is a locked-out machine.
|
||||
_pfu_pam_replace() {
|
||||
_fu_pam_replace() {
|
||||
local file="$1" content="$2" tmp
|
||||
tmp="$(mktemp "${file}.pfu.XXXXXX")" || return 1
|
||||
tmp="$(mktemp "${file}.fu.XXXXXX")" || return 1
|
||||
printf '%s\n' "$content" > "$tmp" || { rm -f "$tmp"; return 1; }
|
||||
if [[ -e $file ]]; then
|
||||
chown --reference="$file" "$tmp" 2>/dev/null
|
||||
@@ -124,40 +124,40 @@ _pfu_pam_replace() {
|
||||
mv -f "$tmp" "$file"
|
||||
}
|
||||
|
||||
# pfu_pam_enable <service> (root)
|
||||
pfu_pam_enable() {
|
||||
# fu_pam_enable <service> (root)
|
||||
fu_pam_enable() {
|
||||
local service="$1" file vendor content
|
||||
file="$(pfu_pam_etc "$service")"
|
||||
file="$(fu_pam_etc "$service")"
|
||||
|
||||
[[ -e $PFU_PAM_MODULE ]] || { pfu_bad "$(pfu_msg "The PAM module is not installed at %s." "$PFU_PAM_MODULE")"; return 1; }
|
||||
pfu_pam_enabled "$service" && return 0
|
||||
[[ -e $FU_PAM_MODULE ]] || { fu_bad "$(fu_msg "The PAM module is not installed at %s." "$FU_PAM_MODULE")"; return 1; }
|
||||
fu_pam_enabled "$service" && return 0
|
||||
|
||||
if [[ -f $file ]]; then
|
||||
content="$(pfu_pam_insert "$file")" || return 1
|
||||
elif vendor="$(pfu_pam_vendor "$service")"; then
|
||||
content="$(pfu_pam_wrapper "$vendor")"
|
||||
content="$(fu_pam_insert "$file")" || return 1
|
||||
elif vendor="$(fu_pam_vendor "$service")"; then
|
||||
content="$(fu_pam_wrapper "$vendor")"
|
||||
else
|
||||
pfu_bad "$(pfu_msg "There is no PAM configuration for %s on this system." "$service")"
|
||||
fu_bad "$(fu_msg "There is no PAM configuration for %s on this system." "$service")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_pfu_pam_replace "$file" "$content"
|
||||
_fu_pam_replace "$file" "$content"
|
||||
}
|
||||
|
||||
# pfu_pam_disable <service> (root)
|
||||
pfu_pam_disable() {
|
||||
# fu_pam_disable <service> (root)
|
||||
fu_pam_disable() {
|
||||
local service="$1" file content
|
||||
file="$(pfu_pam_etc "$service")"
|
||||
file="$(fu_pam_etc "$service")"
|
||||
|
||||
pfu_pam_enabled "$service" || return 0
|
||||
fu_pam_enabled "$service" || return 0
|
||||
|
||||
if head -n 3 "$file" | grep -qF "$PFU_PAM_WRAPPER_MARK"; then
|
||||
if head -n 3 "$file" | grep -qF "$FU_PAM_WRAPPER_MARK"; then
|
||||
# Ours from the first line to the last. Without it the distribution's
|
||||
# own copy is in charge again.
|
||||
rm -f -- "$file"
|
||||
return
|
||||
fi
|
||||
|
||||
content="$(pfu_pam_remove_lines "$file")" || return 1
|
||||
_pfu_pam_replace "$file" "$content"
|
||||
content="$(fu_pam_remove_lines "$file")" || return 1
|
||||
_fu_pam_replace "$file" "$content"
|
||||
}
|
||||
+34
-34
@@ -8,17 +8,17 @@
|
||||
# is already looking at. The verbs are all there is: there is no way to hand
|
||||
# the root side a command of one's own.
|
||||
#
|
||||
# --root set <Key> <Value> one line of /etc/plasma-face-unlock/config
|
||||
# --root set <Key> <Value> one line of /etc/face-unlock/config
|
||||
# --root pam-enable <service> sudo or polkit-1, see pam.sh
|
||||
# --root pam-disable <service>
|
||||
# --root socket-enable start the daemon's socket, and at boot
|
||||
# --root socket-disable
|
||||
|
||||
PFU_SELF="${PFU_SELF:-$(readlink -f "${BASH_SOURCE[1]:-$0}")}"
|
||||
FU_SELF="${FU_SELF:-$(readlink -f "${BASH_SOURCE[1]:-$0}")}"
|
||||
|
||||
# What each system setting may be set to. Anything else is refused on the root
|
||||
# side, whatever the menu sent.
|
||||
declare -A PFU_SYS_VALID=(
|
||||
declare -A FU_SYS_VALID=(
|
||||
[Camera]='^(auto|/dev/video[0-9]+)$'
|
||||
[Liveness]='^(off|light|heavy)$'
|
||||
[Strictness]='^(relaxed|normal|strict)$'
|
||||
@@ -30,63 +30,63 @@ declare -A PFU_SYS_VALID=(
|
||||
[LockoutMinutes]='^[1-9][0-9]{0,3}$'
|
||||
)
|
||||
|
||||
# pfu_root <verb> [args...]
|
||||
pfu_root() {
|
||||
# fu_root <verb> [args...]
|
||||
fu_root() {
|
||||
local candidate
|
||||
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
pfu_root_verb "$@"
|
||||
fu_root_verb "$@"
|
||||
return
|
||||
fi
|
||||
for candidate in sudo run0 doas; do
|
||||
if pfu_have "$candidate"; then
|
||||
"$candidate" "$PFU_SELF" --root "$@"
|
||||
if fu_have "$candidate"; then
|
||||
"$candidate" "$FU_SELF" --root "$@"
|
||||
return
|
||||
fi
|
||||
done
|
||||
pfu_bad "$(pfu_msg "This needs root, and neither sudo, run0 nor doas is installed.")"
|
||||
fu_bad "$(fu_msg "This needs root, and neither sudo, run0 nor doas is installed.")"
|
||||
return 1
|
||||
}
|
||||
|
||||
pfu_root_verb() {
|
||||
fu_root_verb() {
|
||||
local verb="${1:-}"
|
||||
[[ $# -gt 0 ]] && shift
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
pfu_bad "$(pfu_msg "This command has to run as root.")"
|
||||
fu_bad "$(fu_msg "This command has to run as root.")"
|
||||
return 2
|
||||
fi
|
||||
|
||||
case "$verb" in
|
||||
set)
|
||||
local key="${1:-}" value="${2:-}"
|
||||
if [[ -z ${PFU_SYS_VALID[$key]+set} || ! $value =~ ${PFU_SYS_VALID[$key]} ]]; then
|
||||
pfu_bad "$(pfu_msg "Not a valid setting: %s=%s" "$key" "$value")"
|
||||
if [[ -z ${FU_SYS_VALID[$key]+set} || ! $value =~ ${FU_SYS_VALID[$key]} ]]; then
|
||||
fu_bad "$(fu_msg "Not a valid setting: %s=%s" "$key" "$value")"
|
||||
return 1
|
||||
fi
|
||||
pfu_kv_set "$PFU_SYSCONFIG" "$key" "$value" "$PFU_PRETTY (system settings)" || return 1
|
||||
chmod 0644 "$PFU_SYSCONFIG"
|
||||
fu_kv_set "$FU_SYSCONFIG" "$key" "$value" "$FU_PRETTY (system settings)" || return 1
|
||||
chmod 0644 "$FU_SYSCONFIG"
|
||||
;;
|
||||
pam-enable|pam-disable)
|
||||
local service="${1:-}" known=0 s
|
||||
for s in "${PFU_PAM_SERVICES[@]}"; do
|
||||
for s in "${FU_PAM_SERVICES[@]}"; do
|
||||
[[ $s == "$service" ]] && known=1
|
||||
done
|
||||
(( known )) || { pfu_bad "$(pfu_msg "Not a service this can be used for: %s" "$service")"; return 1; }
|
||||
(( known )) || { fu_bad "$(fu_msg "Not a service this can be used for: %s" "$service")"; return 1; }
|
||||
if [[ $verb == pam-enable ]]; then
|
||||
pfu_pam_enable "$service"
|
||||
fu_pam_enable "$service"
|
||||
else
|
||||
pfu_pam_disable "$service"
|
||||
fu_pam_disable "$service"
|
||||
fi
|
||||
;;
|
||||
socket-enable)
|
||||
systemctl enable --now "$PFU_UNIT_SOCKET" > /dev/null 2>&1
|
||||
systemctl enable --now "$FU_UNIT_SOCKET" > /dev/null 2>&1
|
||||
;;
|
||||
socket-disable)
|
||||
systemctl disable --now "$PFU_UNIT_SOCKET" > /dev/null 2>&1
|
||||
systemctl disable --now "$FU_UNIT_SOCKET" > /dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
pfu_bad "$(pfu_msg "Unknown command: %s" "$verb")"
|
||||
fu_bad "$(fu_msg "Unknown command: %s" "$verb")"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
@@ -96,27 +96,27 @@ pfu_root_verb() {
|
||||
# The two services
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
pfu_socket_enabled() {
|
||||
systemctl is-enabled --quiet "$PFU_UNIT_SOCKET" 2>/dev/null
|
||||
fu_socket_enabled() {
|
||||
systemctl is-enabled --quiet "$FU_UNIT_SOCKET" 2>/dev/null
|
||||
}
|
||||
|
||||
pfu_agent_available() {
|
||||
pfu_have systemctl && [[ -n ${XDG_RUNTIME_DIR:-} ]]
|
||||
fu_agent_available() {
|
||||
fu_have systemctl && [[ -n ${XDG_RUNTIME_DIR:-} ]]
|
||||
}
|
||||
|
||||
pfu_agent_enabled() {
|
||||
systemctl --user is-enabled --quiet "$PFU_UNIT_AGENT" 2>/dev/null
|
||||
fu_agent_enabled() {
|
||||
systemctl --user is-enabled --quiet "$FU_UNIT_AGENT" 2>/dev/null
|
||||
}
|
||||
|
||||
pfu_agent_running() {
|
||||
systemctl --user is-active --quiet "$PFU_UNIT_AGENT" 2>/dev/null
|
||||
fu_agent_running() {
|
||||
systemctl --user is-active --quiet "$FU_UNIT_AGENT" 2>/dev/null
|
||||
}
|
||||
|
||||
pfu_agent_enable() {
|
||||
fu_agent_enable() {
|
||||
systemctl --user daemon-reload > /dev/null 2>&1 || true
|
||||
systemctl --user enable --now "$PFU_UNIT_AGENT" > /dev/null 2>&1
|
||||
systemctl --user enable --now "$FU_UNIT_AGENT" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
pfu_agent_disable() {
|
||||
systemctl --user disable --now "$PFU_UNIT_AGENT" > /dev/null 2>&1 || true
|
||||
fu_agent_disable() {
|
||||
systemctl --user disable --now "$FU_UNIT_AGENT" > /dev/null 2>&1 || true
|
||||
}
|
||||
Reference in new issue
Block a user