Password Manager Made with Only Bash 2

6 min

language: ja bn en es hi pt ru zh-cn zh-tw

Hello, it's me, the incompetent one.
You know, there's this convenient .bashrc, right?

_ssh_hosts() {
  local cur=${COMP_WORDS[COMP_CWORD]}
  COMPREPLY=( $(compgen -W "$(awk '{print $1}' ~/.ssh/known_hosts | cut -d, -f1 | sort -u)" -- "$cur") )
}
complete -F _ssh_hosts ssh

(I found it somewhere before and copied it)

So, I thought these convenient built-in bash commands are super useful! And I tried incorporating them into a password manager I made myself.
It wasn't so much that I wanted to create a password manager, but rather that I just wanted to use complete.
GitHub - haturatu/ppbash: My own password generation & manager made with only bash

Explanation

_usage

This is an internal helper function used when no arguments are passed. It's just made to be reusable even if more password generation commands are added.

_usage() {
  local pass_func="$1"
  local phrase="$2"
  local filename="$3"

  if [[ -z "$filename" ]]; then
    echo "Usage: $pass_func <filename> <phrase>"
    echo
    echo "Description:"
    echo "  $pass_func generates a password from the specified <phrase>,"
    echo "  and saves it encrypted as <filename> in ~/.${pass_func}/."
    echo
    echo "Arguments:"
    echo "  <filename> : Identifier (filename) used for saving/loading"
    echo "  <phrase>   : The original phrase (enclose in quotes if it contains spaces)"
    echo
    echo "Example:"
    echo "  $pass_func mymail 'Like a rolling stone'"
    echo
    echo "Reuse:"
    echo "  If you specify an already saved <filename>, its password will be displayed again."
    echo
    echo "Completion:"
    echo "  ${pass_func} <Tab> will complete with saved filenames."
    echo
    echo "Related commands:"
    echo "  ppmenu  : Lists registered password directories."
    echo
    return 1
  fi

  return 0
}

_init_pass_dir

I wondered if it was necessary to write this specifically, but it would be redundant, so I made this a helper function too.

_init_pass_dir() {
  local dir=$1
  if [[ ! -d $dir ]]; then
    mkdir -p $dir
  fi
}

_pass_list

It stores the completion files to be passed to complete in an array.
printf "%s " "${passfiles[@]##*/}" lists only the filenames from an array of full paths.
It's similar to awk, but for example, if it's /uoo/ooo/genki, it will only be genki.

_pass_list() {
  local dir="$1"
  local passfiles=()

  if [[ -d "$dir" ]]; then
    passfiles=("$dir"/*)
    printf "%s " "${passfiles[@]##*/}"
  fi
}

_register_func_dir

It's a bit confusing, so maybe I should fix the function name...

Functions are stored in an array.
declare -F extracts functions defined in bash that start with pb.
These are then stored in the PASS_DIRS array.

After that, complete -W enables completion for space-separated words when the $fn function is entered.

_register_func_dir() {
  while read -r fn _; do
    local dir="$HOME/.$fn"
    PASS_DIRS+=("$dir")

    complete -W "$(_pass_list "$dir")" "$fn"
  done < <(declare -F | awk '{print $3}' | grep '^pb')
}

I think complete -F is more versatile than complete -W.
This is because it dynamically generates completions by executing a function.
-W completes from static values, but for the ssh completion mentioned earlier,

_ssh_hosts() {
  local cur=${COMP_WORDS[COMP_CWORD]}
  COMPREPLY=( $(compgen -W "$(awk '{print $1}' ~/.ssh/known_hosts | cut -d, -f1 | sort -u)" -- "$cur") )
}
complete -F _ssh_hosts ssh

If you press Tab after ssh, _ssh_hosts will be executed.
My future self will probably make it so that it can be completed with complete -F later...

The rest of the password generation functions aren't very interesting, so I'll stop here.
[Creepy] Password Manager Made with Only .bashrc - SOULMINIGRIG
The mechanism is described around here, and basically, it just uses the helper functions I've already introduced.
See you next time. Thank you.

Related Posts