mirror of
https://github.com/pivpn/pivpn.git
synced 2025-04-25 08:40:10 +00:00
Reformatted the code
This commit is contained in:
parent
47e8908489
commit
af20461590
24 changed files with 2655 additions and 2021 deletions
|
@ -1,21 +1,25 @@
|
|||
#!/bin/bash
|
||||
_pivpn()
|
||||
{
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
dashopts="-a -c -d -l -r -h -u -up -bk"
|
||||
opts="debug add clients list revoke uninstall help update backup"
|
||||
if [ "${#COMP_WORDS[@]}" -eq 2 ]; then
|
||||
if [[ ${cur} == -* ]] ; then
|
||||
COMPREPLY=( "$(compgen -W "${dashopts}" -- "${cur}")" )
|
||||
else
|
||||
COMPREPLY=( "$(compgen -W "${opts}" -- "${cur}")" )
|
||||
fi
|
||||
elif [[ ( "$prev" == "add" || "$prev" == "-a" ) && "${#COMP_WORDS[@]}" -eq 3 ]]; then
|
||||
COMPREPLY=( "$(compgen -W "nopass" -- "${cur}")" )
|
||||
|
||||
_pivpn() {
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD - 1]}"
|
||||
dashopts="-a -c -d -l -r -h -u -up -bk"
|
||||
opts="debug add clients list revoke uninstall help update backup"
|
||||
|
||||
if [[ "${#COMP_WORDS[@]}" -eq 2 ]]; then
|
||||
if [[ "${cur}" == -* ]]; then
|
||||
COMPREPLY=("$(compgen -W "${dashopts}" -- "${cur}")")
|
||||
else
|
||||
COMPREPLY=("$(compgen -W "${opts}" -- "${cur}")")
|
||||
fi
|
||||
return 0
|
||||
elif [[ ("${prev}" == "add" || "${prev}" == "-a") ]] &&
|
||||
[[ "${#COMP_WORDS[@]}" -eq 3 ]]; then
|
||||
COMPREPLY=("$(compgen -W "nopass" -- "${cur}")")
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -F _pivpn pivpn
|
||||
|
|
|
@ -1,84 +1,99 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# PiVPN: client status script
|
||||
|
||||
STATUS_LOG="/var/log/openvpn-status.log"
|
||||
|
||||
if [ ! -f "${STATUS_LOG}" ]; then
|
||||
echo "The file: $STATUS_LOG was not found!"
|
||||
exit 1
|
||||
if [[ ! -f "${STATUS_LOG}" ]]; then
|
||||
err "The file: ${STATUS_LOG} was not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
scriptusage(){
|
||||
echo "::: List any connected clients to the server"
|
||||
echo ":::"
|
||||
echo "::: Usage: pivpn <-c|clients> [-b|bytes]"
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: [none] List clients with human readable format"
|
||||
echo "::: -b, bytes List clients with dotted decimal notation"
|
||||
echo "::: -h, help Show this usage dialog"
|
||||
err() {
|
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||
}
|
||||
|
||||
hr(){
|
||||
numfmt --to=iec-i --suffix=B "$1"
|
||||
scriptusage() {
|
||||
echo "::: List any connected clients to the server"
|
||||
echo ":::"
|
||||
echo "::: Usage: pivpn <-c|clients> [-b|bytes]"
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: [none] List clients with human readable format"
|
||||
echo "::: -b, bytes List clients with dotted decimal notation"
|
||||
echo "::: -h, help Show this usage dialog"
|
||||
}
|
||||
|
||||
hr() {
|
||||
numfmt --to=iec-i --suffix=B "${1}"
|
||||
}
|
||||
|
||||
listClients(){
|
||||
printf ": NOTE : The output below is NOT real-time!\n"
|
||||
printf ": : It may be off by a few minutes.\n"
|
||||
printf "\n"
|
||||
printf "\e[1m::: Client Status List :::\e[0m\n"
|
||||
listClients() {
|
||||
printf ": NOTE : The output below is NOT real-time!\n"
|
||||
printf ": : It may be off by a few minutes.\n"
|
||||
printf "\n"
|
||||
printf "\e[1m::: Client Status List :::\e[0m\n"
|
||||
|
||||
{
|
||||
printf "\e[4mName\e[0m \t \e[4mRemote IP\e[0m \t \e[4mVirtual IP\e[0m \t \e[4mBytes Received\e[0m \t \e[4mBytes Sent\e[0m \t \e[4mConnected Since\e[0m\n"
|
||||
{
|
||||
printf "\e[4mName\e[0m \t \e[4mRemote IP\e[0m \t "
|
||||
printf "\e[4mVirtual IP\e[0m \t \e[4mBytes Received\e[0m \t "
|
||||
printf "\e[4mBytes Sent\e[0m \t \e[4mConnected Since\e[0m\n"
|
||||
|
||||
if grep -q "^CLIENT_LIST" "${STATUS_LOG}"; then
|
||||
if [ -n "$(type -t numfmt)" ]; then
|
||||
if [ "$HR" = 1 ]; then
|
||||
while read -r line; do
|
||||
read -r -a array <<< "$line"
|
||||
[[ ${array[0]} = CLIENT_LIST ]] || continue
|
||||
printf "%s \t %s \t %s \t %s \t %s \t %s %s %s - %s\n" "${array[1]}" "${array[2]}" "${array[3]}" "$(hr "${array[4]}")" "$(hr "${array[5]}")" "${array[7]}" "${array[8]}" "${array[10]}" "${array[9]}"
|
||||
done <$STATUS_LOG
|
||||
else
|
||||
while read -r line; do
|
||||
read -r -a array <<< "$line"
|
||||
[[ ${array[0]} = CLIENT_LIST ]] || continue
|
||||
printf "%s \t %s \t %s \t %'d \t %'d \t %s %s %s - %s\n" "${array[1]}" "${array[2]}" "${array[3]}" "${array[4]}" "${array[5]}" "${array[7]}" "${array[8]}" "${array[10]}" "${array[9]}"
|
||||
done <$STATUS_LOG
|
||||
fi
|
||||
else
|
||||
awk -F' ' -v s='CLIENT_LIST' '$1 == s {print $2"\t\t"$3"\t"$4"\t"$5"\t\t"$6"\t\t"$8" "$9" "$11" - "$10"\n"}' ${STATUS_LOG}
|
||||
fi
|
||||
if [[ -n "$(type -t numfmt)" ]]; then
|
||||
while read -r line; do
|
||||
read -r -a array <<< "${line}"
|
||||
|
||||
[[ "${array[0]}" == 'CLIENT_LIST' ]] || continue
|
||||
|
||||
printf "%s \t %s \t " "${array[1]}" "${array[2]}"
|
||||
printf "%s \t " "${array[3]}"
|
||||
|
||||
if [[ "${HR}" == 1 ]]; then
|
||||
printf "%s \t %s" "$(hr "${array[4]}")" "$(hr "${array[5]}")"
|
||||
else
|
||||
printf "%'d \t %'d" "${array[4]}" "${array[5]}"
|
||||
fi
|
||||
|
||||
printf " \t %s %s %s " "${array[7]}" "${array[8]}" "${array[10]}"
|
||||
printf "- %s\n" "${array[9]}"
|
||||
done < "${STATUS_LOG}"
|
||||
else
|
||||
awk \
|
||||
-F' ' \
|
||||
-v s='CLIENT_LIST' \
|
||||
'$1 == s {
|
||||
print $2"\t\t"$3"\t"$4"\t"$5"\t\t"$6"\t\t"$8" "$9" "$11" - "$10"\n"
|
||||
}' \
|
||||
"${STATUS_LOG}"
|
||||
fi
|
||||
else
|
||||
printf "\nNo Clients Connected!\n"
|
||||
printf "\nNo Clients Connected!\n"
|
||||
fi
|
||||
|
||||
printf "\n"
|
||||
} | column -t -s $'\t'
|
||||
} | column -t -s $'\t'
|
||||
}
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
HR=1
|
||||
listClients
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
HR=1
|
||||
listClients
|
||||
else
|
||||
while true; do
|
||||
case "$1" in
|
||||
-b|bytes)
|
||||
HR=0
|
||||
listClients
|
||||
exit 0
|
||||
;;
|
||||
-h|help)
|
||||
scriptusage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
HR=0
|
||||
listClients
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
while true; do
|
||||
case "${1}" in
|
||||
-b | bytes)
|
||||
HR=0
|
||||
listClients
|
||||
exit 0
|
||||
;;
|
||||
-h | help)
|
||||
scriptusage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
HR=0
|
||||
listClients
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
|
|
@ -1,42 +1,57 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# PiVPN: list clients script
|
||||
# Updated Script to include Expiration Dates and Clean up Escape Seq -- psgoundar
|
||||
# Updated Script to include Expiration Dates and
|
||||
# Clean up Escape Seq -- psgoundar
|
||||
|
||||
INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
|
||||
if [ ! -f "${INDEX}" ]; then
|
||||
echo "The file: $INDEX was not found!"
|
||||
exit 1
|
||||
|
||||
err() {
|
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||
}
|
||||
|
||||
if [[ ! -f "${INDEX}" ]]; then
|
||||
err "The file: ${INDEX} was not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EASYRSA="/etc/openvpn/easy-rsa/easyrsa"
|
||||
if [ ! -f "${EASYRSA}" ]; then
|
||||
echo "The file: $EASYRSA was not found!"
|
||||
exit 1
|
||||
|
||||
if [[ ! -f "${EASYRSA}" ]]; then
|
||||
err "The file: ${EASYRSA} was not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$EASYRSA update-db >> /dev/null 2>&1
|
||||
"${EASYRSA}" update-db >> /dev/null 2>&1
|
||||
|
||||
printf ": NOTE : The first entry is your server, which should always be valid!\n"
|
||||
printf ": NOTE : The first entry is your server, "
|
||||
printf "which should always be valid!\n"
|
||||
printf "\\n"
|
||||
printf "\\e[1m::: Certificate Status List :::\\e[0m\\n"
|
||||
|
||||
{
|
||||
printf "\\e[4mStatus\\e[0m \t \\e[4mName\\e[0m\\e[0m \t \\e[4mExpiration\\e[0m\\n"
|
||||
printf "\\e[4mStatus\\e[0m \t \\e[4mName\\e[0m\\e[0m \t "
|
||||
printf "\\e[4mExpiration\\e[0m\\n"
|
||||
|
||||
while read -r line || [ -n "$line" ]; do
|
||||
STATUS=$(echo "$line" | awk '{print $1}')
|
||||
NAME=$(echo "$line" | awk -FCN= '{print $2}')
|
||||
EXPD=$(echo "$line" | awk '{if (length($2) == 15) print $2; else print "20"$2}' | cut -b 1-8 | date +"%b %d %Y" -f -)
|
||||
while read -r line || [[ -n "${line}" ]]; do
|
||||
STATUS="$(echo "${line}" | awk '{print $1}')"
|
||||
NAME="$(echo "${line}" | awk -FCN= '{print $2}')"
|
||||
EXPD="$(echo "${line}" |
|
||||
awk '{if (length($2) == 15) print $2; else print "20"$2}' |
|
||||
cut -b 1-8 |
|
||||
date +"%b %d %Y" -f -)"
|
||||
|
||||
if [ "${STATUS}" == "V" ]; then
|
||||
printf "Valid \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD"
|
||||
elif [ "${STATUS}" == "R" ]; then
|
||||
printf "Revoked \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD"
|
||||
elif [ "${STATUS}" == "E" ]; then
|
||||
printf "Expired \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD"
|
||||
if [[ "${STATUS}" == "V" ]]; then
|
||||
printf "Valid"
|
||||
elif [[ "${STATUS}" == "R" ]]; then
|
||||
printf "Revoked"
|
||||
elif [[ "${STATUS}" == "E" ]]; then
|
||||
printf "Expired"
|
||||
else
|
||||
printf "Unknown \t %s \t %s\\n" "$(echo -e "$NAME")" "$EXPD"
|
||||
printf "Unknown"
|
||||
fi
|
||||
|
||||
done <${INDEX}
|
||||
printf "\\n"
|
||||
printf " \t %s \t %s\\n" "$(echo -e "${NAME}")" "${EXPD}"
|
||||
done < "${INDEX}"
|
||||
|
||||
printf "\\n"
|
||||
} | column -t -s $'\t'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Create OVPN Client
|
||||
# Default Variable Declarations
|
||||
setupVars="/etc/pivpn/openvpn/setupVars.conf"
|
||||
|
@ -10,429 +11,498 @@ CA="ca.crt"
|
|||
TA="ta.key"
|
||||
INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
|
||||
|
||||
if [ ! -f "${setupVars}" ]; then
|
||||
echo "::: Missing setup vars file!"
|
||||
exit 1
|
||||
if [[ ! -f "${setupVars}" ]]; then
|
||||
err "::: Missing setup vars file!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${setupVars}"
|
||||
|
||||
helpFunc() {
|
||||
echo "::: Create a client ovpn profile, optional nopass"
|
||||
echo ":::"
|
||||
echo "::: Usage: pivpn <-a|add> [-n|--name <arg>] [-p|--password <arg>]|[nopass] [-d|--days <number>] [-b|--bitwarden] [-i|--iOS] [-o|--ovpn] [-h|--help]"
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: [none] Interactive mode"
|
||||
echo "::: nopass Create a client without a password"
|
||||
echo "::: -n,--name Name for the Client (default: \"$(hostname)\")"
|
||||
echo "::: -p,--password Password for the Client (no default)"
|
||||
echo "::: -d,--days Expire the certificate after specified number of days (default: 1080)"
|
||||
echo "::: -b,--bitwarden Create and save a client through Bitwarden"
|
||||
echo "::: -i,--iOS Generate a certificate that leverages iOS keychain"
|
||||
echo "::: -o,--ovpn Regenerate a .ovpn config file for an existing client"
|
||||
echo "::: -h,--help Show this help dialog"
|
||||
err() {
|
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||
}
|
||||
|
||||
if [ -z "$HELP_SHOWN" ]; then
|
||||
helpFunc
|
||||
echo
|
||||
echo "HELP_SHOWN=1" >> "$setupVars"
|
||||
helpFunc() {
|
||||
echo "::: Create a client ovpn profile, optional nopass"
|
||||
echo ":::"
|
||||
echo -n "::: Usage: pivpn <-a|add> [-n|--name <arg>] "
|
||||
echo -n "[-p|--password <arg>]|[nopass] [-d|--days <number>] "
|
||||
echo "[-b|--bitwarden] [-i|--iOS] [-o|--ovpn] [-h|--help]"
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: [none] Interactive mode"
|
||||
echo "::: nopass Create a client without a password"
|
||||
echo -n "::: -n,--name Name for the Client "
|
||||
echo "(default: \"$(hostname)\")"
|
||||
echo "::: -p,--password Password for the Client (no default)"
|
||||
echo -n "::: -d,--days Expire the certificate after specified "
|
||||
echo "number of days (default: 1080)"
|
||||
echo "::: -b,--bitwarden Create and save a client through Bitwarden"
|
||||
echo -n "::: -i,--iOS Generate a certificate that leverages iOS "
|
||||
echo "keychain"
|
||||
echo -n "::: -o,--ovpn Regenerate a .ovpn config file for an "
|
||||
echo "existing client"
|
||||
echo "::: -h,--help Show this help dialog"
|
||||
}
|
||||
|
||||
if [[ -z "${HELP_SHOWN}" ]]; then
|
||||
helpFunc
|
||||
echo
|
||||
echo "HELP_SHOWN=1" >> "${setupVars}"
|
||||
fi
|
||||
|
||||
# Parse input arguments
|
||||
while test $# -gt 0; do
|
||||
_key="$1"
|
||||
case "$_key" in
|
||||
-n|--name|--name=*)
|
||||
_val="${_key##--name=}"
|
||||
if test "$_val" = "$_key"; then
|
||||
test $# -lt 2 && echo "Missing value for the optional argument '$_key'." && exit 1
|
||||
_val="$2"
|
||||
shift
|
||||
fi
|
||||
NAME="$_val"
|
||||
;;
|
||||
-p|--password|--password=*)
|
||||
_val="${_key##--password=}"
|
||||
if test "$_val" = "$_key"; then
|
||||
test $# -lt 2 && echo "Missing value for the optional argument '$_key'." && exit 1
|
||||
_val="$2"
|
||||
shift
|
||||
fi
|
||||
PASSWD="$_val"
|
||||
;;
|
||||
-d|--days|--days=*)
|
||||
_val="${_key##--days=}"
|
||||
if test "$_val" = "$_key"; then
|
||||
test $# -lt 2 && echo "Missing value for the optional argument '$_key'." && exit 1
|
||||
_val="$2"
|
||||
shift
|
||||
fi
|
||||
DAYS="$_val"
|
||||
;;
|
||||
-i|--iOS)
|
||||
if [ "$TWO_POINT_FOUR" -ne 1 ]; then
|
||||
iOS=1
|
||||
else
|
||||
echo "Sorry, can't generate iOS-specific configs for ECDSA certificates"
|
||||
echo "Generate traditional certificates using 'pivpn -a' or reinstall PiVPN without opting in for OpenVPN 2.4 features"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-h|--help)
|
||||
helpFunc
|
||||
exit 0
|
||||
;;
|
||||
nopass)
|
||||
NO_PASS="1"
|
||||
;;
|
||||
-b|--bitwarden)
|
||||
if command -v bw > /dev/null; then
|
||||
BITWARDEN="2"
|
||||
else
|
||||
echo 'Bitwarden not found, please install bitwarden'
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
_key="${1}"
|
||||
|
||||
if [ "${PLAT}" == 'Alpine' ]; then
|
||||
echo 'You can download it through the following commands:'
|
||||
echo $'\t' 'curl -fLo bitwarden.zip --no-cache https://github.com/bitwarden/clients/releases/download/cli-v2022.6.2/bw-linux-2022.6.2.zip'
|
||||
echo $'\t' 'apk --no-cache -X https://dl-cdn.alpinelinux.org/alpine/edge/testing/ add atool'
|
||||
echo $'\t' 'aunpack -F zip bitwarden.zip'
|
||||
echo $'\t' 'mv bw /opt/bw'
|
||||
echo $'\t' 'chmod 755 /opt/bw'
|
||||
echo $'\t' 'rm bitwarden.zip'
|
||||
echo $'\t' 'apk --no-cache --purge del -r atool'
|
||||
fi
|
||||
case "${_key}" in
|
||||
-n | --name | --name=*)
|
||||
_val="${_key##--name=}"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${_val}" == "${_key}" ]]; then
|
||||
[[ "$#" -lt 2 ]] &&
|
||||
err "Missing value for the optional argument '${_key}'." &&
|
||||
exit 1
|
||||
|
||||
;;
|
||||
-o|--ovpn)
|
||||
GENOVPNONLY=1
|
||||
;;
|
||||
*)
|
||||
echo "Error: Got an unexpected argument '$1'"
|
||||
helpFunc
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
_val="${2}"
|
||||
shift
|
||||
fi
|
||||
|
||||
NAME="${_val}"
|
||||
;;
|
||||
-p | --password | --password=*)
|
||||
_val="${_key##--password=}"
|
||||
|
||||
if [[ "${_val}" == "${_key}" ]]; then
|
||||
[[ "$#" -lt 2 ]] &&
|
||||
err "Missing value for the optional argument '${_key}'." &&
|
||||
exit 1
|
||||
|
||||
_val="${2}"
|
||||
shift
|
||||
fi
|
||||
|
||||
PASSWD="${_val}"
|
||||
;;
|
||||
-d | --days | --days=*)
|
||||
_val="${_key##--days=}"
|
||||
|
||||
if [[ "${_val}" == "${_key}" ]]; then
|
||||
[[ "$#" -lt 2 ]] &&
|
||||
err "Missing value for the optional argument '${_key}'." &&
|
||||
exit 1
|
||||
|
||||
_val="${2}"
|
||||
shift
|
||||
fi
|
||||
|
||||
DAYS="${_val}"
|
||||
;;
|
||||
-i | --iOS)
|
||||
if [[ "${TWO_POINT_FOUR}" -ne 1 ]]; then
|
||||
iOS=1
|
||||
else
|
||||
err "Sorry, can't generate iOS-specific configs for ECDSA certificates"
|
||||
err "Generate traditional certificates using 'pivpn -a' or reinstall PiVPN without opting in for OpenVPN 2.4 features"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-h | --help)
|
||||
helpFunc
|
||||
exit 0
|
||||
;;
|
||||
nopass)
|
||||
NO_PASS="1"
|
||||
;;
|
||||
-b | --bitwarden)
|
||||
if command -v bw > /dev/null; then
|
||||
BITWARDEN="2"
|
||||
else
|
||||
echo 'Bitwarden not found, please install bitwarden'
|
||||
|
||||
if [[ "${PLAT}" == 'Alpine' ]]; then
|
||||
echo 'You can download it through the following commands:'
|
||||
echo -n $'\t''curl -fLo bitwarden.zip --no-cache https://github.com/'
|
||||
echo -n 'bitwarden/clients/releases/download/cli-v2022.6.2/'
|
||||
echo 'bw-linux-2022.6.2.zip'
|
||||
echo $'\t''apk --no-cache unzip'
|
||||
echo $'\t''unzip bitwarden.zip'
|
||||
echo $'\t''mv bw /opt/bw'
|
||||
echo $'\t''chmod 755 /opt/bw'
|
||||
echo $'\t''rm bitwarden.zip'
|
||||
echo $'\t''apk --no-cache --purge del -r unzip'
|
||||
fi
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
;;
|
||||
-o | --ovpn)
|
||||
GENOVPNONLY=1
|
||||
;;
|
||||
*)
|
||||
err "Error: Got an unexpected argument '${1}'"
|
||||
helpFunc
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
# Functions def
|
||||
|
||||
function keynoPASS() {
|
||||
|
||||
#Build the client key
|
||||
expect << EOF
|
||||
keynoPASS() {
|
||||
# Build the client key
|
||||
expect << EOF
|
||||
set timeout -1
|
||||
set env(EASYRSA_CERT_EXPIRE) "${DAYS}"
|
||||
spawn ./easyrsa build-client-full "${NAME}" nopass
|
||||
expect eof
|
||||
EOF
|
||||
|
||||
cd pki || exit
|
||||
|
||||
cd pki || exit
|
||||
}
|
||||
|
||||
function useBitwarden() {
|
||||
useBitwarden() {
|
||||
# login and unlock vault
|
||||
printf "****Bitwarden Login****"
|
||||
printf "\n"
|
||||
|
||||
# login and unlock vault
|
||||
printf "****Bitwarden Login****"
|
||||
printf "\n"
|
||||
SESSION_KEY=$(bw login --raw)
|
||||
export BW_SESSION=$SESSION_KEY
|
||||
printf "Successfully Logged in!"
|
||||
printf "\n"
|
||||
SESSION_KEY="$(bw login --raw)"
|
||||
export BW_SESSION="${SESSION_KEY}"
|
||||
|
||||
# ask user for username
|
||||
printf "Enter the username: "
|
||||
printf "Successfully Logged in!"
|
||||
printf "\n"
|
||||
|
||||
# ask user for username
|
||||
printf "Enter the username: "
|
||||
read -r NAME
|
||||
|
||||
# check name
|
||||
until [[ "${NAME}" =~ ^[a-zA-Z0-9.@_-]+$ ]] &&
|
||||
[[ "${NAME::1}" != "." ]] &&
|
||||
[[ "${NAME::1}" != "-" ]]; do
|
||||
echo -n "Name can only contain alphanumeric characters and these "
|
||||
echo -n "characters (.-@_). The name also cannot start with a dot (.)"
|
||||
echo " or a dash (-). Please try again."
|
||||
# ask user for username again
|
||||
printf "Enter the username: "
|
||||
read -r NAME
|
||||
done
|
||||
|
||||
# check name
|
||||
until [[ "$NAME" =~ ^[a-zA-Z0-9.@_-]+$ && ${NAME::1} != "." && ${NAME::1} != "-" ]]; do
|
||||
echo "Name can only contain alphanumeric characters and these characters (.-@_). The name also cannot start with a dot (.) or a dash (-). Please try again."
|
||||
# ask user for username again
|
||||
printf "Enter the username: "
|
||||
read -r NAME
|
||||
done
|
||||
|
||||
# ask user for length of password
|
||||
printf "Please enter the length of characters you want your password to be "
|
||||
printf "(minimum 12): "
|
||||
read -r LENGTH
|
||||
|
||||
# check length
|
||||
until [[ "${LENGTH}" -gt 11 ]] && [[ "${LENGTH}" -lt 129 ]]; do
|
||||
echo "Password must be between from 12 to 128 characters, please try again."
|
||||
# ask user for length of password
|
||||
printf "Please enter the length of characters you want your password to be (minimum 12): "
|
||||
printf "Please enter the length of characters you want your password to be "
|
||||
printf "(minimum 12): "
|
||||
read -r LENGTH
|
||||
done
|
||||
|
||||
# check length
|
||||
until [[ "$LENGTH" -gt 11 && "$LENGTH" -lt 129 ]]; do
|
||||
echo "Password must be between from 12 to 128 characters, please try again."
|
||||
# ask user for length of password
|
||||
printf "Enter the length of characters you want your password to be (minimum 12): "
|
||||
read -r LENGTH
|
||||
done
|
||||
|
||||
printf "Creating a PiVPN item for your vault..."
|
||||
printf "\n"
|
||||
# create a new item for your PiVPN Password
|
||||
PASSWD=$(bw generate -usln --length "$LENGTH")
|
||||
bw get template item | jq '.login.type = "1"'| jq '.name = "PiVPN"' | jq -r --arg NAME "$NAME" '.login.username = $NAME' | jq -r --arg PASSWD "$PASSWD" '.login.password = $PASSWD' | bw encode | bw create item
|
||||
bw logout
|
||||
printf "Creating a PiVPN item for your vault..."
|
||||
printf "\n"
|
||||
|
||||
# create a new item for your PiVPN Password
|
||||
PASSWD="$(bw generate -usln --length "${LENGTH}")"
|
||||
bw get template item |
|
||||
jq '.login.type = "1"' |
|
||||
jq '.name = "PiVPN"' |
|
||||
jq -r --arg NAME "${NAME}" '.login.username = $NAME' |
|
||||
jq -r --arg PASSWD "${PASSWD}" '.login.password = $PASSWD' |
|
||||
bw encode |
|
||||
bw create item
|
||||
bw logout
|
||||
}
|
||||
|
||||
function keyPASS() {
|
||||
keyPASS() {
|
||||
if [[ -z "${PASSWD}" ]]; then
|
||||
stty -echo
|
||||
|
||||
while true; do
|
||||
printf "Enter the password for the client: "
|
||||
read -r PASSWD
|
||||
printf "\n"
|
||||
printf "Enter the password again to verify: "
|
||||
read -r PASSWD2
|
||||
printf "\n"
|
||||
|
||||
[[ "${PASSWD}" == "${PASSWD2}" ]] && break
|
||||
|
||||
printf "Passwords do not match! Please try again.\n"
|
||||
done
|
||||
|
||||
stty echo
|
||||
|
||||
if [[ -z "${PASSWD}" ]]; then
|
||||
stty -echo
|
||||
while true; do
|
||||
printf "Enter the password for the client: "
|
||||
read -r PASSWD
|
||||
printf "\n"
|
||||
printf "Enter the password again to verify: "
|
||||
read -r PASSWD2
|
||||
printf "\n"
|
||||
[ "${PASSWD}" = "${PASSWD2}" ] && break
|
||||
printf "Passwords do not match! Please try again.\n"
|
||||
done
|
||||
stty echo
|
||||
if [[ -z "${PASSWD}" ]]; then
|
||||
echo "You left the password blank"
|
||||
echo "If you don't want a password, please run:"
|
||||
echo "pivpn add nopass"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ ${#PASSWD} -lt 4 ] || [ ${#PASSWD} -gt 1024 ]; then
|
||||
echo "Password must be between from 4 to 1024 characters"
|
||||
exit 1
|
||||
err "You left the password blank"
|
||||
err "If you don't want a password, please run:"
|
||||
err "pivpn add nopass"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
#Escape chars in PASSWD
|
||||
PASSWD_UNESCAPED="${PASSWD}"
|
||||
PASSWD=$(echo -n "${PASSWD}" | sed -E -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/\$/\\\$/g' -e 's/!/\\!/g' -e 's/\./\\\./g' -e "s/'/\\'/g" -e 's/"/\\"/g' -e 's/\*/\\\*/g' -e 's/@/\\@/g' -e 's/#/\\#/g' -e 's/£/\\£/g' -e 's/%/\\%/g' -e 's/\^/\\\^/g' -e 's/&/\\&/g' -e 's/\(/\\\(/g' -e 's/\)/\\\)/g' -e 's/\-/\\\-/g' -e 's/_/\\_/g' -e 's/\+/\\\+/g' -e 's/=/\\=/g' -e 's/\[/\\\[/g' -e 's/\]/\\\]/g' -e 's/;/\\;/g' -e 's/:/\\:/g' -e 's/\|/\\\|/g' -e 's/\</\\\</g' -e 's/\>/\\\>/g' -e 's/,/\\,/g' -e 's/\?/\\\?/g' -e 's/~/\\~/g' -e 's/\{/\\\{/g' -e 's/\}/\\\}/g')
|
||||
if [[ "${#PASSWD}" -lt 4 ]] || [[ "${#PASSWD}" -gt 1024 ]]; then
|
||||
err "Password must be between from 4 to 1024 characters"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#Build the client key and then encrypt the key
|
||||
# Escape chars in PASSWD
|
||||
PASSWD_UNESCAPED="${PASSWD}"
|
||||
|
||||
expect << EOF
|
||||
set timeout -1
|
||||
set env(EASYRSA_CERT_EXPIRE) "${DAYS}"
|
||||
spawn ./easyrsa build-client-full "${NAME}"
|
||||
expect "Enter PEM pass phrase" { sleep 0.1; send -- "${PASSWD}\r" }
|
||||
expect "Verifying - Enter PEM pass phrase" { sleep 0.1; send -- "${PASSWD}\r" }
|
||||
expect eof
|
||||
PASSWD="${PASSWD//\\/\\\\}"
|
||||
PASSWD="${PASSWD//\//\\\/}"
|
||||
PASSWD="${PASSWD//\$/\\\$}"
|
||||
PASSWD="${PASSWD//!/\\!}"
|
||||
PASSWD="${PASSWD//\./\\\.}"
|
||||
PASSWD="${PASSWD//\'/\\\'}"
|
||||
PASSWD="${PASSWD//\"/\\\"}"
|
||||
PASSWD="${PASSWD//*/\\*}"
|
||||
PASSWD="${PASSWD//@/\\@}"
|
||||
PASSWD="${PASSWD//#/\\#}"
|
||||
PASSWD="${PASSWD//\£/\\\£}"
|
||||
PASSWD="${PASSWD//%/\\%}"
|
||||
PASSWD="${PASSWD//\^/\\\^}"
|
||||
PASSWD="${PASSWD//\&/\\\&}"
|
||||
PASSWD="${PASSWD//\(/\\\(}"
|
||||
PASSWD="${PASSWD//\)/\\\)}"
|
||||
PASSWD="${PASSWD//\-/\\\-}"
|
||||
PASSWD="${PASSWD//\_/\\\_}"
|
||||
PASSWD="${PASSWD//\+/\\\+}"
|
||||
PASSWD="${PASSWD//\=/\\\=}"
|
||||
PASSWD="${PASSWD//\[/\\\[}"
|
||||
PASSWD="${PASSWD//\]/\\\]}"
|
||||
PASSWD="${PASSWD//:/\\:}"
|
||||
PASSWD="${PASSWD//\;/\\\;}"
|
||||
PASSWD="${PASSWD//\|/\\\|}"
|
||||
PASSWD="${PASSWD//\</\\\<}"
|
||||
PASSWD="${PASSWD//\>/\\\>}"
|
||||
PASSWD="${PASSWD//\,/\\\,}"
|
||||
PASSWD="${PASSWD//\~/\\\~}"
|
||||
PASSWD="${PASSWD//\?/\\\?}"
|
||||
PASSWD="${PASSWD//\{/\\\{}"
|
||||
PASSWD="${PASSWD//\}/\\\}}"
|
||||
|
||||
# Build the client key and then encrypt the key
|
||||
expect << EOF
|
||||
set timeout -1
|
||||
set env(EASYRSA_CERT_EXPIRE) "${DAYS}"
|
||||
spawn ./easyrsa build-client-full "${NAME}"
|
||||
expect "Enter PEM pass phrase" {sleep 0.1; send -- "${PASSWD}\r"}
|
||||
expect "Verifying - Enter PEM pass phrase" {sleep 0.1; send -- "${PASSWD}\r"}
|
||||
expect eof
|
||||
EOF
|
||||
cd pki || exit
|
||||
|
||||
cd pki || exit
|
||||
}
|
||||
|
||||
#make sure ovpns dir exists
|
||||
# Disabling warning for SC2154, var sourced externaly
|
||||
# shellcheck disable=SC2154
|
||||
if [ ! -d "$install_home/ovpns" ]; then
|
||||
mkdir "$install_home/ovpns"
|
||||
chown "$install_user":"$install_user" "$install_home/ovpns"
|
||||
chmod 0750 "$install_home/ovpns"
|
||||
if [[ ! -d "${install_home}/ovpns" ]]; then
|
||||
mkdir "${install_home}/ovpns"
|
||||
chown "${install_user}:${install_user}" "${install_home}/ovpns"
|
||||
chmod 0750 "${install_home}/ovpns"
|
||||
fi
|
||||
|
||||
#bitWarden
|
||||
if [[ "${BITWARDEN}" =~ "2" ]]; then
|
||||
useBitwarden
|
||||
fi
|
||||
|
||||
if [ -z "${NAME}" ]; then
|
||||
printf "Enter a Name for the Client: "
|
||||
read -r NAME
|
||||
fi
|
||||
|
||||
if [[ ${NAME::1} == "." ]] || [[ ${NAME::1} == "-" ]]; then
|
||||
echo "Names cannot start with a dot (.) or a dash (-)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${NAME}" =~ [^a-zA-Z0-9.@_-] ]]; then
|
||||
echo "Name can only contain alphanumeric characters and these characters (.-@_)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${NAME}" =~ ^[0-9]+$ ]]; then
|
||||
echo "Names cannot be integers."
|
||||
exit 1
|
||||
useBitwarden
|
||||
fi
|
||||
|
||||
if [[ -z "${NAME}" ]]; then
|
||||
echo "You cannot leave the name blank."
|
||||
exit 1
|
||||
printf "Enter a Name for the Client: "
|
||||
read -r NAME
|
||||
elif [[ "${NAME::1}" == "." ]] || [[ "${NAME::1}" == "-" ]]; then
|
||||
err "Names cannot start with a dot (.) or a dash (-)."
|
||||
exit 1
|
||||
elif [[ "${NAME}" =~ [^a-zA-Z0-9.@_-] ]]; then
|
||||
err "Name can only contain alphanumeric characters and these symbols (.-@_)."
|
||||
exit 1
|
||||
elif [[ "${NAME}" =~ ^[0-9]+$ ]]; then
|
||||
err "Names cannot be integers."
|
||||
exit 1
|
||||
elif [[ -z "${NAME}" ]]; then
|
||||
err "You cannot leave the name blank."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${GENOVPNONLY}" == "1" ]; then
|
||||
# Generate .ovpn configuration file
|
||||
cd /etc/openvpn/easy-rsa/pki || exit
|
||||
if [[ "${GENOVPNONLY}" == 1 ]]; then
|
||||
# Generate .ovpn configuration file
|
||||
cd /etc/openvpn/easy-rsa/pki || exit
|
||||
else
|
||||
# Check if name is already in use
|
||||
while read -r line || [ -n "${line}" ]; do
|
||||
STATUS=$(echo "$line" | awk '{print $1}')
|
||||
# Check if name is already in use
|
||||
while read -r line || [[ -n "${line}" ]]; do
|
||||
STATUS=$(echo "${line}" | awk '{print $1}')
|
||||
|
||||
if [ "${STATUS}" == "V" ]; then
|
||||
# Disabling SC2001 as ${variable//search/replace} doesn't go well with regexp
|
||||
# shellcheck disable=SC2001
|
||||
CERT=$(echo "$line" | sed -e 's:.*/CN=::')
|
||||
if [ "${CERT}" == "${NAME}" ]; then
|
||||
INUSE="1"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done <${INDEX}
|
||||
if [[ "${STATUS}" == "V" ]]; then
|
||||
# Disabling SC2001 as ${variable//search/replace}
|
||||
# doesn't go well with regexp
|
||||
# shellcheck disable=SC2001
|
||||
CERT="$(echo "${line}" | sed -e 's:.*/CN=::')"
|
||||
|
||||
if [ "${INUSE}" == "1" ]; then
|
||||
printf "\n!! This name is already in use by a Valid Certificate."
|
||||
printf "\nPlease choose another name or revoke this certificate first.\n"
|
||||
exit 1
|
||||
if [[ "${CERT}" == "${NAME}" ]]; then
|
||||
INUSE="1"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done < "${INDEX}"
|
||||
|
||||
# Check if name is reserved
|
||||
if [ "${NAME}" == "ta" ] || [ "${NAME}" == "server" ] || [ "${NAME}" == "ca" ]; then
|
||||
echo "Sorry, this is in use by the server and cannot be used by clients."
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${INUSE}" == 1 ]]; then
|
||||
err "!! This name is already in use by a Valid Certificate."
|
||||
err "Please choose another name or revoke this certificate first."
|
||||
exit 1
|
||||
# Check if name is reserved
|
||||
elif [[ "${NAME}" == "ta" ]] ||
|
||||
[[ "${NAME}" == "server" ]] ||
|
||||
[[ "${NAME}" == "ca" ]]; then
|
||||
err "Sorry, this is in use by the server and cannot be used by clients."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#As of EasyRSA 3.0.6, by default certificates last 1080 days, see https://github.com/OpenVPN/easy-rsa/blob/6b7b6bf1f0d3c9362b5618ad18c66677351cacd1/easyrsa3/vars.example
|
||||
if [ -z "${DAYS}" ]; then
|
||||
read -r -e -p "How many days should the certificate last? " -i 1080 DAYS
|
||||
fi
|
||||
# As of EasyRSA 3.0.6, by default certificates last 1080 days,
|
||||
# see https://github.com/OpenVPN/easy-rsa/blob/6b7b6bf1f0d3c9362b5618ad18c66677351cacd1/easyrsa3/vars.example
|
||||
if [[ -z "${DAYS}" ]]; then
|
||||
read -r -e -p "How many days should the certificate last? " -i 1080 DAYS
|
||||
fi
|
||||
|
||||
if [[ ! "$DAYS" =~ ^[0-9]+$ ]] || [ "$DAYS" -lt 1 ] || [ "$DAYS" -gt 3650 ]; then
|
||||
#The CRL lasts 3650 days so it doesn't make much sense that certificates would last longer
|
||||
echo "Please input a valid number of days, between 1 and 3650 inclusive."
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! "${DAYS}" =~ ^[0-9]+$ ]] ||
|
||||
[[ "${DAYS}" -lt 1 ]] ||
|
||||
[[ "${DAYS}" -gt 3650 ]]; then
|
||||
# The CRL lasts 3650 days so it doesn't make much sense
|
||||
# that certificates would last longer
|
||||
err "Please input a valid number of days, between 1 and 3650 inclusive."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd /etc/openvpn/easy-rsa || exit
|
||||
cd /etc/openvpn/easy-rsa || exit
|
||||
|
||||
if [[ "${NO_PASS}" =~ "1" ]]; then
|
||||
if [[ -n "${PASSWD}" ]]; then
|
||||
echo "Both nopass and password arguments passed to the script. Please use either one."
|
||||
exit 1
|
||||
else
|
||||
keynoPASS
|
||||
fi
|
||||
if [[ "${NO_PASS}" =~ "1" ]]; then
|
||||
if [[ -n "${PASSWD}" ]]; then
|
||||
err "Both nopass and password arguments passed to the script. Please use either one."
|
||||
exit 1
|
||||
else
|
||||
keyPASS
|
||||
keynoPASS
|
||||
fi
|
||||
else
|
||||
keyPASS
|
||||
fi
|
||||
fi
|
||||
|
||||
#1st Verify that clients Public Key Exists
|
||||
if [ ! -f "issued/${NAME}${CRT}" ]; then
|
||||
echo "[ERROR]: Client Public Key Certificate not found: $NAME$CRT"
|
||||
exit
|
||||
if [[ ! -f "issued/${NAME}${CRT}" ]]; then
|
||||
err "[ERROR]: Client Public Key Certificate not found: ${NAME}${CRT}"
|
||||
exit
|
||||
fi
|
||||
echo "Client's cert found: $NAME$CRT"
|
||||
|
||||
echo "Client's cert found: ${NAME}${CRT}"
|
||||
|
||||
#Then, verify that there is a private key for that client
|
||||
if [ ! -f "private/${NAME}${KEY}" ]; then
|
||||
echo "[ERROR]: Client Private Key not found: $NAME$KEY"
|
||||
exit
|
||||
if [[ ! -f "private/${NAME}${KEY}" ]]; then
|
||||
err "[ERROR]: Client Private Key not found: ${NAME}${KEY}"
|
||||
exit
|
||||
fi
|
||||
echo "Client's Private Key found: $NAME$KEY"
|
||||
|
||||
echo "Client's Private Key found: ${NAME}${KEY}"
|
||||
|
||||
#Confirm the CA public key exists
|
||||
if [ ! -f "${CA}" ]; then
|
||||
echo "[ERROR]: CA Public Key not found: $CA"
|
||||
exit
|
||||
if [[ ! -f "${CA}" ]]; then
|
||||
err "[ERROR]: CA Public Key not found: ${CA}"
|
||||
exit
|
||||
fi
|
||||
echo "CA public Key found: $CA"
|
||||
|
||||
echo "CA public Key found: ${CA}"
|
||||
|
||||
#Confirm the tls key file exists
|
||||
if [ ! -f "${TA}" ]; then
|
||||
echo "[ERROR]: tls Private Key not found: $TA"
|
||||
exit
|
||||
if [[ ! -f "${TA}" ]]; then
|
||||
err "[ERROR]: tls Private Key not found: ${TA}"
|
||||
exit
|
||||
fi
|
||||
echo "tls Private Key found: $TA"
|
||||
|
||||
echo "tls Private Key found: ${TA}"
|
||||
|
||||
## Added new step to create an .ovpn12 file that can be stored on iOS keychain
|
||||
## This step is more secure method and does not require the end-user to keep entering passwords, or storing the client private cert where it can be easily tampered
|
||||
## This step is more secure method and does not require the end-user to keep
|
||||
## entering passwords, or storing the client private cert where it can be easily
|
||||
## tampered
|
||||
## https://openvpn.net/faq/how-do-i-use-a-client-certificate-and-private-key-from-the-ios-keychain/
|
||||
if [ "$iOS" = "1" ]; then
|
||||
#Generates the .ovpn file WITHOUT the client private key
|
||||
{
|
||||
# Start by populating with the default file
|
||||
cat "${DEFAULT}"
|
||||
|
||||
#Now, append the CA Public Cert
|
||||
echo "<ca>"
|
||||
cat "${CA}"
|
||||
echo "</ca>"
|
||||
# Generates the .ovpn file WITHOUT the client private key
|
||||
{
|
||||
# Start by populating with the default file
|
||||
cat "${DEFAULT}"
|
||||
|
||||
#Next append the client Public Cert
|
||||
echo "<cert>"
|
||||
sed -n -e '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' < "issued/${NAME}${CRT}"
|
||||
echo "</cert>"
|
||||
# Now, append the CA Public Cert
|
||||
echo "<ca>"
|
||||
cat "${CA}"
|
||||
echo "</ca>"
|
||||
|
||||
#Finally, append the tls Private Key
|
||||
echo "<tls-auth>"
|
||||
cat "${TA}"
|
||||
echo "</tls-auth>"
|
||||
# Next append the client Public Cert
|
||||
echo "<cert>"
|
||||
sed \
|
||||
-n \
|
||||
-e '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' \
|
||||
< "issued/${NAME}${CRT}"
|
||||
echo "</cert>"
|
||||
|
||||
} > "${NAME}${FILEEXT}"
|
||||
|
||||
# Copy the .ovpn profile to the home directory for convenient remote access
|
||||
|
||||
printf "========================================================\n"
|
||||
printf "Generating an .ovpn12 file for use with iOS devices\n"
|
||||
printf "Please remember the export password\n"
|
||||
printf "as you will need this import the certificate on your iOS device\n"
|
||||
printf "========================================================\n"
|
||||
openssl pkcs12 -passin pass:"$PASSWD_UNESCAPED" -export -in "issued/${NAME}${CRT}" -inkey "private/${NAME}${KEY}" -certfile ${CA} -name "${NAME}" -out "$install_home/ovpns/$NAME.ovpn12"
|
||||
chown "$install_user":"$install_user" "$install_home/ovpns/$NAME.ovpn12"
|
||||
chmod 640 "$install_home/ovpns/$NAME.ovpn12"
|
||||
printf "========================================================\n"
|
||||
printf "\e[1mDone! %s successfully created!\e[0m \n" "$NAME.ovpn12"
|
||||
printf "You will need to transfer both the .ovpn and .ovpn12 files\n"
|
||||
printf "to your iOS device.\n"
|
||||
printf "========================================================\n\n"
|
||||
else
|
||||
#This is the standard non-iOS configuration
|
||||
#Ready to make a new .ovpn file
|
||||
{
|
||||
# Start by populating with the default file
|
||||
cat "${DEFAULT}"
|
||||
|
||||
#Now, append the CA Public Cert
|
||||
echo "<ca>"
|
||||
cat "${CA}"
|
||||
echo "</ca>"
|
||||
|
||||
#Next append the client Public Cert
|
||||
echo "<cert>"
|
||||
sed -n -e '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' < "issued/${NAME}${CRT}"
|
||||
echo "</cert>"
|
||||
|
||||
#Then, append the client Private Key
|
||||
if [[ "${iOS}" != 1 ]]; then
|
||||
# Then, append the client Private Key
|
||||
echo "<key>"
|
||||
cat "private/${NAME}${KEY}"
|
||||
echo "</key>"
|
||||
fi
|
||||
|
||||
#Finally, append the tls Private Key
|
||||
if [ "$TWO_POINT_FOUR" -eq 1 ]; then
|
||||
echo "<tls-crypt>"
|
||||
cat "${TA}"
|
||||
echo "</tls-crypt>"
|
||||
else
|
||||
echo "<tls-auth>"
|
||||
cat "${TA}"
|
||||
echo "</tls-auth>"
|
||||
fi
|
||||
# Finally, append the tls Private Key
|
||||
if [[ "${iOS}" != 1 ]] && [[ "${TWO_POINT_FOUR}" -eq 1 ]]; then
|
||||
echo "<tls-crypt>"
|
||||
cat "${TA}"
|
||||
echo "</tls-crypt>"
|
||||
else
|
||||
echo "<tls-auth>"
|
||||
cat "${TA}"
|
||||
echo "</tls-auth>"
|
||||
fi
|
||||
} > "${NAME}${FILEEXT}"
|
||||
|
||||
} > "${NAME}${FILEEXT}"
|
||||
if [[ "${iOS}" == 1 ]]; then
|
||||
# Copy the .ovpn profile to the home directory for convenient remote access
|
||||
printf "========================================================\n"
|
||||
printf "Generating an .ovpn12 file for use with iOS devices\n"
|
||||
printf "Please remember the export password\n"
|
||||
printf "as you will need this import the certificate on your iOS device\n"
|
||||
printf "========================================================\n"
|
||||
|
||||
openssl pkcs12 \
|
||||
-passin pass:"${PASSWD_UNESCAPED}" \
|
||||
-export \
|
||||
-in "issued/${NAME}${CRT}" \
|
||||
-inkey "private/${NAME}${KEY}" \
|
||||
-certfile "${CA}" \
|
||||
-name "${NAME}" \
|
||||
-out "${install_home}/ovpns/${NAME}.ovpn12"
|
||||
|
||||
chown "${install_user}:${install_user}" "${install_home}/ovpns/${NAME}.ovpn12"
|
||||
chmod 640 "${install_home}/ovpns/${NAME}.ovpn12"
|
||||
|
||||
printf "========================================================\n"
|
||||
printf "\e[1mDone! %s successfully created!\e[0m \n" "${NAME}.ovpn12"
|
||||
printf "You will need to transfer both the .ovpn and .ovpn12 files\n"
|
||||
printf "to your iOS device.\n"
|
||||
printf "========================================================\n\n"
|
||||
fi
|
||||
|
||||
cidrToMask(){
|
||||
# Source: https://stackoverflow.com/a/20767392
|
||||
set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
|
||||
shift "$1"
|
||||
echo "${1-0}"."${2-0}"."${3-0}"."${4-0}"
|
||||
cidrToMask() {
|
||||
# Source: https://stackoverflow.com/a/20767392
|
||||
set -- $((5 - (${1} / 8))) \
|
||||
255 255 255 255 \
|
||||
$(((255 << (8 - (${1} % 8))) & 255)) \
|
||||
0 0 0
|
||||
shift "${1}"
|
||||
echo "${1-0}.${2-0}.${3-0}.${4-0}"
|
||||
}
|
||||
|
||||
#disabling SC2514, variable sourced externaly
|
||||
|
@ -441,37 +511,45 @@ NET_REDUCED="${pivpnNET::-2}"
|
|||
|
||||
# Find an unused number for the last octet of the client IP
|
||||
for i in {2..254}; do
|
||||
# find returns 0 if the folder is empty, so we create the 'ls -A [...]'
|
||||
# exception to stop at the first static IP (10.8.0.2). Otherwise it would
|
||||
# cycle to the end without finding and available octet.
|
||||
# disabling SC2514, variable sourced externaly
|
||||
# shellcheck disable=SC2154
|
||||
if [ -z "$(ls -A /etc/openvpn/ccd)" ] || ! find /etc/openvpn/ccd -type f -exec grep -q "${NET_REDUCED}.${i}" {} +; then
|
||||
COUNT="${i}"
|
||||
echo "ifconfig-push ${NET_REDUCED}.${i} $(cidrToMask "$subnetClass")" >> /etc/openvpn/ccd/"${NAME}"
|
||||
break
|
||||
fi
|
||||
# find returns 0 if the folder is empty, so we create the 'ls -A [...]'
|
||||
# exception to stop at the first static IP (10.8.0.2). Otherwise it would
|
||||
# cycle to the end without finding and available octet.
|
||||
# disabling SC2514, variable sourced externaly
|
||||
# shellcheck disable=SC2154
|
||||
if [[ -z "$(ls -A /etc/openvpn/ccd)" ]] ||
|
||||
! find /etc/openvpn/ccd \
|
||||
-type f \
|
||||
-exec grep -q "${NET_REDUCED}.${i}" {} +; then
|
||||
COUNT="${i}"
|
||||
echo -n "ifconfig-push ${NET_REDUCED}.${i}" >> /etc/openvpn/ccd/"${NAME}"
|
||||
cidrToMask "${subnetClass}" >> /etc/openvpn/ccd/"${NAME}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -f /etc/pivpn/hosts.openvpn ]; then
|
||||
echo "${NET_REDUCED}.${COUNT} ${NAME}.pivpn" >> /etc/pivpn/hosts.openvpn
|
||||
if killall -SIGHUP pihole-FTL; then
|
||||
echo "::: Updated hosts file for Pi-hole"
|
||||
else
|
||||
echo "::: Failed to reload pihole-FTL configuration"
|
||||
fi
|
||||
if [[ -f /etc/pivpn/hosts.openvpn ]]; then
|
||||
echo "${NET_REDUCED}.${COUNT} ${NAME}.pivpn" >> /etc/pivpn/hosts.openvpn
|
||||
|
||||
if killall -SIGHUP pihole-FTL; then
|
||||
echo "::: Updated hosts file for Pi-hole"
|
||||
else
|
||||
err "::: Failed to reload pihole-FTL configuration"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Copy the .ovpn profile to the home directory for convenient remote access
|
||||
cp "/etc/openvpn/easy-rsa/pki/$NAME$FILEEXT" "$install_home/ovpns/$NAME$FILEEXT"
|
||||
chown "$install_user":"$install_user" "$install_home/ovpns/$NAME$FILEEXT"
|
||||
chmod 640 "/etc/openvpn/easy-rsa/pki/$NAME$FILEEXT"
|
||||
chmod 640 "$install_home/ovpns/$NAME$FILEEXT"
|
||||
dest_path="${install_home}/ovpns/${NAME}${FILEEXT}"
|
||||
cp "/etc/openvpn/easy-rsa/pki/${NAME}${FILEEXT}" "${dest_path}"
|
||||
chown "${install_user}:${install_user}" "${dest_path}"
|
||||
chmod 640 "/etc/openvpn/easy-rsa/pki/${NAME}${FILEEXT}"
|
||||
chmod 640 "${dest_path}"
|
||||
unset dest_path
|
||||
|
||||
printf "\n\n"
|
||||
printf "========================================================\n"
|
||||
printf "\e[1mDone! %s successfully created!\e[0m \n" "$NAME$FILEEXT"
|
||||
printf "%s was copied to:\n" "$NAME$FILEEXT"
|
||||
printf " %s/ovpns\n" "$install_home"
|
||||
printf "\e[1mDone! %s successfully created!\e[0m \n" "${NAME}${FILEEXT}"
|
||||
printf "%s was copied to:\n" "${NAME}${FILEEXT}"
|
||||
printf " %s/ovpns\n" "${install_home}"
|
||||
printf "for easy transfer. Please use this profile only on one\n"
|
||||
printf "device and create additional profiles for other devices.\n"
|
||||
printf "========================================================\n\n"
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
CHECK_PKG_INSTALLED='dpkg-query -s'
|
||||
|
||||
if grep -qsEe "^NAME\=['\"]?Alpine[a-zA-Z ]*['\"]?$" /etc/os-release; then
|
||||
CHECK_PKG_INSTALLED='apk --no-cache info -e'
|
||||
CHECK_PKG_INSTALLED='apk --no-cache info -e'
|
||||
fi
|
||||
|
||||
# Must be root to use this tool
|
||||
if [[ ! $EUID -eq 0 ]]; then
|
||||
if eval "${CHECK_PKG_INSTALLED} sudo" &> /dev/null; then
|
||||
export SUDO="sudo"
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
if ${CHECK_PKG_INSTALLED} sudo &> /dev/null; then
|
||||
export SUDO="sudo"
|
||||
else
|
||||
echo "::: Please install sudo or run this as root."
|
||||
err "::: Please install sudo or run this as root."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
@ -19,88 +19,113 @@ fi
|
|||
scriptDir="/opt/pivpn"
|
||||
vpn="openvpn"
|
||||
|
||||
function makeOVPNFunc {
|
||||
shift
|
||||
$SUDO ${scriptDir}/${vpn}/makeOVPN.sh "$@"
|
||||
exit "$?"
|
||||
err() {
|
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||
}
|
||||
|
||||
function listClientsFunc {
|
||||
shift
|
||||
$SUDO ${scriptDir}/${vpn}/clientStat.sh "$@"
|
||||
exit "$?"
|
||||
makeOVPNFunc() {
|
||||
shift
|
||||
${SUDO} "${scriptDir}/${vpn}/makeOVPN.sh" "$@"
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
function listOVPNFunc {
|
||||
$SUDO ${scriptDir}/${vpn}/listOVPN.sh
|
||||
exit "$?"
|
||||
listClientsFunc() {
|
||||
shift
|
||||
${SUDO} "${scriptDir}/${vpn}/clientStat.sh" "$@"
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
function debugFunc {
|
||||
echo "::: Generating Debug Output"
|
||||
$SUDO ${scriptDir}/${vpn}/pivpnDebug.sh | tee /tmp/debug.log
|
||||
echo "::: "
|
||||
echo "::: Debug output completed above."
|
||||
echo "::: Copy saved to /tmp/debug.log"
|
||||
echo "::: "
|
||||
exit "$?"
|
||||
listOVPNFunc() {
|
||||
${SUDO} "${scriptDir}/${vpn}/listOVPN.sh"
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
function removeOVPNFunc {
|
||||
shift
|
||||
$SUDO ${scriptDir}/${vpn}/removeOVPN.sh "$@"
|
||||
exit "$?"
|
||||
debugFunc() {
|
||||
echo "::: Generating Debug Output"
|
||||
|
||||
${SUDO} "${scriptDir}/${vpn}/pivpnDebug.sh" | tee /tmp/debug.log
|
||||
|
||||
echo "::: "
|
||||
echo "::: Debug output completed above."
|
||||
echo "::: Copy saved to /tmp/debug.log"
|
||||
echo "::: "
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
function uninstallFunc {
|
||||
$SUDO ${scriptDir}/uninstall.sh "${vpn}"
|
||||
exit "$?"
|
||||
removeOVPNFunc() {
|
||||
shift
|
||||
${SUDO} "${scriptDir}/${vpn}/removeOVPN.sh" "$@"
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
function update {
|
||||
shift
|
||||
$SUDO ${scriptDir}/update.sh "$@"
|
||||
exit "$?"
|
||||
uninstallFunc() {
|
||||
${SUDO} "${scriptDir}/uninstall.sh" "${vpn}"
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
function backup {
|
||||
$SUDO ${scriptDir}/backup.sh "${vpn}"
|
||||
exit "$?"
|
||||
update() {
|
||||
shift
|
||||
${SUDO} "${scriptDir}/update.sh" "$@"
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
|
||||
function helpFunc {
|
||||
echo "::: Control all PiVPN specific functions!"
|
||||
echo ":::"
|
||||
echo "::: Usage: pivpn <command> [option]"
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: -a, add [nopass] Create a client ovpn profile, optional nopass"
|
||||
echo "::: -c, clients List any connected clients to the server"
|
||||
echo "::: -d, debug Start a debugging session if having trouble"
|
||||
echo "::: -l, list List all valid and revoked certificates"
|
||||
echo "::: -r, revoke Revoke a client ovpn profile"
|
||||
echo "::: -h, help Show this help dialog"
|
||||
echo "::: -u, uninstall Uninstall PiVPN from your system!"
|
||||
echo "::: -up, update Updates PiVPN Scripts"
|
||||
echo "::: -bk, backup Backup Openvpn and ovpns dir"
|
||||
exit 0
|
||||
backup() {
|
||||
${SUDO} "${scriptDir}/backup.sh" "${vpn}"
|
||||
exit "${?}"
|
||||
}
|
||||
|
||||
if [[ $# = 0 ]]; then
|
||||
helpFunc
|
||||
helpFunc() {
|
||||
echo "::: Control all PiVPN specific functions!"
|
||||
echo ":::"
|
||||
echo "::: Usage: pivpn <command> [option]"
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: -a, add [nopass] Create a client ovpn profile, optional nopass"
|
||||
echo "::: -c, clients List any connected clients to the server"
|
||||
echo "::: -d, debug Start a debugging session if having trouble"
|
||||
echo "::: -l, list List all valid and revoked certificates"
|
||||
echo "::: -r, revoke Revoke a client ovpn profile"
|
||||
echo "::: -h, help Show this help dialog"
|
||||
echo "::: -u, uninstall Uninstall PiVPN from your system!"
|
||||
echo "::: -up, update Updates PiVPN Scripts"
|
||||
echo "::: -bk, backup Backup Openvpn and ovpns dir"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [[ "$#" == 0 ]]; then
|
||||
helpFunc
|
||||
fi
|
||||
|
||||
# Handle redirecting to specific functions based on arguments
|
||||
case "$1" in
|
||||
"-a" | "add" ) makeOVPNFunc "$@";;
|
||||
"-c" | "clients" ) listClientsFunc "$@";;
|
||||
"-d" | "debug" ) debugFunc;;
|
||||
"-l" | "list" ) listOVPNFunc;;
|
||||
"-r" | "revoke" ) removeOVPNFunc "$@";;
|
||||
"-h" | "help" ) helpFunc;;
|
||||
"-u" | "uninstall" ) uninstallFunc;;
|
||||
"-up"| "update" ) update "$@" ;;
|
||||
"-bk"| "backup" ) backup;;
|
||||
* ) helpFunc;;
|
||||
case "${1}" in
|
||||
"-a" | "add")
|
||||
makeOVPNFunc "$@"
|
||||
;;
|
||||
"-c" | "clients")
|
||||
listClientsFunc "$@"
|
||||
;;
|
||||
"-d" | "debug")
|
||||
debugFunc
|
||||
;;
|
||||
"-l" | "list")
|
||||
listOVPNFunc
|
||||
;;
|
||||
"-r" | "revoke")
|
||||
removeOVPNFunc "$@"
|
||||
;;
|
||||
"-h" | "help")
|
||||
helpFunc
|
||||
;;
|
||||
"-u" | "uninstall")
|
||||
uninstallFunc
|
||||
;;
|
||||
"-up" | "update")
|
||||
update "$@"
|
||||
;;
|
||||
"-bk" | "backup")
|
||||
backup
|
||||
;;
|
||||
*)
|
||||
helpFunc
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# This scripts runs as root
|
||||
|
||||
setupVars="/etc/pivpn/openvpn/setupVars.conf"
|
||||
|
||||
if [ ! -f "${setupVars}" ]; then
|
||||
echo "::: Missing setup vars file!"
|
||||
exit 1
|
||||
err() {
|
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||
}
|
||||
|
||||
if [[ ! -f "${setupVars}" ]]; then
|
||||
err "::: Missing setup vars file!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
|
@ -15,41 +19,63 @@ echo -e "::::\t\t\e[4mPiVPN debug\e[0m\t\t ::::"
|
|||
printf "=============================================\n"
|
||||
echo -e "::::\t\t\e[4mLatest commit\e[0m\t\t ::::"
|
||||
echo -n "Branch: "
|
||||
|
||||
git --git-dir /usr/local/src/pivpn/.git rev-parse --abbrev-ref HEAD
|
||||
git --git-dir /usr/local/src/pivpn/.git log -n 1 --format='Commit: %H%nAuthor: %an%nDate: %ad%nSummary: %s'
|
||||
git \
|
||||
--git-dir /usr/local/src/pivpn/.git log \
|
||||
-n 1 \
|
||||
--format='Commit: %H%nAuthor: %an%nDate: %ad%nSummary: %s'
|
||||
|
||||
printf "=============================================\n"
|
||||
echo -e "::::\t \e[4mInstallation settings\e[0m \t ::::"
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
sed "s/$pivpnHOST/REDACTED/" < ${setupVars}
|
||||
sed "s/${pivpnHOST}/REDACTED/" < "${setupVars}"
|
||||
|
||||
printf "=============================================\n"
|
||||
echo -e ":::: \e[4mServer configuration shown below\e[0m ::::"
|
||||
|
||||
cat /etc/openvpn/server.conf
|
||||
|
||||
printf "=============================================\n"
|
||||
echo -e ":::: \e[4mClient template file shown below\e[0m ::::"
|
||||
sed "s/$pivpnHOST/REDACTED/" < /etc/openvpn/easy-rsa/pki/Default.txt
|
||||
|
||||
sed "s/${pivpnHOST}/REDACTED/" < /etc/openvpn/easy-rsa/pki/Default.txt
|
||||
|
||||
printf "=============================================\n"
|
||||
echo -e ":::: \t\e[4mRecursive list of files in\e[0m\t ::::\n::: \e[4m/etc/openvpn/easy-rsa/pki shows below\e[0m :::"
|
||||
echo -e ":::: \t\e[4mRecursive list of files in\e[0m\t ::::\n"
|
||||
echo -e "::: \e[4m/etc/openvpn/easy-rsa/pki shows below\e[0m :::"
|
||||
|
||||
ls -LR /etc/openvpn/easy-rsa/pki/ -Ireqs -Icerts_by_serial
|
||||
|
||||
printf "=============================================\n"
|
||||
echo -e "::::\t\t\e[4mSelf check\e[0m\t\t ::::"
|
||||
|
||||
/opt/pivpn/self_check.sh "${VPN}"
|
||||
|
||||
printf "=============================================\n"
|
||||
echo -e ":::: Having trouble connecting? Take a look at the FAQ:"
|
||||
echo -e ":::: \e[1mhttps://docs.pivpn.io/faq\e[0m"
|
||||
printf "=============================================\n"
|
||||
|
||||
if [ "${PLAT}" != 'Alpine' ]; then
|
||||
echo -e ":::: \e[4mSnippet of the server log\e[0m ::::"
|
||||
OVPNLOG="$(tail -n 20 /var/log/openvpn.log)"
|
||||
if [[ "${PLAT}" != 'Alpine' ]]; then
|
||||
echo -e ":::: \e[4mSnippet of the server log\e[0m ::::"
|
||||
OVPNLOG="$(tail -n 20 /var/log/openvpn.log)"
|
||||
|
||||
# Regular expession taken from https://superuser.com/a/202835, it will match invalid IPs
|
||||
# like 123.456.789.012 but it's fine since the log only contains valid ones.
|
||||
declare -a IPS_TO_HIDE=("$(grepcidr -v 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 <<< "$OVPNLOG" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | uniq)")
|
||||
for IP in "${IPS_TO_HIDE[@]}"; do
|
||||
OVPNLOG="${OVPNLOG//"$IP"/REDACTED}"
|
||||
done
|
||||
# Regular expession taken from https://superuser.com/a/202835,
|
||||
# it will match invalid IPs like 123.456.789.012 but it's fine
|
||||
# since the log only contains valid ones.
|
||||
declare -a IPS_TO_HIDE=("$(echo "${OVPNLOG}" |
|
||||
grepcidr -v 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 |
|
||||
grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' |
|
||||
uniq)")
|
||||
|
||||
echo "$OVPNLOG"
|
||||
printf "=============================================\n"
|
||||
for IP in "${IPS_TO_HIDE[@]}"; do
|
||||
OVPNLOG="${OVPNLOG//"$IP"/REDACTED}"
|
||||
done
|
||||
|
||||
echo "${OVPNLOG}"
|
||||
printf "=============================================\n"
|
||||
fi
|
||||
|
||||
echo -e "::::\t\t\e[4mDebug complete\e[0m\t\t ::::"
|
||||
|
|
|
@ -1,172 +1,196 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# PiVPN: revoke client script
|
||||
|
||||
setupVars="/etc/pivpn/openvpn/setupVars.conf"
|
||||
INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
|
||||
|
||||
if [ ! -f "${setupVars}" ]; then
|
||||
echo "::: Missing setup vars file!"
|
||||
exit 1
|
||||
if [[ ! -f "${setupVars}" ]]; then
|
||||
err "::: Missing setup vars file!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${setupVars}"
|
||||
|
||||
err() {
|
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||
}
|
||||
|
||||
helpFunc() {
|
||||
echo "::: Revoke a client ovpn profile"
|
||||
echo ":::"
|
||||
echo "::: Usage: pivpn <-r|revoke> [-y|--yes] [-h|--help] [<client-1>] ... [<client-n>] ..."
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: [none] Interactive mode"
|
||||
echo "::: <client> Client(s) to to revoke"
|
||||
echo "::: -y,--yes Remove Client(s) without confirmation"
|
||||
echo "::: -h,--help Show this help dialog"
|
||||
echo "::: Revoke a client ovpn profile"
|
||||
echo ":::"
|
||||
echo -n "::: Usage: pivpn <-r|revoke> [-y|--yes] [-h|--help] "
|
||||
echo "[<client-1> ... [<client-2>] ...]"
|
||||
echo ":::"
|
||||
echo "::: Commands:"
|
||||
echo "::: [none] Interactive mode"
|
||||
echo "::: <client> Client(s) to to revoke"
|
||||
echo "::: -y,--yes Remove Client(s) without confirmation"
|
||||
echo "::: -h,--help Show this help dialog"
|
||||
}
|
||||
|
||||
# Parse input arguments
|
||||
while test $# -gt 0; do
|
||||
_key="$1"
|
||||
case "$_key" in
|
||||
-h|--help)
|
||||
helpFunc
|
||||
exit 0
|
||||
;;
|
||||
-y|--yes)
|
||||
CONFIRM=true
|
||||
;;
|
||||
*)
|
||||
CERTS_TO_REVOKE+=("$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
_key="${1}"
|
||||
|
||||
case "${_key}" in
|
||||
-h | --help)
|
||||
helpFunc
|
||||
exit 0
|
||||
;;
|
||||
-y | --yes)
|
||||
CONFIRM=true
|
||||
;;
|
||||
*)
|
||||
CERTS_TO_REVOKE+=("${1}")
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ ! -f "${INDEX}" ]; then
|
||||
printf "The file: %s was not found\n" "$INDEX"
|
||||
exit 1
|
||||
if [[ ! -f "${INDEX}" ]]; then
|
||||
err "The file: ${INDEX} was not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Disabling SC2128, just checking if variable is empty or not
|
||||
# shellcheck disable=SC2128
|
||||
if [[ -z "${CERTS_TO_REVOKE}" ]]; then
|
||||
printf "\n"
|
||||
printf " ::\e[4m Certificate List \e[0m:: \n"
|
||||
printf "\n"
|
||||
printf " ::\e[4m Certificate List \e[0m:: \n"
|
||||
|
||||
i=0
|
||||
while read -r line || [ -n "$line" ]; do
|
||||
STATUS=$(echo "$line" | awk '{print $1}')
|
||||
if [[ "${STATUS}" = "V" ]]; then
|
||||
# Disabling SC2001 warning, suggested method doesn't work with regexp
|
||||
# shellcheck disable=SC2001
|
||||
NAME=$(echo "$line" | sed -e 's:.*/CN=::')
|
||||
if [ "$i" != 0 ]; then
|
||||
# Prevent printing "server" certificate
|
||||
CERTS[$i]=$(echo -e "${NAME}")
|
||||
fi
|
||||
((i++))
|
||||
fi
|
||||
done <${INDEX}
|
||||
i=0
|
||||
while read -r line || [[ -n "${line}" ]]; do
|
||||
STATUS=$(echo "${line}" | awk '{print $1}')
|
||||
|
||||
i=1
|
||||
len=${#CERTS[@]}
|
||||
while [ $i -le "${len}" ]; do
|
||||
printf "%0${#len}s) %s\r\n" ${i} "${CERTS[(($i))]}"
|
||||
((i++))
|
||||
done
|
||||
printf "\n"
|
||||
if [[ "${STATUS}" == "V" ]]; then
|
||||
# Disabling SC2001 warning, suggested method doesn't work with regexp
|
||||
# shellcheck disable=SC2001
|
||||
NAME=$(echo "${line}" | sed -e 's:.*/CN=::')
|
||||
|
||||
echo -n "::: Please enter the Index/Name of the client to be revoked from the list above: "
|
||||
read -r NAME
|
||||
if [[ "${i}" != 0 ]]; then
|
||||
# Prevent printing "server" certificate
|
||||
CERTS["${i}"]=$(echo -e "${NAME}")
|
||||
fi
|
||||
|
||||
if [[ -z "${NAME}" ]]; then
|
||||
echo "You can not leave this blank!"
|
||||
exit 1
|
||||
((i++))
|
||||
fi
|
||||
done < "${INDEX}"
|
||||
|
||||
re='^[0-9]+$'
|
||||
if [[ ${NAME} =~ $re ]] ; then
|
||||
NAME=${CERTS[$((NAME))]}
|
||||
i=1
|
||||
len="${#CERTS[@]}"
|
||||
while [[ "${i}" -le "${len}" ]]; do
|
||||
printf "%0${#len}s) %s\r\n" "${i}" "${CERTS[(($i))]}"
|
||||
((i++))
|
||||
done
|
||||
|
||||
printf "\n"
|
||||
echo -n "::: Please enter the Index/Name of the client to be revoked "
|
||||
echo -n "from the list above: "
|
||||
read -r NAME
|
||||
|
||||
if [[ -z "${NAME}" ]]; then
|
||||
err "You can not leave this blank!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
re='^[0-9]+$'
|
||||
if [[ "${NAME}" =~ $re ]]; then
|
||||
NAME="${CERTS[$((NAME))]}"
|
||||
fi
|
||||
|
||||
for ((x = 1; x <= i; ++x)); do
|
||||
if [[ "${CERTS[$x]}" == "${NAME}" ]]; then
|
||||
VALID=1
|
||||
fi
|
||||
done
|
||||
|
||||
for((x=1;x<=i;++x)); do
|
||||
if [ "${CERTS[$x]}" = "${NAME}" ]; then
|
||||
VALID=1
|
||||
fi
|
||||
done
|
||||
if [[ -z "${VALID}" ]]; then
|
||||
err "You didn't enter a valid cert name!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${VALID}" ]; then
|
||||
printf "You didn't enter a valid cert name!\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CERTS_TO_REVOKE=( "${NAME}" )
|
||||
CERTS_TO_REVOKE=("${NAME}")
|
||||
else
|
||||
i=0
|
||||
while read -r line || [ -n "$line" ]; do
|
||||
STATUS=$(echo "$line" | awk '{print $1}')
|
||||
if [[ "${STATUS}" = "V" ]]; then
|
||||
NAME=$(echo -e "$line" | sed -e 's:.*/CN=::')
|
||||
CERTS[$i]=${NAME}
|
||||
((i++))
|
||||
fi
|
||||
done <${INDEX}
|
||||
i=0
|
||||
while read -r line || [[ -n "${line}" ]]; do
|
||||
STATUS=$(echo "${line}" | awk '{print $1}')
|
||||
|
||||
for (( ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
|
||||
VALID=0
|
||||
for((x=1;x<=i;++x)); do
|
||||
if [ "${CERTS[$x]}" = "${CERTS_TO_REVOKE[ii]}" ]; then
|
||||
VALID=1
|
||||
fi
|
||||
done
|
||||
if [[ "${STATUS}" == "V" ]]; then
|
||||
NAME=$(echo -e "${line}" | sed -e 's:.*/CN=::')
|
||||
CERTS["${i}"]="${NAME}"
|
||||
((i++))
|
||||
fi
|
||||
done < "${INDEX}"
|
||||
|
||||
if [ "${VALID}" != 1 ]; then
|
||||
printf "You passed an invalid cert name: '%s'! \n" "${CERTS_TO_REVOKE[ii]}"
|
||||
exit 1
|
||||
fi
|
||||
for ((ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
|
||||
VALID=0
|
||||
|
||||
for ((x = 1; x <= i; ++x)); do
|
||||
if [[ "${CERTS[$x]}" == "${CERTS_TO_REVOKE[ii]}" ]]; then
|
||||
VALID=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${VALID}" != 1 ]]; then
|
||||
err "You passed an invalid cert name: '${CERTS_TO_REVOKE[ii]}'!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
cd /etc/openvpn/easy-rsa || exit
|
||||
|
||||
for (( ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
|
||||
if [ -n "$CONFIRM" ]; then
|
||||
REPLY="y"
|
||||
else
|
||||
read -r -p "Do you really want to revoke '${CERTS_TO_REVOKE[ii]}'? [y/N] "
|
||||
fi
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
printf "\n::: Revoking certificate '%s'. \n" "${CERTS_TO_REVOKE[ii]}"
|
||||
./easyrsa --batch revoke "${CERTS_TO_REVOKE[ii]}"
|
||||
./easyrsa gen-crl
|
||||
printf "\n::: Certificate revoked, and CRL file updated.\n"
|
||||
printf "::: Removing certs and client configuration for this profile.\n"
|
||||
rm -rf "pki/reqs/${CERTS_TO_REVOKE[ii]}.req"
|
||||
rm -rf "pki/private/${CERTS_TO_REVOKE[ii]}.key"
|
||||
rm -rf "pki/issued/${CERTS_TO_REVOKE[ii]}.crt"
|
||||
|
||||
# Disabling SC2154 $pivpnNET sourced externally
|
||||
# shellcheck disable=SC2154
|
||||
# Grab the client IP address
|
||||
NET_REDUCED="${pivpnNET::-2}"
|
||||
STATIC_IP=$(grep -v "^#" /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}" | grep -w ifconfig-push | grep -oE "${NET_REDUCED}\.[0-9]{1,3}")
|
||||
rm -rf /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}"
|
||||
|
||||
# disablung warning SC2154, $install_home sourced externally
|
||||
# shellcheck disable=SC2154
|
||||
rm -rf "${install_home}/ovpns/${CERTS_TO_REVOKE[ii]}.ovpn"
|
||||
rm -rf "/etc/openvpn/easy-rsa/pki/${CERTS_TO_REVOKE[ii]}.ovpn"
|
||||
cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem
|
||||
|
||||
# If using Pi-hole, remove the client from the hosts file
|
||||
if [ -f /etc/pivpn/hosts.openvpn ]; then
|
||||
sed "\#${STATIC_IP} ${CERTS_TO_REVOKE[ii]}.pivpn#d" -i /etc/pivpn/hosts.openvpn
|
||||
if killall -SIGHUP pihole-FTL; then
|
||||
echo "::: Updated hosts file for Pi-hole"
|
||||
else
|
||||
echo "::: Failed to reload pihole-FTL configuration"
|
||||
fi
|
||||
fi
|
||||
for ((ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
|
||||
if [[ -n "${CONFIRM}" ]]; then
|
||||
REPLY="y"
|
||||
else
|
||||
read -r -p "Do you really want to revoke '${CERTS_TO_REVOKE[ii]}'? [y/N] "
|
||||
fi
|
||||
|
||||
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
|
||||
printf "\n::: Revoking certificate '%s'. \n" "${CERTS_TO_REVOKE[ii]}"
|
||||
|
||||
./easyrsa --batch revoke "${CERTS_TO_REVOKE[ii]}"
|
||||
./easyrsa gen-crl
|
||||
|
||||
printf "\n::: Certificate revoked, and CRL file updated.\n"
|
||||
printf "::: Removing certs and client configuration for this profile.\n"
|
||||
|
||||
rm -rf "pki/reqs/${CERTS_TO_REVOKE[ii]}.req"
|
||||
rm -rf "pki/private/${CERTS_TO_REVOKE[ii]}.key"
|
||||
rm -rf "pki/issued/${CERTS_TO_REVOKE[ii]}.crt"
|
||||
|
||||
# Disabling SC2154 $pivpnNET sourced externally
|
||||
# shellcheck disable=SC2154
|
||||
# Grab the client IP address
|
||||
NET_REDUCED="${pivpnNET::-2}"
|
||||
STATIC_IP="$(grep -v "^#" /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}" |
|
||||
grep -w ifconfig-push |
|
||||
grep -oE "${NET_REDUCED}\.[0-9]{1,3}")"
|
||||
rm -rf /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}"
|
||||
|
||||
# disablung warning SC2154, $install_home sourced externally
|
||||
# shellcheck disable=SC2154
|
||||
rm -rf "${install_home}/ovpns/${CERTS_TO_REVOKE[ii]}.ovpn"
|
||||
rm -rf "/etc/openvpn/easy-rsa/pki/${CERTS_TO_REVOKE[ii]}.ovpn"
|
||||
cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem
|
||||
|
||||
# If using Pi-hole, remove the client from the hosts file
|
||||
if [[ -f /etc/pivpn/hosts.openvpn ]]; then
|
||||
sed \
|
||||
-e "\#${STATIC_IP} ${CERTS_TO_REVOKE[ii]}.pivpn#d" \
|
||||
-i \
|
||||
/etc/pivpn/hosts.openvpn
|
||||
|
||||
if killall -SIGHUP pihole-FTL; then
|
||||
echo "::: Updated hosts file for Pi-hole"
|
||||
else
|
||||
err "::: Failed to reload pihole-FTL configuration"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
printf "::: Completed!\n"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue