gocryptfs with password saved in secret-tool

#!/usr/bin/env bash
set -euo pipefail

VAULT_NAME="${1:-vault}"

if [[ ! "$VAULT_NAME" =~ ^[a-zA-Z0-9._-]+$ ]]; then
  echo "错误:保险库名称只能包含字母、数字、点、下划线和连字符" >&2
  exit 1
fi

CIPHER_DIR="$HOME/.local/share/${VAULT_NAME}.enc"
MOUNT_DIR="$HOME/$VAULT_NAME"
BIN_DIR="$HOME/.local/bin"
SYSTEMD_DIR="$HOME/.config/systemd/user"
CTL_SCRIPT="$BIN_DIR/gocryptfs-$VAULT_NAME"
SERVICE_NAME="gocryptfs-$VAULT_NAME.service"
SERVICE_FILE="$SYSTEMD_DIR/$SERVICE_NAME"
SECRET_APP="gocryptfs"
SECRET_VAULT="$VAULT_NAME"

require_cmd() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "错误:未找到命令 $1" >&2
    exit 1
  }
}

init_directories() {
  mkdir -p "$CIPHER_DIR" "$MOUNT_DIR" "$BIN_DIR" "$SYSTEMD_DIR"
  chmod 700 "$CIPHER_DIR" "$MOUNT_DIR" "$BIN_DIR"
}

store_password() {
  if secret-tool lookup app "$SECRET_APP" vault "$SECRET_VAULT" \
      >/dev/null 2>&1; then
    echo "secret-tool 中已存在保险库密码"
    return
  fi

  local password confirm

  read -r -s -p "请输入 gocryptfs 密码: " password
  echo
  read -r -s -p "请再次输入密码: " confirm
  echo

  if [[ -z "$password" ]]; then
    echo "错误:密码不能为空" >&2
    exit 1
  fi

  if [[ "$password" != "$confirm" ]]; then
    echo "错误:两次输入的密码不一致" >&2
    exit 1
  fi

  printf '%s\n' "$password" |
    secret-tool store \
      --label="gocryptfs $VAULT_NAME" \
      app "$SECRET_APP" \
      vault "$SECRET_VAULT"

  unset password confirm
}

init_vault() {
  if [[ -f "$CIPHER_DIR/gocryptfs.conf" ]]; then
    echo "加密目录已经初始化:$CIPHER_DIR"
    return
  fi

  gocryptfs -init \
    -extpass "secret-tool lookup app $SECRET_APP vault $SECRET_VAULT" \
    "$CIPHER_DIR"
}

install_control_script() {
  cat > "$CTL_SCRIPT" <<EOF
#!/usr/bin/env bash
set -euo pipefail

CIPHER_DIR="$CIPHER_DIR"
MOUNT_DIR="$MOUNT_DIR"
SECRET_APP="$SECRET_APP"
SECRET_VAULT="$SECRET_VAULT"

get_password_command() {
  printf 'secret-tool lookup app %q vault %q' "\$SECRET_APP" "\$SECRET_VAULT"
}

case "\${1:-mount}" in
  mount)
    mkdir -p "\$MOUNT_DIR"

    if mountpoint -q "\$MOUNT_DIR"; then
      echo "已经挂载:\$MOUNT_DIR"
      exit 0
    fi

    exec gocryptfs \
      -extpass "\$(get_password_command)" \
      "\$CIPHER_DIR" \
      "\$MOUNT_DIR"
    ;;

  umount)
    if ! mountpoint -q "\$MOUNT_DIR"; then
      echo "未挂载:\$MOUNT_DIR"
      exit 0
    fi

    if command -v fusermount3 >/dev/null 2>&1; then
      exec fusermount3 -u "\$MOUNT_DIR"
    else
      exec fusermount -u "\$MOUNT_DIR"
    fi
    ;;

  status)
    if mountpoint -q "\$MOUNT_DIR"; then
      echo "已挂载:\$MOUNT_DIR"
    else
      echo "未挂载:\$MOUNT_DIR"
    fi
    ;;

  *)
    echo "用法:\$0 {mount|umount|status}" >&2
    exit 1
    ;;
esac
EOF

  chmod 700 "$CTL_SCRIPT"
}

install_systemd_service() {
  cat > "$SERVICE_FILE" <<EOF
[Unit]
Description=Auto mount gocryptfs vault: $VAULT_NAME
After=default.target

[Service]
Type=forking
ExecStart=$CTL_SCRIPT mount
ExecStop=$CTL_SCRIPT umount
Restart=no

[Install]
WantedBy=default.target
EOF

  chmod 600 "$SERVICE_FILE"
}

enable_service() {
  systemctl --user daemon-reload
  systemctl --user enable "$SERVICE_NAME"
  systemctl --user restart "$SERVICE_NAME" 2>/dev/null ||
    systemctl --user start "$SERVICE_NAME"
}

main() {
  require_cmd gocryptfs
  require_cmd secret-tool
  require_cmd mountpoint
  require_cmd systemctl

  init_directories
  store_password
  init_vault
  install_control_script
  install_systemd_service
  enable_service

  echo
  echo "初始化完成"
  echo "加密目录:$CIPHER_DIR"
  echo "明文目录:$MOUNT_DIR"
  echo "服务名称:$SERVICE_NAME"
  echo
  echo "当前状态:"
  "$CTL_SCRIPT" status
}

main "$@"

 

secret-tool 

命令格式是:
secret-tool lookup 属性名1 属性值1 属性名2 属性值2 ...

posted @ 2026-08-07 09:59  ccdriver  阅读(2)  评论(0)    收藏  举报