aboutsummaryrefslogtreecommitdiffstats
path: root/makepass.sh
blob: 3af683017447d951f725c75aedcdf38942da9ba5 (plain) (blame)
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
102
103
104
105
106
107
108
109
110
#!/usr/bin/env sh
# Filename:      makepass.sh
# Purpose:       Creating random passwords.
# Authors:       Dennis Eriksen <d@ennis.no>
# Bug-Reports:   Email <git@dnns.no>
# License:       This file is licensed under the BSD 3-Clause license.
################################################################################
# This file takes randomness from /dev/urandom and turns it into random
# passwords.
#
# This particualr script is meant to be fully POSIX compatible.
################################################################################


# Copyright (c) 2018-2023 Dennis Eriksen • d@ennis.no

# makepass-function
makepass() {
  MAKEPASS_WORDLIST=${MAKEPASS_WORDLIST:-/usr/share/dict/words}

  # We only take one argument
  [ "$#" -gt 1 ] && printf '%s\n' 'only one argument' && return 1

  # if $1 is not empty and is not a number
  if [ ! -z "$1" ] && ! printf '%d' "$1" >/dev/null 2>&1; then printf '%s\n' 'not a number' && return 1; fi
  if [ ! -z "$1" ] && [ ! ${1:-0} -gt 0 ]; then printf '%s\n' 'not a number above 0'; return 1; fi

  # Go!
  len=$1

  printf '%s\n' 'Normal passwords:'
  i=0
  while [ $i -lt 10 ]; do
    _random "${len:-}" '_A-Z-a-z-0-9' true
    i=$((i + 1))
  done | column
  printf '\n'

  printf '%s\n' 'Passwords with special characters:'
  i=0
  while [ $i -lt 6 ]; do
    _random "${len:-}" '!#$%&/()=?+-_,.;:<>[]{}|\@*^A-Z-a-z-0-9' true
    i=$((i + 1))
  done | column

  if [ -r "${MAKEPASS_WORDLIST}" ]; then
    printf '\n'
    printf '%s\n' 'Passphrases:'
    lines=$(wc -l < ${MAKEPASS_WORDLIST})
    i=0
    while [ $i -lt 5 ]; do
      # shuf is the best solution here, but it is very much not portable.
      #words=$(shuf -n 8 "${MAKEPASS_WORDLIST}" | tr '\n' '-' | tr -dc '_A-Z-a-z-0-9')
      words=""
      j=0
      while [ $j -lt 8 ]; do
        words="${words}-$(sed -n $(($(_RANDOM) % $lines + 1))p "${MAKEPASS_WORDLIST}" | tr -dc '_A-Z-a-z-0-9')"
        j=$((j + 1))
      done
      printf '%s\n' "${words#-}"
      i=$((i + 1))
    done
  fi

  unset len i lines j words
  return 0
}

# get random number
_RANDOM() {
  N=0
  while [ ! "$N" = "${N#0}" ]; do
    N=$(head -n 100 /dev/urandom | tr -cd "[:digit:]" | tail -c 8)
  done
  printf '%s\n' "$N" && return 0
}

# Function to create random stuff
_random() (
  # sh does not like leading zeroes when doing math with numbers. Let's reset until we have a number that doesn't start with 0.

  # Default is a number between 8 and 44
  len=${1:-$(($(_RANDOM) % (44 - 8 + 1) + 8))}

  # Default to [:alnum:] if no chars are specified
  chars=${2:-'[:alnum:]'}

  # First-Last-Alpha - if you want the first and the last letter to be from [:alpha:]
  fla=${3:-'false'}

  if [ "$fla" = "true" ]; then
    if [ $len -le 2 ]; then
      string="$(head -n 10 /dev/urandom | tr -cd '[:alpha:]' | tail -c $len)"
    else
      string="$(head -n 10 /dev/urandom | tr -cd '[:alpha:]' | tail -c 1)"
      string="${string}$(head -n 100 /dev/urandom | tr -cd "$chars" | tail -c $((len-2)))"
      string="${string}$(head -n 10 /dev/urandom | tr -cd '[:alpha:]' | tail -c 1)"
    fi
  else
    string="$(head -n 100 /dev/urandom | tr -cd "$chars" | tail -c $len)"
  fi

  printf '%s\n' "$string"
  unset len chars fla string
  return 0
)

makepass "${@:-}"

## END OF FILE #################################################################