# PC Power Control

A tiny passkey-protected page to wake and shut down your PC.

- `index.html` — sign in with a passkey (Face/Touch ID, Windows Hello, a
  security key, or one synced through Google Password Manager), then
  shows **Turn On** / **Turn Off** links.
- `wol.php` — sends a Wake-on-LAN magic packet.
- `off.php` — shuts the PC down remotely via `net rpc shutdown` (Samba).
- Both are gated by `auth_guard.php`, which requires a valid logged-in
  session — no session, no power control, regardless of how the page is
  reached.

## Deploying to the Pi

Copy the whole folder over, e.g. from this machine:

```sh
scp -r /home/debian-joji/www/html pi@192.168.0.180:/var/www/html
```

Then on the Pi:

```sh
sudo chown -R www-data:www-data /var/www/html
sudo chmod 700 /var/www/html/data
```

The `data/` directory must be writable by the web server user — it stores
`passkeys.json` (your registered passkeys) and PHP writes it at runtime.

### Requirements on the Pi

- PHP with the `sockets` extension (`php-sockets` / bundled in most distro
  PHP builds) — used by `wol.php`.
- The `net` command from `samba-common-bin` (`sudo apt install
  samba-common-bin`) — used by `off.php`.
- Apache with `mod_rewrite`/`.htaccess` support (`AllowOverride All` for
  the site), so the included `.htaccess` files actually take effect and
  block direct access to `config.php`, `lib/`, and `data/`. **If the Pi
  uses nginx instead, `.htaccess` is ignored** — add equivalent `location`
  blocks denying `config.php`, `/lib/`, and `/data/` in the nginx vhost.

## HTTPS is required for passkeys

Browsers only allow `navigator.credentials` (passkeys) in a "secure
context": HTTPS, or the literal hostname `localhost`. Visiting the Pi as
a bare LAN IP like `http://192.168.0.180` will **not** work — passkey
registration/login will fail immediately with a clear error from the
page.

Pick one:

- **Easiest for personal use**: give the Pi a hostname on your LAN (e.g.
  via your router's DNS, `/etc/hosts` on your devices, or mDNS —
  `raspberrypi.local` often works out of the box) and set that hostname
  as `RP_ID` in `config.php`, then put a reverse proxy like [Caddy](https://caddyserver.com/)
  in front for automatic HTTPS with a locally-trusted cert
  ([mkcert](https://github.com/FiloSottile/mkcert) is the fastest way to
  get a cert your devices trust without a public domain).
- **Quick testing only**: in Chrome, visit
  `chrome://flags/#unsafely-treat-insecure-origin-as-secure`, add
  `http://192.168.0.180`, and relaunch. This only affects that one
  browser/device — fine for trying things out, not a real fix.

Whatever hostname you land on, set it as `RP_ID` in `config.php` (it must
be exactly the hostname, no scheme/port).

## First-time setup

1. Edit `config.php`:
   - `RP_ID` / `RP_NAME` — your hostname (see above).
   - `SETUP_KEY` — change this to your own long random secret.
   - `WOL_TARGET_MAC` — your PC's network adapter MAC address.
   - `WOL_BROADCAST_ADDR` — your LAN's broadcast address (already set to
     `192.168.0.255`).
   - `OFF_TARGET_IP`, `OFF_USERNAME`, `OFF_PASSWORD` — already filled in
     for your PC at `192.168.0.192`; update if that ever changes.
2. Open `https://<your-hostname>/index.html?setup_key=<your SETUP_KEY>`
   and click **Register Passkey**. This is only allowed once — as soon as
   one passkey exists, registering another requires being logged in
   first (so a stranger on the LAN can't grab the setup key window and
   register their own).
3. From then on, just open `index.html` and sign in with the passkey.
   Use **+ add another passkey** while signed in to register it on more
   devices (e.g. your phone).

## Security notes

- `config.php` holds the Windows shutdown password in plaintext — the
  `.htaccess` in this folder blocks direct HTTP access to it, but treat
  the file itself (and backups of it) as sensitive.
- Sessions are cookie-based, `HttpOnly` + `SameSite=Strict`, and marked
  `Secure` automatically once served over HTTPS.
- This is sized for one owner with one or a few passkeys, on a home LAN —
  it intentionally has no rate limiting or multi-user support.
