Go CLI using cobra with mount, unmount, status, and init subcommands. Unlocks via udisks2 D-Bus (passphrase/keyfile) or cryptsetup (FIDO2/TPM2) with ordered method fallback. Includes NixOS-specific LD_LIBRARY_PATH injection for systemd cryptsetup token plugins. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
101 lines
2.3 KiB
Go
101 lines
2.3 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Config holds the arca configuration.
|
|
type Config struct {
|
|
Devices map[string]DeviceConfig `yaml:"devices"`
|
|
}
|
|
|
|
// DeviceConfig holds per-device settings.
|
|
type DeviceConfig struct {
|
|
UUID string `yaml:"uuid"`
|
|
Mountpoint string `yaml:"mountpoint,omitempty"`
|
|
Methods []string `yaml:"methods,omitempty"`
|
|
Keyfile string `yaml:"keyfile,omitempty"`
|
|
}
|
|
|
|
// ResolvedDevice holds the effective settings for a device lookup.
|
|
type ResolvedDevice struct {
|
|
UUID string
|
|
Mountpoint string
|
|
Methods []string
|
|
Keyfile string
|
|
}
|
|
|
|
// Load reads the config file. Returns an empty config if the file doesn't exist.
|
|
func Load() *Config {
|
|
cfg := &Config{
|
|
Devices: make(map[string]DeviceConfig),
|
|
}
|
|
|
|
data, err := os.ReadFile(configPath())
|
|
if err != nil {
|
|
return cfg
|
|
}
|
|
|
|
yaml.Unmarshal(data, cfg)
|
|
return cfg
|
|
}
|
|
|
|
// ResolveDevice looks up by alias name first, then checks if the argument
|
|
// is a device path matching a known alias (e.g. "/dev/sda1" matches "sda1").
|
|
// If nothing matches, returns defaults for a bare device path.
|
|
func (c *Config) ResolveDevice(nameOrPath string) ResolvedDevice {
|
|
// Direct alias match.
|
|
if dev, ok := c.Devices[nameOrPath]; ok {
|
|
return resolvedFrom(dev)
|
|
}
|
|
|
|
// Match device path against aliases: "/dev/sda1" matches alias "sda1".
|
|
base := filepath.Base(nameOrPath)
|
|
if dev, ok := c.Devices[base]; ok {
|
|
return resolvedFrom(dev)
|
|
}
|
|
|
|
return ResolvedDevice{
|
|
Methods: []string{"passphrase"},
|
|
}
|
|
}
|
|
|
|
func resolvedFrom(dev DeviceConfig) ResolvedDevice {
|
|
methods := dev.Methods
|
|
if len(methods) == 0 {
|
|
methods = []string{"passphrase"}
|
|
}
|
|
return ResolvedDevice{
|
|
UUID: dev.UUID,
|
|
Mountpoint: dev.Mountpoint,
|
|
Methods: methods,
|
|
Keyfile: dev.Keyfile,
|
|
}
|
|
}
|
|
|
|
// AliasFor returns the config alias for a given UUID, or "" if none.
|
|
func (c *Config) AliasFor(uuid string) string {
|
|
for name, dev := range c.Devices {
|
|
if dev.UUID == uuid {
|
|
return name
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Path returns the config file path, respecting XDG_CONFIG_HOME.
|
|
func Path() string {
|
|
return configPath()
|
|
}
|
|
|
|
func configPath() string {
|
|
if dir := os.Getenv("XDG_CONFIG_HOME"); dir != "" {
|
|
return filepath.Join(dir, "arca", "config.yaml")
|
|
}
|
|
home, _ := os.UserHomeDir()
|
|
return filepath.Join(home, ".config", "arca", "config.yaml")
|
|
}
|