# arca

A CLI tool for mounting and unmounting LUKS-encrypted volumes. Latin for
"strongbox."

arca talks to udisks2 over D-Bus for passphrase/keyfile unlock (no root
needed) and falls back to cryptsetup for FIDO2/TPM2 token-based unlock
(requires doas/sudo). It handles the unlock-then-mount and
unmount-then-lock sequences as single commands.

## Usage

```
arca mount backup              # unlock + mount by config alias
arca mount /dev/sda1           # unlock + mount by device path
arca mount backup -m /mnt/usb  # mount at a specific mountpoint
arca unmount backup            # unmount + lock
arca status                    # show all LUKS volumes and their state
arca init                      # generate config from detected devices
arca --version                 # print version
```

Mount and unmount are idempotent: mounting an already-mounted device
prints the existing mount point; unmounting an already-locked device is
a no-op.

## Configuration

Optional. Without a config file, arca works with device paths directly
using passphrase unlock.

Run `arca init` to auto-generate a config from detected LUKS devices
(excludes the root filesystem). Edit the generated file to set aliases,
methods, and mount points.

`~/.config/arca/config.yaml` (respects `$XDG_CONFIG_HOME`):

```yaml
devices:
  backup:
    uuid: "b8b2f8e3-4cde-4aca-a96e-df9274019f9f"
    mountpoint: "/mnt/backup"  # optional — udisks2 picks if omitted
    methods:                   # optional — default: [passphrase]
      - fido2
      - passphrase
  media:
    uuid: "a1b2c3d4-5678-9abc-def0-1234567890ab"
    methods:
      - keyfile
      - passphrase
    keyfile: "/path/to/media.key"
```

### Config fields

| Field        | Required | Description                                            |
|--------------|----------|--------------------------------------------------------|
| `uuid`       | yes      | LUKS partition UUID (stable across device path changes) |
| `mountpoint` | no       | Where to mount; udisks2 picks if omitted               |
| `methods`    | no       | Ordered unlock strategies; default: `[passphrase]`     |
| `keyfile`    | no       | Path to keyfile (required if `keyfile` is in methods)  |

### Unlock methods

| Method       | Backend    | Root required | Notes                                  |
|--------------|------------|---------------|----------------------------------------|
| `passphrase` | udisks2    | no            | Prompts on terminal                    |
| `keyfile`    | udisks2    | no            | Reads file from `keyfile` config field |
| `fido2`      | cryptsetup | yes (doas)    | Requires enrolled FIDO2 token          |
| `tpm2`       | cryptsetup | yes (doas)    | Requires enrolled TPM2 key             |

Methods are tried in order. If the first fails (e.g., FIDO2 key not
plugged in), arca tries the next.

## Installation

### Nix flake

```nix
# flake.nix
inputs.arca.url = "git+https://git.wntrmute.dev/kyle/arca";

# in your NixOS config
environment.systemPackages = [ inputs.arca.packages.${system}.default ];
```

### From source

```
go install git.wntrmute.dev/kyle/arca@latest
```

## Requirements

- Linux with udisks2 running (standard on most desktop distributions)
- D-Bus system bus access
- For FIDO2/TPM2: `cryptsetup`, `doas` or `sudo`
- For FIDO2/TPM2: token must be enrolled via `systemd-cryptenroll`

## NixOS Notes

cryptsetup loads token handler plugins (FIDO2, TPM2) via `dlopen`, but
NixOS's glibc only searches the binary's baked-in RUNPATH, which doesn't
include systemd's plugin directory. arca works around this by setting
`LD_LIBRARY_PATH` to the systemd cryptsetup plugin directory when
invoking cryptsetup.

The plugin directory is discovered automatically from
`/run/current-system/sw/lib/cryptsetup` or by resolving the
`systemd-cryptenroll` binary path.

Note: cryptsetup's `--external-tokens-path` flag does not work on NixOS
due to the same RUNPATH limitation — the flag is accepted but the
dlopen call still uses the default search path.

### Enrolling a FIDO2 key

```
doas systemd-cryptenroll --fido2-device=auto /dev/sda1
```

This prompts for the existing passphrase, then enrolls the FIDO2 key.
Verify with:

```
doas cryptsetup luksDump /dev/sda1 | grep -A3 Token
```

## Troubleshooting

**"cannot connect to udisks2"**: The udisks2 service isn't running.
Check `systemctl status udisks2`.

**"device not found"**: The device path or alias doesn't match anything
udisks2 knows about. Run `arca status` to list detected devices, or
`arca init` to regenerate the config.

**"No usable token is available"**: The FIDO2/TPM2 token isn't enrolled
on this LUKS device. Enroll with `systemd-cryptenroll`. Also check that
the token plugin is discoverable (see NixOS Notes above).

**"Not authorized to perform operation"**: udisks2 polkit authorization
failed. This happens when mounting a device unlocked via cryptsetup
(root-owned mapping). Use `--mountpoint` or set `mountpoint` in config
to use privileged mount instead.

**FIDO2 key not detected**: Ensure the key is plugged in and
`/dev/hidraw*` devices are accessible. Check `doas systemd-cryptenroll
--fido2-device=list`.
