Metadata-Version: 2.4
Name: linux-face-unlock
Version: 1.0.0
Summary: PAM-based facial authentication for Linux
Author: mohit31kumar
License: Apache-2.0
Project-URL: Homepage, https://github.com/mohit31kumar/face-unlock
Project-URL: Repository, https://github.com/mohit31kumar/face-unlock
Project-URL: BugTracker, https://github.com/mohit31kumar/face-unlock/issues
Keywords: face,recognition,pam,authentication,linux,security
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory
Classifier: Topic :: Security
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: dlib>=19.7
Requires-Dist: opencv-python>=4.5.0
Requires-Dist: numpy>=1.20.0
Requires-Dist: face-recognition-models>=0.3.0
Dynamic: license-file

# Face-Unlock

[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/)
[![Platform](https://img.shields.io/badge/platform-linux-lightgrey.svg)](https://www.linux.org/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)

**Face-Unlock** is a PAM-based facial authentication system for Linux. It hooks into the PAM (Pluggable Authentication Modules) stack to provide face recognition everywhere — `sudo`, GDM login, polkit, TTY login, and any other PAM-aware service. No cloud, no proprietary APIs, no daemons. Just your webcam, dlib, and a few OpenCV frames.

---

## Features

- **PAM Integration** — plugs into any PAM service: `sudo`, `gdm-password`, `polkit-1`, `login`, and more
- **Liveness Detection** — blink-based liveness via Eye Aspect Ratio (EAR) using dlib's facial landmarks
- **HOG + CNN Detectors** — choose between fast HOG or more accurate CNN-based face detection
- **Rate Limiting & Lockout** — file-based per-user rate limiting with configurable thresholds
- **Secure Encoding Storage** — face encodings stored as numpy arrays with HMAC-SHA256 integrity signatures (no pickle, fixing CWE-502)
- **Notification + Choice Dialogs** — on failed auth, a desktop notification appears with a "Try Face Again" / "Use Password" dialog
- **Headless Mode** — works on servers and SSH sessions where no display is available
- **Automatic Session Detection** — detects user displays, Wayland/X11 sessions, and greeter processes (GDM, LightDM, SDDM, etc.)
- **Audit Logging** — all auth events logged to syslog with `LOG_AUTH` facility
- **Configurable** — all parameters adjustable via `/etc/face-unlock/config.ini`

---

## Quick Start

### Prerequisites

- **Linux** (Debian/Ubuntu-based recommended)
- **Python 3.8+**
- A webcam

### Installation

```bash
git clone https://github.com/mohit31kumar/face-unlock.git
cd face-unlock
sudo ./install.sh
```

The installer will:
1. Install system dependencies (cmake, dlib, OpenCV, zenity, libnotify)
2. Install Python packages
3. Copy library files to `/usr/local/lib/face-unlock/`
4. Create wrapper scripts in `/usr/local/bin/`
5. Generate a default config at `/etc/face-unlock/config.ini`
6. Generate a secret HMAC key at `/etc/face-unlock/secret.key`
7. Patch PAM configuration for `gdm-password`, `sudo`, `polkit-1`, `login`, and `common-auth`

### Enroll a User

```bash
sudo face-unlock-enroll <your-username>
```

Follow the on-screen instructions — look at the camera while it captures 5 face samples.

### Test

```bash
# Quick diagnostic
sudo face-unlock-test

# Test recognition against an enrolled user
sudo face-unlock-test --user <your-username>

# Test liveness (blink) detection
sudo face-unlock-test --liveness

# Test the auth choice dialog
sudo face-unlock-test --dialog
```

### Try It

```bash
# This should trigger face auth via PAM
sudo -i
```

### Toggle Authentication

```bash
# Enable face-unlock in all PAM files
sudo face-unlock enable

# Disable face-unlock from all PAM files
sudo face-unlock disable

# Set face as the default (tried first, password fallback)
sudo face-unlock default on

# Set password as the default (tried first, face fallback)
sudo face-unlock default off

# Check current state
sudo face-unlock status
```

---

## Usage

### CLI Reference

| Command | Description |
|---------|-------------|
| `face-unlock enroll <user>` | Enroll a user interactively |
| `face-unlock list` | List enrolled users and encoding counts |
| `face-unlock remove <user>` | Remove a user's encodings |
| `face-unlock test` | Run diagnostics |
| `face-unlock config` | Edit config in `$EDITOR` |
| `face-unlock enable` | Enable face-unlock in PAM files |
| `face-unlock disable` | Disable face-unlock from PAM files |
| `face-unlock default on/off` | Set face-first or password-first auth order |
| `face-unlock status` | Show current PAM state for all files |

### Enrollment Options

```bash
sudo face-unlock-enroll <username> [options]

Options:
  --headless        Auto-capture frames without GUI preview
  --cnn             Use CNN detector (more accurate, slower)
  --device PATH     Specify camera device (e.g., /dev/video1)
  --samples N       Number of face samples (default: 5)
  --jitters N       Encoding jitter iterations (default: 5)
```

### Testing Options

```bash
sudo face-unlock-test [options]

Options:
  --user USER      Test recognition for an enrolled user
  --liveness       Test blink-based liveness detection
  --dialog         Test notification + choice dialog
  --device PATH    Specify camera device
  --cnn            Use CNN detector
  --timeout SECS   Capture timeout (default: 10)
```

---

## Configuration

All settings are in `/etc/face-unlock/config.ini`. Edit with:

```bash
sudo face-unlock config
```

### `[core]`

| Key | Default | Description |
|-----|---------|-------------|
| `use_cnn` | `false` | Use CNN detector (slower, more accurate) |
| `timeout` | `5` | Total auth attempt timeout in seconds |
| `retries` | `3` | Number of capture retries before falling back |
| `disabled` | `false` | Disable face auth globally |
| `show_auth_dialog` | `true` | Show "Try Again / Use Password" dialog on failure |
| `auto_capture_timeout` | `3` | Seconds to wait for a face before auto-capturing |
| `dialog_timeout` | `10` | Seconds before the choice dialog auto-dismisses |

### `[camera]`

| Key | Default | Description |
|-----|---------|-------------|
| `device_path` | *(empty)* | Camera device path (auto-detected if empty) |
| `frame_width` | `640` | Capture frame width |
| `frame_height` | `480` | Capture frame height |
| `max_height` | `480` | Maximum height for face detection |

### `[recognition]`

| Key | Default | Description |
|-----|---------|-------------|
| `tolerance` | `0.55` | Face match tolerance (lower = stricter) |
| `num_jitters` | `5` | Encoding jitter iterations |
| `liveness_blinks` | `1` | Number of blinks required for liveness |
| `liveness_timeout` | `3` | Seconds to wait for blinks |

### `[ratelimit]`

| Key | Default | Description |
|-----|---------|-------------|
| `max_attempts` | `5` | Failed attempts before lockout |
| `lockout_minutes` | `5` | Lockout duration in minutes |

### `[storage]`

| Key | Default | Description |
|-----|---------|-------------|
| `encodings_dir` | `/etc/face-unlock/encodings` | Directory for face encoding files |

---

## How It Works

```
PAM Service (sudo, GDM, polkit, ...)
       │
       ▼
  pam_exec.so ──► face-unlock-auth
       │
       ▼
  authenticate.py
       │
       ├── Rate-limit check (file-based, per-user)
       ├── Load encodings (numpy + HMAC verification)
       ├── Open camera (config-driven resolution)
       ├── Liveness check (EAR blink detection via dlib landmarks)
       ├── Capture face frame (auto or guided)
       ├── Detect face (HOG or CNN)
       ├── Compute 128-d encoding
       ├── Compare against enrolled encodings (cosine similarity)
       │
       ├── Success ✔  ──► PAM_SUCCESS
       │
       └── Failure ✘  ──► notify-send + zenity dialog
                            │
                            ├── "Try Again" ──► retry capture
                            └── "Use Password" ──► skip to password prompt
```

### Architecture

| Module | Role |
|--------|------|
| `authenticate.py` | PAM auth entry point, orchestrates the full flow |
| `face_engine.py` | Face detection (HOG/CNN), 128-d encoding, EAR computation |
| `camera.py` | OpenCV video capture, headless-safe GUI wrappers |
| `storage.py` | HMAC-signed numpy encoding storage, username validation |
| `config.py` | INI config reader with typed getters and syslog fallback |
| `session.py` | DISPLAY/WAYLAND session detection via `/proc` scanning |
| `dialog.py` | Desktop notification + zenity choice dialog |
| `enroll.py` | Interactive enrollment with GUI and headless modes |
| `test.py` | Diagnostics for camera, recognition, liveness, dialog |
| `pam.py` | PAM file manipulation (enable/disable/toggle auth order) |
| `cli.py` | Management CLI (`enroll`, `list`, `remove`, `test`, `config`, `enable`, `disable`, `default`, `status`) |

---

## Security

- **No pickle deserialization** — legacy `.pkl` files are rejected; encodings use `numpy.save`/`numpy.load` only (CWE-502)
- **HMAC-SHA256 integrity signing** — each encoding file has a `.sig` sidecar verified before loading; key stored at `/etc/face-unlock/secret.key` (chmod 600)
- **Username validation** — alphanumeric + `._-`, max 32 chars, preventing path traversal
- **Rate limiting** — per-user file-based throttle with `fcntl` file locking to prevent race conditions; lockout directory and files created with restrictive permissions (0o700/0o600)
- **Fail-closed errors** — rate limit file corruption results in denial, not bypass
- **No network** — all processing is local; no data leaves your machine
- **Minimal attack surface** — no daemons, no DBus services, no network sockets

---

## Project Structure

```
face-unlock/
├── face_unlock/
│   ├── __init__.py
│   ├── authenticate.py      # PAM auth module
│   ├── camera.py            # OpenCV camera capture
│   ├── cli.py               # Management CLI
│   ├── config.py            # Configuration reader
│   ├── dialog.py            # Notification + choice dialog
│   ├── enroll.py            # User enrollment
│   ├── face_engine.py       # Face detection & recognition
│   ├── pam.py               # PAM file manipulation
│   ├── session.py           # Display session detection
│   ├── storage.py           # Encoding storage with HMAC
│   └── test.py              # Diagnostics
├── tests/
│   ├── test_pam.py          # Unit tests for pam.py
│   └── integration_test.sh  # Integration test with real PAM files
├── install.sh               # System installer
├── uninstall.sh             # System uninstaller
├── requirements.txt          # Python dependencies
├── pyproject.toml            # Package metadata
├── LICENSE                   # Apache 2.0
├── CONTRIBUTING.md           # Contribution guidelines
└── .github/
    ├── workflows/
    │   └── ci.yml            # GitHub Actions CI
    └── ISSUE_TEMPLATE/
        ├── bug_report.md
        └── feature_request.md
```

---

## Uninstall

```bash
sudo ./uninstall.sh
```

The uninstaller will:
- Remove wrapper scripts and library files
- Optionally remove configuration and encodings
- Restore PAM files from backup (or remove face-unlock lines)

---

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

---

## License

Copyright 2026 mohit31kumar

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
