build: build on debian 13 and kubuntu 26.04, one apt repository each
release / Debian package (Kubuntu 26.04) (push) Failing after 1m45s
release / Debian package (Debian 13) (push) Canceled after 1s
release / RPM package (push) Failing after 1m26s
release / Release and repositories (push) Skipped
release / Install from the APT repository (Kubuntu 26.04) (push) Skipped
release / Install from the APT repository (Debian 13) (push) Skipped
release / Install from the RPM repository (push) Skipped
release / Debian package (Kubuntu 26.04) (push) Failing after 1m45s
release / Debian package (Debian 13) (push) Canceled after 1s
release / RPM package (push) Failing after 1m26s
release / Release and repositories (push) Skipped
release / Install from the APT repository (Kubuntu 26.04) (push) Skipped
release / Install from the APT repository (Debian 13) (push) Skipped
release / Install from the RPM repository (push) Skipped
This commit is contained in:
1 parent
c26eef95b1
commit
8129215d06
8 files changed
+152
-196
No files matched your search
@@ -17,19 +17,37 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deb:
|
deb:
|
||||||
name: Debian package
|
name: Debian package (${{ matrix.name }})
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# The package depends on the exact Qt it was built against, so each
|
||||||
|
# distribution gets a build and an APT repository of its own.
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
# Plasma 6 arrived in Debian with trixie.
|
# Plasma 6 arrived in Debian with trixie.
|
||||||
container: debian:trixie
|
- name: Debian 13
|
||||||
|
image: debian:trixie
|
||||||
|
codename: trixie
|
||||||
|
suffix: "~deb13"
|
||||||
|
- name: Kubuntu 26.04
|
||||||
|
image: ubuntu:26.04
|
||||||
|
codename: resolute
|
||||||
|
suffix: "~ubuntu26.04"
|
||||||
|
container: ${{ matrix.image }}
|
||||||
|
env:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
steps:
|
steps:
|
||||||
- name: Install the build tools
|
- name: Install the build tools
|
||||||
run: |
|
run: |
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
|
# Older Qt has the Wayland client tools in a package of their own.
|
||||||
|
extra=""
|
||||||
|
[ -n "$(apt-cache madison qt6-wayland-dev-tools)" ] && extra="qt6-wayland-dev-tools"
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
ca-certificates curl git make cmake g++ pkg-config gettext scdoc dpkg-dev \
|
ca-certificates curl git make cmake g++ pkg-config gettext scdoc dpkg-dev \
|
||||||
qt6-base-dev qt6-base-private-dev qt6-declarative-dev \
|
qt6-base-dev qt6-base-dev-tools qt6-base-private-dev qt6-declarative-dev \
|
||||||
qt6-wayland-dev qt6-wayland-dev-tools qt6-wayland-private-dev \
|
qt6-wayland-dev qt6-wayland-private-dev $extra \
|
||||||
liblayershellqtinterface-dev libkf6idletime-dev libkf6i18n-dev \
|
liblayershellqtinterface-dev libkf6i18n-dev \
|
||||||
libopencv-dev libpam0g-dev libsystemd-dev
|
libopencv-dev libpam0g-dev libsystemd-dev
|
||||||
|
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
@@ -38,6 +56,8 @@ jobs:
|
|||||||
run: packaging/check-version.sh "${{ github.ref_name }}"
|
run: packaging/check-version.sh "${{ github.ref_name }}"
|
||||||
|
|
||||||
- run: packaging/build-deb.sh
|
- run: packaging/build-deb.sh
|
||||||
|
env:
|
||||||
|
DEB_SUFFIX: ${{ matrix.suffix }}
|
||||||
|
|
||||||
- name: Look inside what was built
|
- name: Look inside what was built
|
||||||
run: |
|
run: |
|
||||||
@@ -46,7 +66,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
- uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: deb
|
name: deb-${{ matrix.codename }}
|
||||||
path: dist/*.deb
|
path: dist/*.deb
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
@@ -174,8 +194,10 @@ jobs:
|
|||||||
- name: Check that what was written can be verified
|
- name: Check that what was written can be verified
|
||||||
if: steps.key.outputs.present == 'yes'
|
if: steps.key.outputs.present == 'yes'
|
||||||
run: |
|
run: |
|
||||||
gpg --verify pages/deb/InRelease
|
for suite in pages/deb/*/; do
|
||||||
gpg --verify pages/deb/Release.gpg pages/deb/Release
|
gpg --verify "$suite/InRelease"
|
||||||
|
gpg --verify "$suite/Release.gpg" "$suite/Release"
|
||||||
|
done
|
||||||
gpg --verify pages/rpm/repodata/repomd.xml.asc pages/rpm/repodata/repomd.xml
|
gpg --verify pages/rpm/repodata/repomd.xml.asc pages/rpm/repodata/repomd.xml
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
- uses: actions/upload-artifact@v7
|
||||||
@@ -199,11 +221,22 @@ jobs:
|
|||||||
git push "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" HEAD:gh-pages
|
git push "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" HEAD:gh-pages
|
||||||
|
|
||||||
verify-apt:
|
verify-apt:
|
||||||
name: Install from the APT repository
|
name: Install from the APT repository (${{ matrix.name }})
|
||||||
needs: publish
|
needs: publish
|
||||||
if: inputs.dry_run
|
if: inputs.dry_run
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: debian:trixie
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: Debian 13
|
||||||
|
image: debian:trixie
|
||||||
|
codename: trixie
|
||||||
|
- name: Kubuntu 26.04
|
||||||
|
image: ubuntu:26.04
|
||||||
|
codename: resolute
|
||||||
|
container: ${{ matrix.image }}
|
||||||
|
env:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v8
|
- uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
@@ -214,7 +247,7 @@ jobs:
|
|||||||
apt-get update -qq && apt-get install -y --no-install-recommends gpg
|
apt-get update -qq && apt-get install -y --no-install-recommends gpg
|
||||||
install -d -m 0755 /etc/apt/keyrings
|
install -d -m 0755 /etc/apt/keyrings
|
||||||
gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg < pages/KEY.gpg
|
gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg < pages/KEY.gpg
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] file://$PWD/pages/deb ./" \
|
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] file://$PWD/pages/deb/${{ matrix.codename }} ./" \
|
||||||
> /etc/apt/sources.list.d/plasma-face-unlock.list
|
> /etc/apt/sources.list.d/plasma-face-unlock.list
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y plasma-face-unlock
|
apt-get install -y plasma-face-unlock
|
||||||
|
|||||||
@@ -133,8 +133,12 @@ if(PFU_BUILD_AGENT)
|
|||||||
find_package(Qt6 6.5 REQUIRED COMPONENTS Gui Quick WaylandClient)
|
find_package(Qt6 6.5 REQUIRED COMPONENTS Gui Quick WaylandClient)
|
||||||
# The bubble needs the Wayland surface of its window, which only the
|
# The bubble needs the Wayland surface of its window, which only the
|
||||||
# private API hands out. It is the same one Plasma itself uses for this.
|
# private API hands out. It is the same one Plasma itself uses for this.
|
||||||
|
# Newer Qt ships the private modules as packages of their own; older Qt
|
||||||
|
# (6.8 in Debian 13) brings them along with the public ones.
|
||||||
|
if(EXISTS "${Qt6_DIR}/../Qt6GuiPrivate/Qt6GuiPrivateConfig.cmake")
|
||||||
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
||||||
find_package(Qt6 REQUIRED COMPONENTS GuiPrivate WaylandClientPrivate)
|
find_package(Qt6 REQUIRED COMPONENTS GuiPrivate WaylandClientPrivate)
|
||||||
|
endif()
|
||||||
find_package(LayerShellQt REQUIRED)
|
find_package(LayerShellQt REQUIRED)
|
||||||
find_package(KF6I18n REQUIRED)
|
find_package(KF6I18n REQUIRED)
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
<h3 align="center">Face ID for KDE Plasma.</h3>
|
<h3 align="center">Face ID for KDE Plasma.</h3>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Look at the screen and it unlocks. Works for the lock screen, sudo and admin prompts, and a photo of you is not enough.
|
Look at the screen and it unlocks: the lock screen, sudo and admin prompts. A photo of you is not enough.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h5 align="center">
|
<h5 align="center">
|
||||||
|
<a href="#install">Install</a> |
|
||||||
<a href="#how-to-use">How to use</a> |
|
<a href="#how-to-use">How to use</a> |
|
||||||
<a href="#how-to-install">Install</a> |
|
|
||||||
<a href="#is-it-safe">Is it safe?</a> |
|
<a href="#is-it-safe">Is it safe?</a> |
|
||||||
<a href="https://github.com/LoonixTools/plasma-face-unlock/issues">Report a bug</a>
|
<a href="https://github.com/LoonixTools/plasma-face-unlock/issues">Report a bug</a>
|
||||||
</h5>
|
</h5>
|
||||||
@@ -29,84 +29,19 @@
|
|||||||
<img src="res/screenshots/bubble.png" alt="The bubble above the lock screen: looking, recognised, not recognised" width="720">
|
<img src="res/screenshots/bubble.png" alt="The bubble above the lock screen: looking, recognised, not recognised" width="720">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Come back to your locked screen, move the mouse, look at it: a little bubble drops down at the top,
|
Come back to your locked screen and look at it. A bubble drops down at the top, finds your face,
|
||||||
the face in it looks around, two green rings spin and land around a tick, and you are in. The same
|
and you are in. It works for `sudo` and Plasma's admin prompts too, if you want. Everything runs on
|
||||||
for `sudo` in a terminal and for the admin password prompts of Plasma, if you want. Everything runs
|
your computer, and your face is saved as numbers, never as a picture.
|
||||||
on your machine, and your face is stored as numbers, never as a picture.
|
|
||||||
|
|
||||||
The look of the bubble and the photo check are inspired by [Glance](https://github.com/jonnyoo/glance)
|
## Install
|
||||||
(face unlock for the Mac). The code is written from scratch for Plasma.
|
|
||||||
|
|
||||||
## How to use
|
**Arch, CachyOS, EndeavourOS, Manjaro** (AUR)
|
||||||
|
|
||||||
Just run `plasma-face-unlock`. This will open the configuration TUI that looks like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
Plasma Face Unlock
|
|
||||||
|
|
||||||
Face unlock ON
|
|
||||||
|
|
||||||
Faces 2 (Felix, Felix with glasses)
|
|
||||||
Camera Integrated Camera
|
|
||||||
Lock screen on
|
|
||||||
sudo on
|
|
||||||
Admin prompts off
|
|
||||||
Photo check strict (blink or turn your head)
|
|
||||||
Last unlock 2 minutes ago
|
|
||||||
|
|
||||||
[1] Turn face unlock on or off
|
|
||||||
[2] Add a face
|
|
||||||
[3] Faces
|
|
||||||
[4] Settings
|
|
||||||
[5] Try it
|
|
||||||
[q] Quit
|
|
||||||
|
|
||||||
>
|
|
||||||
```
|
|
||||||
|
|
||||||
Press `[1]`. The first time, it opens the setup window: look at the camera, then move your head
|
|
||||||
slowly in a circle until the ring around the picture is full (like setting up Face ID on a phone).
|
|
||||||
It asks for your password once before it adds the face. After that, lock the screen and look at it.
|
|
||||||
|
|
||||||
`[5]` does one scan and shows what the camera sees, which helps a lot when something does not work.
|
|
||||||
`[4]` has everything else:
|
|
||||||
|
|
||||||
```
|
|
||||||
Settings
|
|
||||||
|
|
||||||
▸ Unlock the lock screen ON
|
|
||||||
Look when somebody comes back to the screen ON
|
|
||||||
Look right after the screen locks OFF
|
|
||||||
|
|
||||||
Use for sudo in a terminal* ON
|
|
||||||
Use for admin prompts* OFF
|
|
||||||
|
|
||||||
Photo check* strict (blink or turn your head)
|
|
||||||
How closely a face has to match* normal
|
|
||||||
Only while looking at the screen* ON
|
|
||||||
Camera* automatic (Integrated Camera)
|
|
||||||
How long one look lasts* 5 seconds
|
|
||||||
Learn from every unlock* ON
|
|
||||||
Not while the lid is closed* ON
|
|
||||||
|
|
||||||
Show the bubble at the top ON
|
|
||||||
Bubble style island with the face
|
|
||||||
Animation speed normal
|
|
||||||
Bubble for sudo and admin prompts too ON
|
|
||||||
|
|
||||||
Settings marked * are for the whole computer and ask for your password.
|
|
||||||
Up/Down: select, Space or Right: change, q: back
|
|
||||||
```
|
|
||||||
|
|
||||||
## How to install
|
|
||||||
|
|
||||||
**Arch**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yay -S plasma-face-unlock
|
yay -S plasma-face-unlock
|
||||||
```
|
```
|
||||||
|
|
||||||
**Fedora**
|
**Fedora 44**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo curl -fsSL -o /etc/yum.repos.d/plasma-face-unlock.repo \
|
sudo curl -fsSL -o /etc/yum.repos.d/plasma-face-unlock.repo \
|
||||||
@@ -114,117 +49,96 @@ sudo curl -fsSL -o /etc/yum.repos.d/plasma-face-unlock.repo \
|
|||||||
sudo dnf install plasma-face-unlock
|
sudo dnf install plasma-face-unlock
|
||||||
```
|
```
|
||||||
|
|
||||||
**Debian** (13 or newer) **and Kubuntu** (25.04 or newer)
|
**Debian 13**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo install -d -m 0755 /etc/apt/keyrings
|
sudo install -d -m 0755 /etc/apt/keyrings
|
||||||
curl -fsSL https://loonixtools.github.io/plasma-face-unlock/KEY.gpg \
|
curl -fsSL https://loonixtools.github.io/plasma-face-unlock/KEY.gpg \
|
||||||
| sudo gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg
|
| sudo gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] https://loonixtools.github.io/plasma-face-unlock/deb ./" \
|
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] https://loonixtools.github.io/plasma-face-unlock/deb/trixie ./" \
|
||||||
| sudo tee /etc/apt/sources.list.d/plasma-face-unlock.list
|
| sudo tee /etc/apt/sources.list.d/plasma-face-unlock.list
|
||||||
sudo apt update && sudo apt install plasma-face-unlock
|
sudo apt update && sudo apt install plasma-face-unlock
|
||||||
```
|
```
|
||||||
|
|
||||||
You need Plasma 6 on Wayland and a camera. An infrared camera (the Windows Hello kind) works too.
|
**Kubuntu 26.04**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo install -d -m 0755 /etc/apt/keyrings
|
||||||
|
curl -fsSL https://loonixtools.github.io/plasma-face-unlock/KEY.gpg \
|
||||||
|
| sudo gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] https://loonixtools.github.io/plasma-face-unlock/deb/resolute ./" \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/plasma-face-unlock.list
|
||||||
|
sudo apt update && sudo apt install plasma-face-unlock
|
||||||
|
```
|
||||||
|
|
||||||
|
Updates then come with your normal system updates.
|
||||||
|
|
||||||
|
You need Plasma 6 on Wayland and a camera. Infrared cameras (the Windows Hello kind) work too.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
```bash
|
||||||
|
plasma-face-unlock
|
||||||
|
```
|
||||||
|
|
||||||
|
This opens a menu. Press **1** and follow the setup window: look at the camera, then turn your head
|
||||||
|
slowly in a circle until the ring is full. Then lock the screen and look at it.
|
||||||
|
|
||||||
|
| Key | |
|
||||||
|
|---|---|
|
||||||
|
| **1** | Turn face unlock on or off |
|
||||||
|
| **2** | Add another face, for example with glasses |
|
||||||
|
| **3** | Rename, turn off or delete faces |
|
||||||
|
| **4** | Settings: sudo, admin prompts, photo check, camera, bubble style, animation speed and more |
|
||||||
|
| **5** | One test scan that shows what the camera sees. Try this first when something does not work. |
|
||||||
|
|
||||||
|
Without the menu: `plasma-face-unlock enable`, `disable`, `setup [NAME]`, `faces`, `remove ID`,
|
||||||
|
`test` and `status`.
|
||||||
|
|
||||||
## Is it safe?
|
## Is it safe?
|
||||||
|
|
||||||
**It is a convenience, not a security upgrade.** A phone builds a 3D map of your face with a dot
|
It is a convenience, not a security upgrade. Face ID on a phone sees your face in 3D. A webcam only
|
||||||
projector. A webcam only sees a flat picture, so this cannot be as safe as Face ID. What it does:
|
sees a flat picture.
|
||||||
|
|
||||||
- A photo, printed or on a phone, held up and turned any way, **does not** get in. With the photo
|
- A photo does not get in: the face has to blink or turn a little, and a photo can do neither.
|
||||||
check on *strict* (the default) the face has to blink or turn a little, and a photo can do neither.
|
- A phone or tablet held up to the camera is caught by its reflection and its straight edges.
|
||||||
- A screen or a glossy print held up to the camera throws back one big flat reflection, and a phone
|
- A video of you can still get in.
|
||||||
has straight edges around the face. Both fail the scan straight away.
|
|
||||||
- A **video** of you blinking can still get through. So can, some of the time, a photo that is
|
|
||||||
curled a lot and turned a lot.
|
|
||||||
- Five failed tries in a row pause it for 15 minutes, or until you use your password.
|
- Five failed tries in a row pause it for 15 minutes, or until you use your password.
|
||||||
- Your face data can only be read by root. Adding or deleting a face always needs your password,
|
- Only root can read your face data. Adding or deleting a face always needs your password.
|
||||||
never a face.
|
- sudo and admin prompts never take a face over SSH.
|
||||||
- sudo and admin prompts never take a face over SSH, or when you are not sitting at the machine.
|
|
||||||
|
|
||||||
If the machine guards something that matters, leave sudo and admin prompts off.
|
If the computer guards something important, leave sudo and admin prompts off.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
Four parts:
|
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `plasma-face-unlockd` | Runs as root, started on demand. Owns the camera and the face data, and decides. |
|
| `plasma-face-unlockd` | Runs as root when needed. It owns the camera and the face data and decides. |
|
||||||
| `plasma-face-unlock-agent` | Runs in your session. Watches the lock screen, draws the bubble, is the setup window. |
|
| `plasma-face-unlock-agent` | Runs in your session. It watches the lock screen and draws the bubble. |
|
||||||
| `pam_plasma_face_unlock.so` | Lets sudo and polkit ask the daemon. |
|
| `pam_plasma_face_unlock.so` | Lets sudo and admin prompts ask the daemon. No match: you type your password as usual. |
|
||||||
| `plasma-face-unlock` | This menu. |
|
| `plasma-face-unlock` | The menu. |
|
||||||
|
|
||||||
Faces are found with **YuNet** and turned into 128 numbers with **SFace**, two small networks from
|
Two small networks from the OpenCV model zoo find the face (YuNet) and turn it into numbers (SFace).
|
||||||
the OpenCV model zoo that run on the CPU in a few milliseconds. Two pictures of the same person give
|
They run on the CPU in a few milliseconds. The lock screen is unlocked through logind, the same way
|
||||||
numbers that point the same way; how much they do is the match.
|
`loginctl unlock-session` does it. `man plasma-face-unlock` has all the details.
|
||||||
|
|
||||||
**The photo check** looks for a sign of life on top of the match:
|
## Build from source
|
||||||
|
|
||||||
- **Blink:** the dark of both eyes shrinks to a line and comes back within the fraction of a second a
|
|
||||||
blink takes, while the rest of the face holds still.
|
|
||||||
- **Head turn:** the eyes and the corners of the mouth lie close to one plane, so for a flat picture
|
|
||||||
they predict exactly where the nose has to go when it is turned. A real nose sticks out of that
|
|
||||||
plane and misses the prediction by about as much as the head turned.
|
|
||||||
|
|
||||||
The head turn check is tested against simulated heads and photos (`make test`): photos turned up to
|
|
||||||
60 degrees at heavy camera noise never pass, real heads of all shapes pass 98% of the time.
|
|
||||||
|
|
||||||
**The lock screen** is not unlocked through its password prompt (Plasma runs fingerprints there, but
|
|
||||||
only once per lock). Instead the agent notices the screen locking, scans when you come back (a key,
|
|
||||||
the mouse, the lid, waking from sleep), and unlocks the session through logind, just like
|
|
||||||
`loginctl unlock-session`. KWin lets the bubble show above the lock screen because the agent's desktop
|
|
||||||
file asks for it.
|
|
||||||
|
|
||||||
**sudo and admin prompts** get one line in front of their PAM stack:
|
|
||||||
|
|
||||||
```
|
|
||||||
-auth sufficient /usr/lib/security/pam_plasma_face_unlock.so
|
|
||||||
```
|
|
||||||
|
|
||||||
A match lets you in, anything else falls through to the password. The dash makes PAM skip it quietly
|
|
||||||
if the module is ever missing, so sudo keeps working even after uninstalling. Turning it off takes out
|
|
||||||
exactly that line.
|
|
||||||
|
|
||||||
The man page (`man plasma-face-unlock`) has all the details.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
| Command | |
|
|
||||||
|---|---|
|
|
||||||
| `plasma-face-unlock` | Interactive menu |
|
|
||||||
| `… enable` | Turn on (sets up a face first if needed) |
|
|
||||||
| `… disable` | Turn off, keep the faces |
|
|
||||||
| `… setup [NAME]` | Add a face |
|
|
||||||
| `… faces` | List the faces |
|
|
||||||
| `… remove ID` | Delete a face |
|
|
||||||
| `… test` | One scan, with what the camera sees |
|
|
||||||
| `… status` | What is on |
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make models # downloads the two networks, checked against pinned checksums
|
make models # downloads the two networks and checks them
|
||||||
make
|
make
|
||||||
make test
|
make test
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
Needs CMake, a C++20 compiler, Qt 6 (Core, DBus, Network, Gui, Quick, WaylandClient), LayerShellQt,
|
You need CMake, a C++20 compiler, Qt 6, LayerShellQt, KI18n, OpenCV 4.5.4 or newer (with DNN),
|
||||||
KI18n, OpenCV 4.5.4 or newer with the DNN module, Linux-PAM and libsystemd. Optionally
|
Linux-PAM and libsystemd. `scdoc` and `msgfmt` are optional (man page, translations).
|
||||||
`msgfmt` (gettext) for translations and `scdoc` for the man page. Supports `PREFIX` and `DESTDIR`.
|
[packaging/README.md](packaging/README.md) explains releases.
|
||||||
`make check` runs syntax checks and shellcheck.
|
|
||||||
|
|
||||||
To try it without a camera, point the camera setting at a folder of pictures (`images:/path`) or a
|
|
||||||
video (`file:/path.mp4`) in `/etc/plasma-face-unlock/config`.
|
|
||||||
|
|
||||||
See [packaging/README.md](packaging/README.md) for release builds and repo signing.
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- [Glance](https://github.com/jonnyoo/glance) by Jonathan Zhou (MIT): the idea, the look of the bubble
|
- [Glance](https://github.com/jonnyoo/glance) by Jonathan Zhou (MIT): face unlock for the Mac. The
|
||||||
and the model of deny and confirm cues.
|
idea, the look of the bubble and the photo check come from there. The code here is new.
|
||||||
- [YuNet](https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet) (MIT) and
|
- [YuNet](https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet) (MIT) and
|
||||||
[SFace](https://github.com/opencv/opencv_zoo/tree/main/models/face_recognition_sface) (Apache-2.0)
|
[SFace](https://github.com/opencv/opencv_zoo/tree/main/models/face_recognition_sface) (Apache-2.0)
|
||||||
from the OpenCV model zoo.
|
from the OpenCV model zoo.
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ development packages to build: Debian 13 (trixie) and current Fedora have
|
|||||||
them. The Debian package's library dependencies are read off the binaries by
|
them. The Debian package's library dependencies are read off the binaries by
|
||||||
`dpkg-shlibdeps`; RPM does the same on its own.
|
`dpkg-shlibdeps`; RPM does the same on its own.
|
||||||
|
|
||||||
|
The program uses Qt's private API, so a package only fits the Qt it was built
|
||||||
|
against. The `.deb` is therefore built twice, in Debian 13 and in Ubuntu 26.04
|
||||||
|
(for Kubuntu), with a suffix on the version (`~deb13`, `~ubuntu26.04`), and each
|
||||||
|
gets an APT repository of its own: `deb/trixie` and `deb/resolute`. The RPM is
|
||||||
|
built on the current Fedora.
|
||||||
|
|
||||||
The two networks (YuNet and SFace, from the OpenCV model zoo) are not in the
|
The two networks (YuNet and SFace, from the OpenCV model zoo) are not in the
|
||||||
repository. `make models` downloads them and checks them against the
|
repository. `make models` downloads them and checks them against the
|
||||||
checksums in the Makefile. The RPM spec and the PKGBUILD list them as sources
|
checksums in the Makefile. The RPM spec and the PKGBUILD list them as sources
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ set -euo pipefail
|
|||||||
|
|
||||||
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
version="${1:-$(make -s -C "$here" version)}"
|
version="${1:-$(make -s -C "$here" version)}"
|
||||||
|
# The package depends on the exact Qt of the distribution it is built on, so
|
||||||
|
# each one gets a build of its own, told apart by a suffix: ~deb13, ~ubuntu26.04.
|
||||||
|
debversion="$version${DEB_SUFFIX:-}"
|
||||||
name=plasma-face-unlock
|
name=plasma-face-unlock
|
||||||
|
|
||||||
# A package without its man page or its translations is not a package this
|
# A package without its man page or its translations is not a package this
|
||||||
@@ -49,7 +52,7 @@ depends="$(cd "$work" && dpkg-shlibdeps -O "${elves[@]/#/-e}" 2>/dev/null | sed
|
|||||||
[[ -n $depends ]] || { echo "$0: dpkg-shlibdeps found no dependencies" >&2; exit 1; }
|
[[ -n $depends ]] || { echo "$0: dpkg-shlibdeps found no dependencies" >&2; exit 1; }
|
||||||
|
|
||||||
install -d "$root/DEBIAN"
|
install -d "$root/DEBIAN"
|
||||||
sed -e "s|@VERSION@|$version|g" -e "s|@ARCH@|$arch|g" -e "s|@DEPENDS@|$depends|g" \
|
sed -e "s|@VERSION@|$debversion|g" -e "s|@ARCH@|$arch|g" -e "s|@DEPENDS@|$depends|g" \
|
||||||
"$here/packaging/deb/control" > "$root/DEBIAN/control"
|
"$here/packaging/deb/control" > "$root/DEBIAN/control"
|
||||||
install -Dm644 "$here/packaging/deb/copyright" "$root/usr/share/doc/$name/copyright"
|
install -Dm644 "$here/packaging/deb/copyright" "$root/usr/share/doc/$name/copyright"
|
||||||
|
|
||||||
@@ -69,7 +72,7 @@ chmod 755 "$root/DEBIAN/prerm"
|
|||||||
| LC_ALL=C sort -z | xargs -0 md5sum > DEBIAN/md5sums )
|
| LC_ALL=C sort -z | xargs -0 md5sum > DEBIAN/md5sums )
|
||||||
|
|
||||||
mkdir -p "$here/dist"
|
mkdir -p "$here/dist"
|
||||||
out="$here/dist/${name}_${version}_${arch}.deb"
|
out="$here/dist/${name}_${debversion}_${arch}.deb"
|
||||||
dpkg-deb --root-owner-group --build "$root" "$out" > /dev/null
|
dpkg-deb --root-owner-group --build "$root" "$out" > /dev/null
|
||||||
|
|
||||||
echo "$out"
|
echo "$out"
|
||||||
@@ -76,16 +76,25 @@
|
|||||||
documentation</a> are on GitHub.
|
documentation</a> are on GitHub.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Debian 13 or newer, Kubuntu 25.04 or newer</h2>
|
<h2>Debian 13</h2>
|
||||||
<pre><code>sudo install -d -m 0755 /etc/apt/keyrings
|
<pre><code>sudo install -d -m 0755 /etc/apt/keyrings
|
||||||
curl -fsSL @BASEURL@/KEY.gpg \
|
curl -fsSL @BASEURL@/KEY.gpg \
|
||||||
| sudo gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg
|
| sudo gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] @BASEURL@/deb ./" \
|
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] @BASEURL@/deb/trixie ./" \
|
||||||
| sudo tee /etc/apt/sources.list.d/plasma-face-unlock.list
|
| sudo tee /etc/apt/sources.list.d/plasma-face-unlock.list
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install plasma-face-unlock</code></pre>
|
sudo apt install plasma-face-unlock</code></pre>
|
||||||
|
|
||||||
<h2>Fedora (KDE Plasma)</h2>
|
<h2>Kubuntu 26.04</h2>
|
||||||
|
<pre><code>sudo install -d -m 0755 /etc/apt/keyrings
|
||||||
|
curl -fsSL @BASEURL@/KEY.gpg \
|
||||||
|
| sudo gpg --dearmor -o /etc/apt/keyrings/plasma-face-unlock.gpg
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/plasma-face-unlock.gpg] @BASEURL@/deb/resolute ./" \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/plasma-face-unlock.list
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install plasma-face-unlock</code></pre>
|
||||||
|
|
||||||
|
<h2>Fedora 44 (KDE Plasma)</h2>
|
||||||
<pre><code>sudo curl -fsSL -o /etc/yum.repos.d/plasma-face-unlock.repo \
|
<pre><code>sudo curl -fsSL -o /etc/yum.repos.d/plasma-face-unlock.repo \
|
||||||
@BASEURL@/plasma-face-unlock.repo
|
@BASEURL@/plasma-face-unlock.repo
|
||||||
sudo dnf install plasma-face-unlock</code></pre>
|
sudo dnf install plasma-face-unlock</code></pre>
|
||||||
|
|||||||
+15
-27
@@ -24,46 +24,34 @@ base_url="${PFU_REPO_URL:-https://loonixtools.github.io/plasma-face-unlock}"
|
|||||||
keyid="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/ { print $5; exit }')"
|
keyid="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/ { print $5; exit }')"
|
||||||
[[ -n $keyid ]] || { echo "$0: no secret key in the keyring" >&2; exit 1; }
|
[[ -n $keyid ]] || { echo "$0: no secret key in the keyring" >&2; exit 1; }
|
||||||
|
|
||||||
mkdir -p "$pages/deb" "$pages/rpm"
|
mkdir -p "$pages/rpm"
|
||||||
cp -- "$incoming"/*.deb "$pages/deb/"
|
|
||||||
cp -- "$incoming"/*.rpm "$pages/rpm/"
|
cp -- "$incoming"/*.rpm "$pages/rpm/"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# One APT repository per distribution: each .deb depends on the exact Qt it was
|
||||||
# APT
|
# built against, and its version carries the suffix saying which one that was.
|
||||||
# ---------------------------------------------------------------------------
|
for suite in trixie:deb13 resolute:ubuntu26.04; do
|
||||||
# A flat repository: the packages and their index sit in one directory and the
|
codename="${suite%%:*}"
|
||||||
# sources line ends in "./". There is one distribution here and it is the same
|
tag="${suite#*:}"
|
||||||
# package for all of them, so the suite and component machinery of a pool
|
mkdir -p "$pages/deb/$codename"
|
||||||
# layout would describe nothing.
|
cp -- "$incoming"/*"~${tag}_"*.deb "$pages/deb/$codename/"
|
||||||
(
|
(
|
||||||
cd "$pages/deb"
|
cd "$pages/deb/$codename"
|
||||||
|
|
||||||
# The old index must be gone before the new one is written: apt-ftparchive
|
|
||||||
# hashes every file in the directory, and a Release that hashes the
|
|
||||||
# previous Release is a Release that cannot be verified.
|
|
||||||
rm -f Packages Packages.gz Release Release.gpg InRelease
|
rm -f Packages Packages.gz Release Release.gpg InRelease
|
||||||
|
|
||||||
dpkg-scanpackages --multiversion . > Packages
|
dpkg-scanpackages --multiversion . > Packages
|
||||||
gzip -9kf Packages
|
gzip -9kf Packages
|
||||||
|
|
||||||
apt-ftparchive \
|
apt-ftparchive \
|
||||||
-o APT::FTPArchive::Release::Origin=plasma-face-unlock \
|
-o APT::FTPArchive::Release::Origin=plasma-face-unlock \
|
||||||
-o APT::FTPArchive::Release::Label=plasma-face-unlock \
|
-o APT::FTPArchive::Release::Label=plasma-face-unlock \
|
||||||
-o APT::FTPArchive::Release::Suite=stable \
|
-o APT::FTPArchive::Release::Suite="$codename" \
|
||||||
-o APT::FTPArchive::Release::Codename=stable \
|
-o APT::FTPArchive::Release::Codename="$codename" \
|
||||||
-o APT::FTPArchive::Release::Architectures=amd64 \
|
-o APT::FTPArchive::Release::Architectures=amd64 \
|
||||||
-o APT::FTPArchive::Release::Components=main \
|
-o APT::FTPArchive::Release::Components=main \
|
||||||
release . > Release
|
release . > Release
|
||||||
|
|
||||||
# Both signatures: InRelease is what current apt fetches, Release.gpg is
|
|
||||||
# what an older one falls back to.
|
|
||||||
gpg --batch --yes --local-user "$keyid" --clearsign --output InRelease Release
|
gpg --batch --yes --local-user "$keyid" --clearsign --output InRelease Release
|
||||||
gpg --batch --yes --local-user "$keyid" --detach-sign --armor --output Release.gpg Release
|
gpg --batch --yes --local-user "$keyid" --detach-sign --armor --output Release.gpg Release
|
||||||
)
|
)
|
||||||
|
done
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# RPM
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
(
|
(
|
||||||
cd "$pages/rpm"
|
cd "$pages/rpm"
|
||||||
createrepo_c --quiet --update .
|
createrepo_c --quiet --update .
|
||||||
@@ -85,4 +73,4 @@ sed "s|@BASEURL@|$base_url|g" "$here/packaging/pages/plasma-face-unlock.repo" \
|
|||||||
touch "$pages/.nojekyll"
|
touch "$pages/.nojekyll"
|
||||||
|
|
||||||
echo "signed with $keyid"
|
echo "signed with $keyid"
|
||||||
ls -1 "$pages/deb" "$pages/rpm"
|
ls -1 "$pages"/deb/* "$pages/rpm"
|
||||||
@@ -68,7 +68,6 @@ void BubbleWindow::create()
|
|||||||
// rather than being pushed down below it.
|
// rather than being pushed down below it.
|
||||||
layer->setExclusiveZone(-1);
|
layer->setExclusiveZone(-1);
|
||||||
layer->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityNone);
|
layer->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityNone);
|
||||||
layer->setActivateOnShow(false);
|
|
||||||
// KWin makes a window type of the scope and takes one it does not
|
// KWin makes a window type of the scope and takes one it does not
|
||||||
// know for a normal window. Its scale effect then opens and closes
|
// know for a normal window. Its scale effect then opens and closes
|
||||||
// that with a blur forced behind the whole, mostly clear window: a
|
// that with a blur forced behind the whole, mostly clear window: a
|
||||||
|
|||||||
Reference in new issue
Block a user