aboutsummarylogtreecommitdiffstats
path: root/ctotp.sh
blob: 9ef2b09078fd627a4e39cc0cdfc2047c9060c306 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/bin/bash

# Configuration
CONFIG_DIR="$HOME/.config/ctotp"
VAULT_FILE="$CONFIG_DIR/vault.json"
SILENT=false
VERBOSE=false

# Ensure config directory exists
mkdir -p "$CONFIG_DIR"

# Helper: Show usage
usage() {
  echo "Usage: ctotp [COMMAND] [OPTIONS]"
  echo ""
  echo "Commands:"
  echo "  import         Configure the Ente export path and build the vault"
  echo "  copy [NAME]    Copy TOTP code to clipboard (fuzzy search if NAME omitted)"
  echo ""
  echo "Options:"
  echo "  --sync, -y     Run 'ente export' before fetching codes"
  echo "  --silent, -s   Suppress desktop notifications"
  echo "  --verbose, -v  Print logs to console"
  exit 1
}

# Helper: Build JSON Vault from Ente TXT
build_vault() {
  local export_file=$1
  if [[ ! -f "$export_file" ]]; then
    echo "Error: Export file not found at $export_file"
    exit 1
  fi

  echo "[" >"$VAULT_FILE"
  grep "otpauth://" "$export_file" | while read -r line; do
    name=$(echo "$line" | sed -e 's/.*issuer=\([^&]*\).*/\1/')
    secret=$(echo "$line" | sed -e 's/.*secret=\([^&]*\).*/\1/' | tr -d '\r')
    echo "  {\"name\": \"$name\", \"secret\": \"$secret\"}," >>"$VAULT_FILE"
  done
  # Remove last comma and close JSON
  sed -i '$ s/,$//' "$VAULT_FILE"
  echo "]" >>"$VAULT_FILE"
}

# Parse Subcommand
COMMAND=$1
shift

# Parse Flags
while [[ "$#" -gt 0 ]]; do
  case $1 in
  --sync | -y) SYNC=true ;;
  --silent | -s) SILENT=true ;;
  --verbose | -v) VERBOSE=true ;;
  *) NAME=$1 ;; # Assume any non-flag is the Account Name
  esac
  shift
done

if [[ "$VERBOSE" == true ]]; then
  set -x
  # Optional: Customize the prompt for verbose output (makes it stand out)
  export PS4='+ [$(date +"%H:%M:%S")] '
fi

case "$COMMAND" in
import)
  echo "Step 1: Run 'ente account add' if you haven't already."
  echo "Step 2: Run 'ente export' to generate the txt file."
  read -p "Enter full path to ente_auth.txt: " ENTE_PATH
  build_vault "$ENTE_PATH"
  echo "Vault created at $VAULT_FILE"
  ;;

copy)
  if [[ "$SYNC" == true ]]; then
    ente export >/dev/null 2>&1
  fi

  if [[ -z "$NAME" ]]; then
    # Fuzzy search using fzf on the JSON names
    NAME=$(grep '"name":' "$VAULT_FILE" | cut -d '"' -f 4 | fzf --prompt="ctotp > ")
  fi

  if [[ -n "$NAME" ]]; then
    # Extract secret from JSON
    SECRET=$(grep "\"name\": \"$NAME\"" "$VAULT_FILE" | sed -e 's/.*"secret": "\([^"]*\)".*/\1/')

    if [[ -n "$SECRET" ]]; then
      oathtool --totp -b "$SECRET" | wl-copy
      if [[ "$SILENT" == false ]]; then
        notify-send "ctotp" "Code for $NAME copied to clipboard!"
      fi
    else
      echo "Account '$NAME' not found in vault."
    fi
  fi
  ;;
*) usage ;;
esac