diff --git a/bin/lemper-cli.sh b/bin/lemper-cli.sh index 9995212..0fdd01c 100644 --- a/bin/lemper-cli.sh +++ b/bin/lemper-cli.sh @@ -20,16 +20,57 @@ set -e -o pipefail # Version control. -PROG_NAME=$(basename "$0") -PROG_VER="2.x.x" +export PROG_NAME && PROG_NAME=$(basename "$0") +export PROG_VERSION && PROG_VERSION="2.x.x" # Test mode. DRYRUN=false +# Make sure only root can run this script. +function requires_root() { + if [[ "$(id -u)" -ne 0 ]]; then + if ! hash sudo 2>/dev/null; then + echo "${PROG_NAME} command must be run as 'root' or with sudo." + exit 1 + else + #echo "Switching to root user to run this script." + sudo -E "$0" "$@" + exit 0 + fi + fi +} + +requires_root "$@" + +# Export LEMPer Stack configuration. +if [[ -f "/etc/lemper/lemper.conf" ]]; then + # Clean environemnt first. + # shellcheck source=/etc/lemper/lemper.conf + # shellcheck disable=SC2046 + unset $(grep -v '^#' /etc/lemper/lemper.conf | grep -v '^\[' | sed -E 's/(.*)=.*/\1/' | xargs) + + # shellcheck source=/etc/lemper/lemper.conf + # shellcheck disable=SC1094 + # shellcheck disable=SC1091 + source <(grep -v '^#' /etc/lemper/lemper.conf | grep -v '^\[' | sed -E 's|^(.+)=(.*)$|: ${\1=\2}; export \1|g') +else + echo "LEMPer Stack configuration required, but the file doesn't exist." + echo "It should be created during installation process and placed under '/etc/lemper/lemper.conf'." + exit 1 +fi + +# Set default variables. +LEMPER_USERNAME=${LEMPER_USERNAME:-"lemper"} +LEMPER_PASSWORD=${LEMPER_PASSWORD:-""} +MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-""} + +# Set CLI plugins directory. +CLI_PLUGINS_DIR="/etc/lemper/cli-plugins" + # Color decorator. -RED=91 -GREEN=92 -YELLOW=93 +RED=31 +GREEN=32 +YELLOW=33 ## # Helper Functions. @@ -108,54 +149,13 @@ function run() { fi } -# Make sure only root can run this script. -function requires_root() { - if [[ "$(id -u)" -ne 0 ]]; then - if ! hash sudo 2>/dev/null; then - echo "${PROG_NAME} command must be run as 'root' or with sudo." - exit 1 - else - #echo "Switching to root user to run this script." - sudo -E "$0" "$@" - exit 0 - fi - fi -} - -requires_root "$@" - -# Export LEMPer Stack configuration. -if [[ -f "/etc/lemper/lemper.conf" ]]; then - # Clean environemnt first. - # shellcheck source=/etc/lemper/lemper.conf - # shellcheck disable=SC2046 - unset $(grep -v '^#' /etc/lemper/lemper.conf | grep -v '^\[' | sed -E 's/(.*)=.*/\1/' | xargs) - - # shellcheck source=/etc/lemper/lemper.conf - # shellcheck disable=SC1094 - # shellcheck disable=SC1091 - source <(grep -v '^#' /etc/lemper/lemper.conf | grep -v '^\[' | sed -E 's|^(.+)=(.*)$|: ${\1=\2}; export \1|g') -else - echo "LEMPer Stack configuration required, but the file doesn't exist." - echo "It should be created during installation process and placed under '/etc/lemper/lemper.conf'." - exit 1 -fi - -# Set default variables. -LEMPER_USERNAME=${LEMPER_USERNAME:-"lemper"} -LEMPER_PASSWORD=${LEMPER_PASSWORD:-""} -MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-""} - -# Set CLI plugins directory. -CLI_PLUGINS_DIR="/etc/lemper/cli-plugins" - ## # Show usage # output to STDERR. ## function cmd_help() { cat <<- EOL -${PROG_NAME} ${PROG_VER} +${PROG_NAME} ${PROG_VERSION} Command line management tool for LEMPer Stack. Usage: ${PROG_NAME} [--version] [--help] @@ -178,7 +178,7 @@ EOL # Show version. ## function cmd_version() { - echo "${PROG_NAME} version ${PROG_VER}" + echo "${PROG_NAME} version ${PROG_VERSION}" } ## @@ -204,10 +204,9 @@ function init_lemper_cli() { # Source the plugin executable file. # shellcheck disable=SC1090 . "${CLI_PLUGINS_DIR}/lemper-${CMD}" "$@" - exit 0 else - echo "${PROG_NAME}: '${CMD}' is not ${PROG_NAME} command" - echo "See '${PROG_NAME} --help' for more information" + echo "${PROG_NAME}: '${CMD}' is not valid command." + echo "See '${PROG_NAME} --help' for more information." exit 1 fi ;; diff --git a/lib/lemper-account.sh b/lib/lemper-account.sh index d62340a..73f64c9 100644 --- a/lib/lemper-account.sh +++ b/lib/lemper-account.sh @@ -15,6 +15,16 @@ # | Authors: Edi Septriyanto | # +-------------------------------------------------------------------------+ +# Version control. +#CMD_PARENT="${PROG_NAME}" +#CMD_NAME="account" + +# Make sure only root can access and not direct access. +if [[ "$(type -t requires_root)" != "function" ]]; then + echo "Direct access to this script is not permitted." + exit 1 +fi + # Create default system account. function create_account() { export USERNAME=${1:-"lemper"} diff --git a/lib/lemper-adduser.sh b/lib/lemper-adduser.sh index b8429da..ad53562 100755 --- a/lib/lemper-adduser.sh +++ b/lib/lemper-adduser.sh @@ -16,9 +16,7 @@ # +-------------------------------------------------------------------------+ # Version control. -#PROG_NAME=$(basename "$0") -#PROG_VER="2.x.x" -#CMD_PARENT="lemper-cli" +#CMD_PARENT="${PROG_NAME}" #CMD_NAME="adduser" # Make sure only root can access and not direct access. diff --git a/lib/lemper-create.sh b/lib/lemper-create.sh index 26eda7e..0bcf2ac 100755 --- a/lib/lemper-create.sh +++ b/lib/lemper-create.sh @@ -16,9 +16,7 @@ # +-------------------------------------------------------------------------+ # Version control. -PROG_NAME=$(basename "$0") -PROG_VER="2.x.x" -CMD_PARENT="lemper-cli" +CMD_PARENT="${PROG_NAME}" CMD_NAME="create" # Make sure only root can access and not direct access. @@ -52,8 +50,9 @@ fi # function show_usage { cat <<- EOL -${CMD_PARENT} ${CMD_NAME} ${PROG_VER} -Creates Nginx virtual host (vHost) configuration file. +${CMD_PARENT} ${CMD_NAME} ${PROG_VERSION} +LEMPer Stack virtual host (vhost) configurator, +creates Nginx vhost configuration file on Debian/Ubuntu server. Requirements: * LEMP stack setup uses [LEMPer](https://github.com/joglomedia/LEMPer) @@ -91,8 +90,6 @@ Options: Auto install application for selected framework. -s, --enable-ssl Enable HTTPS with Let's Encrypt free SSL certificate. - -P, --enable-pagespeed - Enable Nginx mod_pagespeed. -W, --wildcard-domain Enable wildcard (*) domain. @@ -143,37 +140,6 @@ server { # gzip (default) or brotli (requires Nginx installed with brotli module). #include /etc/nginx/includes/compression_gzip.conf; - ## Uncomment to enable Mod PageSpeed (Nginx must be installed with mod PageSpeed). - #include /etc/nginx/includes/mod_pagespeed.conf; - - # Authorizing domain. - #pagespeed Domain ${SERVERNAME}; - #pagespeed Domain *.${SERVERNAME}; - - # Authorize CDN host below here! - ##pagespeed Domain your-cdn-host; - - # Map CDN host below here! - ##pagespeed MapOriginDomain https://your-cdn-address https://${SERVERNAME}; - - # Rewrite CDN host below here! - ##pagespeed MapRewriteDomain https://your-cdn-address https://${SERVERNAME}; - - # PageSpeed should be disabled on the WP admin/dashboard - # adjust manually to suit your custom admin URLs. - #pagespeed Disallow "*/admin/*"; - #pagespeed Disallow "*/account/*"; - #pagespeed Disallow "*/dashboard/*"; - #pagespeed Disallow "*/wp-admin/*"; - #pagespeed Disallow "*/wp-login*"; - - ## Access control Cross-origin Resource Sharing (CORS). - set \$cors "${SERVERNAME},*.${SERVERNAME}"; - - # PageSpeed CORS support. - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "${SERVERNAME}"; - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "*.${SERVERNAME}"; - ## Global directives configuration. include /etc/nginx/includes/rules_security.conf; include /etc/nginx/includes/rules_staticfiles.conf; @@ -226,7 +192,7 @@ server { } EOL else - info "Vhost created in dry run mode, no data written." + info "Virtual host created in dry run mode, no data written." fi } @@ -263,33 +229,6 @@ server { # gzip (default) or brotli (requires Nginx installed with brotli module). #include /etc/nginx/includes/compression_gzip.conf; - ## Uncomment to enable Mod PageSpeed (Nginx must be installed with mod PageSpeed). - #include /etc/nginx/includes/mod_pagespeed.conf; - - # Authorizing domain. - #pagespeed Domain ${SERVERNAME}; - #pagespeed Domain *.${SERVERNAME}; - - # Authorize CDN host below here! - ##pagespeed Domain your-cdn-host; - - # Map CDN host below here! - ##pagespeed MapOriginDomain https://your-cdn-address https://${SERVERNAME}; - - # Rewrite CDN host below here! - ##pagespeed MapRewriteDomain https://your-cdn-address https://${SERVERNAME}; - - # PageSpeed should be disabled on the user panel (adjust to suit custom admin URLs). - #pagespeed Disallow "*/user/*"; - #pagespeed Disallow "*/account/*"; - - ## Access control Cross-origin Resource Sharing (CORS). - set \$cors "${SERVERNAME},*.${SERVERNAME}"; - - # PageSpeed CORS support. - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "${SERVERNAME}"; - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "*.${SERVERNAME}"; - ## Global directives configuration. include /etc/nginx/includes/rules_security.conf; include /etc/nginx/includes/rules_staticfiles.conf; @@ -340,7 +279,7 @@ server { } EOL else - info "Vhost created in dry run mode, no data written." + info "Virtual host created in dry run mode, no data written." fi } @@ -377,34 +316,6 @@ server { # gzip (default) or brotli (requires Nginx installed with brotli module). #include /etc/nginx/includes/compression_gzip.conf; - ## Uncomment to enable Mod PageSpeed (Nginx must be installed with mod PageSpeed). - #include /etc/nginx/includes/mod_pagespeed.conf; - - # Authorizing domain. - #pagespeed Domain ${SERVERNAME}; - #pagespeed Domain *.${SERVERNAME}; - - # Authorize CDN host below here! - ##pagespeed Domain your-cdn-host; - - # Map CDN host below here! - ##pagespeed MapOriginDomain https://your-cdn-address https://${SERVERNAME}; - - # Rewrite CDN host below here! - ##pagespeed MapRewriteDomain https://your-cdn-address https://${SERVERNAME}; - - # PageSpeed should be disabled on the admin (adjust to suit custom admin URLs). - #pagespeed Disallow "*/account/*"; - #pagespeed Disallow "*/dashboard/*"; - #pagespeed Disallow "*/admin/*"; - - ## Access control Cross-origin Resource Sharing (CORS). - set \$cors "${SERVERNAME},*.${SERVERNAME}"; - - # PageSpeed CORS support. - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "${SERVERNAME}"; - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "*.${SERVERNAME}"; - ## Global directives configuration. include /etc/nginx/includes/rules_security.conf; include /etc/nginx/includes/rules_staticfiles.conf; @@ -455,7 +366,7 @@ server { } EOL else - info "Vhost created in dry run mode, no data written." + info "Virtual host created in dry run mode, no data written." fi } @@ -492,34 +403,6 @@ server { # gzip (default) or brotli (requires Nginx installed with brotli module). #include /etc/nginx/includes/compression_gzip.conf; - ## Uncomment to enable Mod PageSpeed (Nginx must be installed with mod PageSpeed). - #include /etc/nginx/includes/mod_pagespeed.conf; - - # Authorizing domain. - #pagespeed Domain ${SERVERNAME}; - #pagespeed Domain *.${SERVERNAME}; - - # Authorize CDN host below here! - ##pagespeed Domain your-cdn-host; - - # Map CDN host below here! - ##pagespeed MapOriginDomain https://your-cdn-address https://${SERVERNAME}; - - # Rewrite CDN host below here! - ##pagespeed MapRewriteDomain https://your-cdn-address https://${SERVERNAME}; - - # PageSpeed should be disabled on the admin (adjust to suit custom admin URLs). - #pagespeed Disallow "*/account/*"; - #pagespeed Disallow "*/dashboard/*"; - #pagespeed Disallow "*/admin/*"; - - ## Access control Cross-origin Resource Sharing (CORS). - set \$cors "${SERVERNAME},*.${SERVERNAME}"; - - # PageSpeed CORS support. - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "${SERVERNAME}"; - #pagespeed AddResourceHeader "Access-Control-Allow-Origin" "*.${SERVERNAME}"; - ## Global directives configuration. include /etc/nginx/includes/rules_security.conf; include /etc/nginx/includes/rules_staticfiles.conf; @@ -573,7 +456,7 @@ server { } EOL else - info "Vhost created in dry run mode, no data written." + info "Virtual host created in dry run mode, no data written." fi } @@ -893,9 +776,9 @@ function install_wordpress() { # function init_lemper_create() { # Command line arguments. - OPTS=$(getopt -o u:d:e:f:4:6:w:p:iScPsFWDhv \ + OPTS=$(getopt -o u:d:e:f:4:6:w:p:iScsFWDhv \ -l username:,domain-name:,admin-email:,framework:,ipv4:,ipv6:,webroot:,php-version:,install-app,subdomains \ - -l enable-fastcgi-cache,enable-pagespeed,enable-ssl,enable-fail2ban,wildcard-domain,dryrun,help,version \ + -l enable-fastcgi-cache,enable-ssl,enable-fail2ban,wildcard-domain,dryrun,help,version \ -n "${PROG_NAME}" -- "$@") eval set -- "${OPTS}" @@ -911,7 +794,6 @@ function init_lemper_create() { INSTALL_APP=false WPMS_SUBDOMAINS="" ENABLE_FASTCGI_CACHE=false - ENABLE_PAGESPEED=false ENABLE_SSL=false ENABLE_WILDCARD_DOMAIN=false ENABLE_FAIL2BAN=false @@ -982,11 +864,7 @@ function init_lemper_create() { shift ENABLE_FAIL2BAN=true ;; - -h | --help) - shift - show_usage - exit 0 - ;; + -i | --install-app) shift INSTALL_APP=true @@ -995,22 +873,23 @@ function init_lemper_create() { shift WPMS_SUBDOMAINS="--subdomains" ;; - -P | --enable-pagespeed) - shift - ENABLE_PAGESPEED=true - ;; -s | --enable-ssl) shift ENABLE_SSL=true ;; - -v | --version) + -W | --wildcard-domain) shift - echo "${PROG_NAME} version ${PROG_VER}" + ENABLE_WILDCARD_DOMAIN=true + ;; + -h | --help) + shift + show_usage exit 0 ;; - -W | --wildcard-domain) + -v | --version) shift - ENABLE_WILDCARD_DOMAIN=true + echo "${PROG_NAME} version ${PROG_VERSION}" + exit 0 ;; --) # End of all options, shift to the next (non getopt) argument as $1. @@ -1574,22 +1453,6 @@ EOL fi fi - # Enable PageSpeed. - if [[ ${ENABLE_PAGESPEED} == true ]]; then - echo "Enable Mod PageSpeed for ${SERVERNAME}..." - - if [[ -f /etc/nginx/includes/mod_pagespeed.conf && -f /etc/nginx/modules-enabled/60-mod-pagespeed.conf ]]; then - # enable mod pagespeed - run sed -i "s|#include\ /etc/nginx/mod_pagespeed|include\ /etc/nginx/mod_pagespeed|g" /etc/nginx/nginx.conf - run sed -i "s|#include\ /etc/nginx/includes/mod_pagespeed.conf|include\ /etc/nginx/includes/mod_pagespeed.conf|g" "${VHOST_FILE}" - run sed -i "s|#pagespeed\ EnableFilters|pagespeed\ EnableFilters|g" "${VHOST_FILE}" - run sed -i "s|#pagespeed\ Disallow|pagespeed\ Disallow|g" "${VHOST_FILE}" - run sed -i "s|#pagespeed\ Domain|pagespeed\ Domain|g" "${VHOST_FILE}" - else - info "Mod PageSpeed is not enabled. Nginx must be installed with PageSpeed module." - fi - fi - # Enable fail2ban filter if [[ "${ENABLE_FAIL2BAN}" == true ]]; then echo "Enable Fail2ban ${FRAMEWORK^} filter for ${SERVERNAME}..." @@ -1695,8 +1558,8 @@ EOL error "The virtual host config file for ${SERVERNAME} already exists. Aborting..." fi else - echo "${PROG_NAME}: missing required arguments." - echo "See '${PROG_NAME} --help' for more information." + echo "${CMD_PARENT} ${CMD_NAME}: missing required arguments." + echo "See '${CMD_PARENT} ${CMD_NAME} --help' for more information." fi } diff --git a/lib/lemper-db.sh b/lib/lemper-db.sh index 9b5c118..af5b205 100755 --- a/lib/lemper-db.sh +++ b/lib/lemper-db.sh @@ -16,9 +16,7 @@ # +-------------------------------------------------------------------------+ # Version control. -PROG_NAME=$(basename "$0") -PROG_VER="2.x.x" -CMD_PARENT="lemper-cli" +CMD_PARENT="${PROG_NAME}" CMD_NAME="db" # Make sure only root can access and not direct access. @@ -58,186 +56,13 @@ function str_to_upper() { } ## -# Prints help. +# Account sub commands ## -function cmd_help() { +function cmd_account_help() { cat <<- EOL -${CMD_PARENT} ${CMD_NAME} ${PROG_VER} -Command line database management tool for LEMPer stack. - -Usage: ${CMD_PARENT} ${CMD_NAME} [--version] [--help] - [] - -Default options are read from the following files in the given order: -/etc/lemper/lemper.conf - -These are common ${CMD_PARENT} ${CMD_NAME} subcommands used in various situations: - account Manage database account. - create Creates a new database. - databases Lists the databases. - drop Deletes the database. - export Exports a database to a file or to STDOUT. - import Imports a database from a file or from STDIN. - list An aliases of databases sub command. - optimize Optimizes the database. - query Executes a SQL query against the database. - repair Repairs the database. - reset Removes all tables from the database. - search Finds a string in the database. - show An aliases of databases subcommand. - size Displays the database name and size. - tables Lists all tables from the database. - user An aliases of account subcommand. - - -GLOBAL PARAMETERS - - --dbhost= - MySQL database host / server address, default is localhost. - - --dbport= - MySQL database host / server port, default is 3306. - - --dbuser= - MySQL database account username. - - --dbpass= - MySQL database account password. - - --dbname= - Selected database that will be used for operations. - - --dbprefix= - Database name prefix, such as prefix_. - - --dbcollation= - A set of rules used to compare characters in a particular character set, default is utf8_unicode_ci. - - --dbprivileges= - Granted to a MySQL account determine which operations the account can perform. - - --dbfile= - Path to the SQL database file. - - --dbquery= - A set of SQL query. - - --extra-args= - Passes extra arguments to the command or subcommand operations. - - -Example: - ${CMD_PARENT} ${CMD_NAME} account create --dbuser=user --dbpass=secret - -For help with each command run: -${CMD_PARENT} ${CMD_NAME} -h|--help -EOL - - exit 0 -} - -function cmd_version() { - echo "${CMD_PARENT} ${CMD_NAME} version ${PROG_VER}" - exit 0 -} - -function cmd_account() { - db_ops "--action=account" "$@" -} - -function cmd_create() { - db_ops "--action=create" "$@" -} - -function cmd_add() { - db_ops "--action=add" "$@" -} - -function cmd_databases() { - db_ops "--action=databases" "$@" -} - -function cmd_list() { - db_ops "--action=list" "$@" -} - -function cmd_drop() { - db_ops "--action=drop" "$@" -} - -function cmd_delete() { - db_ops "--action=delete" "$@" -} - -function cmd_export() { - db_ops "--action=export" "$@" -} - -function cmd_import() { - db_ops "--action=import" "$@" -} - -function cmd_optimize() { - echo "Optimizes the database." - db_ops "--action=optimize" "$@" -} - -function cmd_query() { - db_ops "--action=query" "$@" -} - -function cmd_repair() { - echo "Repairs the database." - db_ops "--action=repair" "$@" -} - -function cmd_reset() { - echo "Removes all tables from the database." - db_ops "--action=reset" "$@" -} - -function cmd_search() { - echo "Finds a string in the database." - db_ops "--action=search" "$@" -} - -function cmd_user() { - cmd_account "$@" -} - -# Aliases of cmd database. -function cmd_show() { - cmd_databases "$@" -} - -function cmd_list() { - cmd_databases "$@" -} - -function cmd_size() { - echo "Displays the database name and size." - db_ops "--action=size" "$@" -} - -function cmd_tables() { - echo "Lists the database tables." - db_ops "--action=tables" "$@" -} - -function cmd_users() { - echo "Lists users." - db_ops "--action=users" "$@" -} - -## -# Initialize account subcommand. -## -function sub_cmd_account() { - # account subcommands - function cmd_account_help() { - cat <<- EOL -${PROG_NAME} ${PROG_VER} -Command line database management tool for LEMPer stack. +${CMD_PARENT} ${CMD_NAME} account ${PROG_VERSION} +LEMPer Stack database account manager, +create, update, delete, and manage MySQL/MariaDB database account. Usage: ${CMD_PARENT} ${CMD_NAME} account [--version] [--help] [] @@ -257,226 +82,217 @@ These are common ${CMD_PARENT} ${CMD_NAME} account subcommands used in various s For help with each command run: ${CMD_PARENT} ${CMD_NAME} account -h|--help EOL +} - exit 0 - } +function cmd_account_version() { + echo "${CMD_PARENT} ${CMD_NAME} account version ${PROG_VERSION}" +} - function cmd_account_version() { - echo "${CMD_PARENT} ${CMD_NAME} account version ${PROG_VER}" - exit 0 - } +# Grant access privileges. +function cmd_account_access() { + if [[ -z "${DBUSER}" ]]; then + fail "Please specify the account's username using --dbuser parameter." + fi - # Grant access privileges. - function cmd_account_access() { - if [[ -z "${DBUSER}" ]]; then - fail "Please specify the account's username using --dbuser parameter." - fi + if [[ -z "${DBNAME}" ]]; then + fail "Please specify the database name using --dbname parameter." + fi - if [[ -z "${DBNAME}" ]]; then - fail "Please specify the database name using --dbname parameter." - fi + if [[ -z "${DBPRIVILEGES}" ]]; then + DBPRIVILEGES="ALL PRIVILEGES" + fi - if [[ -z "${DBPRIVILEGES}" ]]; then - DBPRIVILEGES="ALL PRIVILEGES" - fi + if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SHOW DATABASES;" | grep -qwE "${DBNAME}"; then + echo "Grants database '${DBNAME}' privileges to '${DBUSER}'@'${DBHOST}'" + run "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "GRANT ${DBPRIVILEGES} ON ${DBNAME}.* TO '${DBUSER}'@'${DBHOST}'; FLUSH PRIVILEGES;" + exit 0 + else + fail "The specified database '${DBNAME}' does not exist." + fi +} + +# Creates a new account. +function cmd_account_create() { + if [ "${DBUSER}" != "root" ]; then + DBUSER=${DBUSER:-"${LEMPER_USERNAME}_$(openssl rand -base64 32 | tr -dc 'a-z0-9' | fold -w 8 | head -n 1)"} + DBPASS=${DBPASS:-"$(openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"} - #if [ -d "/var/lib/mysql/${DBNAME}" ]; then - if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SHOW DATABASES;" | grep -qwE "${DBNAME}"; then - echo "Grants database '${DBNAME}' privileges to '${DBUSER}'@'${DBHOST}'" - run "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "GRANT ${DBPRIVILEGES} ON ${DBNAME}.* TO '${DBUSER}'@'${DBHOST}'; FLUSH PRIVILEGES;" + # Create database account. + if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT User FROM mysql.user WHERE user='${DBUSER}';" | grep -qwE "${DBUSER}"; then + fail "MySQL account ${DBUSER} is already exist. Please use another one!" else - error "Specified database '${DBNAME}' does not exist." - exit 1 - fi - } + echo "Creating new MySQL account '${DBUSER}'@'${DBHOST}' using password ${DBPASS}..." - # Creates a new account. - function cmd_account_create() { - if [ "${DBUSER}" != "root" ]; then - DBUSER=${DBUSER:-"${LEMPER_USERNAME}_$(openssl rand -base64 32 | tr -dc 'a-z0-9' | fold -w 8 | head -n 1)"} - DBPASS=${DBPASS:-"$(openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"} + run "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "CREATE USER '${DBUSER}'@'${DBHOST}' IDENTIFIED BY '${DBPASS}';" - # Create database account. if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT User FROM mysql.user WHERE user='${DBUSER}';" | grep -qwE "${DBUSER}"; then - error "MySQL account ${DBUSER} is already exist. Please use another one!" - exit 1 - else - echo "Creating new MySQL account '${DBUSER}'@'${DBHOST}' using password ${DBPASS}..." + success "MySQL account ${DBUSER} has been created." + [[ ${VERBOSE} == true ]] && echo -e "Below the account details:\nUsername: ${DBUSER}\nPassword: ${DBPASS}\nHost: ${DBHOST}" + fi + fi + else + fail "Root user is already exist. Please use another one!" + fi +} - run "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "CREATE USER '${DBUSER}'@'${DBHOST}' IDENTIFIED BY '${DBPASS}';" +# Deletes an existing account. +function cmd_account_delete() { + if [ -z "${DBUSER}" ]; then + fail "Please specify the account's username using --dbuser parameter." + fi - if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT User FROM mysql.user WHERE user='${DBUSER}';" | grep -qwE "${DBUSER}"; then - success "MySQL account ${DBUSER} has been created." - [[ ${VERBOSE} == true ]] && echo -e "Below the account details:\nUsername: ${DBUSER}\nPassword: ${DBPASS}\nHost: ${DBHOST}" - fi + if [[ "${DBUSER}" = "root" || "${DBUSER}" = "lemper" ]]; then + fail "You're not allowed to delete this user." + else + local SQL_QUERY="DROP USER '${DBUSER}'@'${DBHOST}';" - exit 0 + if [[ "${DRYRUN}" != true ]]; then + if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "${SQL_QUERY}"; then + success "The database's account '${DBUSER}'@'${DBHOST}' has been deleted." + else + fail "Unable to delete database account '${DBUSER}'@'${DBHOST}'." fi else - error "Root user is already exist. Please use another one!" - exit 1 + info "SQL query: \"${SQL_QUERY}\"" fi - } + fi +} - # Deletes an existing account. - function cmd_account_delete() { - if [ -z "${DBUSER}" ]; then - fail "Please specify the account's username using --dbuser parameter." - fi +# Update password. +function cmd_account_passwd() { + DBPASS2=${DBPASS2:-"$(openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"} - if [[ "${DBUSER}" = "root" || "${DBUSER}" = "lemper" ]]; then - error "You're not allowed to delete this user." - exit 1 - else - local SQL_QUERY="DROP USER '${DBUSER}'@'${DBHOST}';" + if [ -z "${DBUSER}" ]; then + fail "Please specify the account's username using --dbuser parameter." + fi - if ! "${DRYRUN}"; then - if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "${SQL_QUERY}"; then - success "The database's account '${DBUSER}'@'${DBHOST}' has been deleted." - else - error "Unable to delete database account '${DBUSER}'@'${DBHOST}'." - exit 1 - fi - else - info "SQL query: \"${SQL_QUERY}\"" - fi - fi - } + if [ -z "${DBPASS2}" ]; then + error "Please specify the new password using --extra-args parameter (dbpass2)." + echo "An example for passing extra arguments: --extra-args=\"dbpass2=newpass\"" + exit 1 + fi - # Update password. - function cmd_account_passwd() { - DBPASS2=${DBPASS2:-"$(openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"} + local SQL_QUERY="UPDATE mysql.user SET Password=PASSWORD('${DBPASS2}') WHERE USER='${DBUSER}' AND Host='${DBHOST}';" - if [ -z "${DBUSER}" ]; then - fail "Please specify the account's username using --dbuser parameter." + if [[ "${DRYRUN}" != true ]]; then + if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "${SQL_QUERY}"; then + success "Password for account '${DBUSER}'@'${DBHOST}' has been updated to '${DBPASS2}'." + else + fail "Unable to update password for '${DBUSER}'@'${DBHOST}'." fi + else + info "SQL query: \"${SQL_QUERY}\"" + fi +} - if [ -z "${DBPASS2}" ]; then - error "Please specify the new password using --extra-args parameter (dbpass2)." - echo "An example for passing extra arguments: --extra-args=\"dbuser2=newuser,dbhost2=127.0.0.1\"" - exit 1 - fi +# Rename an existing account. +function cmd_account_rename() { + DBHOST2=${DBHOST2:-"${DBHOST}"} + DBUSER2=${DBUSER2:-""} + DBROOT_PASS=${DBROOTPASS:-"${MYSQL_ROOT_PASSWORD}"} + + if [ -z "${DBUSER}" ]; then + fail "Please specify the account's username using --dbuser parameter." + fi + + if [ -z "${DBUSER2}" ]; then + error "Please specify the new username using --extra-args parameter (dbuser2)." + echo "An example for passing extra arguments: --extra-args=\"dbuser2=newuser,dbhost2=127.0.0.1\"" + exit 1 + fi - local SQL_QUERY="UPDATE mysql.user SET Password=PASSWORD('${DBPASS2}') WHERE USER='${DBUSER}' AND Host='${DBHOST}';" + local SQL_QUERY="RENAME USER '${DBUSER}'@'${DBHOST}' TO '${DBUSER2}'@'${DBHOST2}';" - if ! "${DRYRUN}"; then - if "${MYSQLCLI}" -u root -p"${MYSQL_ROOT_PASSWORD}" -e "${SQL_QUERY}"; then - success "Password for account '${DBUSER}'@'${DBHOST}' has been updated to '${DBPASS2}'." + if [[ "${DRYRUN}" != true ]]; then + if [[ "${DBUSER}" = "root" || "${DBUSER}" = "lemper" ]]; then + fail "You are not allowed to rename this account." + else + if "${MYSQLCLI}" -u root -p"${DBROOT_PASS}" -e "${SQL_QUERY}"; then + success "Database account '${DBUSER}'@'${DBHOST}' has been renamed to '${DBUSER2}'@'${DBHOST2}'." else - error "Unable to update password for '${DBUSER}'@'${DBHOST}'." - exit 1 + fail "Unable to rename database account '${DBUSER}'@'${DBHOST}'." fi - else - info "SQL query: \"${SQL_QUERY}\"" fi - } + else + info "SQL query: \"${SQL_QUERY}\"" + fi +} - # Rename an existing account. - function cmd_account_rename() { - DBHOST2=${DBHOST2:-"${DBHOST}"} - DBUSER2=${DBUSER2:-""} - DBROOT_PASS=${DBROOTPASS:-"${MYSQL_ROOT_PASSWORD}"} +# List all database users +function cmd_account_users() { + DBUSER=${DBUSER:-"root"} + DBPASS=${DBPASS:-""} + [[ "${DBUSER}" = "root" && -z "${DBPASS}" ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" + + echo "List all existing database users." - if [ -z "${DBUSER}" ]; then - fail "Please specify the account's username using --dbuser parameter." - fi + run "${MYSQLCLI}" -u "${DBUSER}" -p"${DBPASS}" -e "SELECT user,host FROM mysql.user;" +} - if [ -z "${DBUSER2}" ]; then - error "Please specify the new username using --extra-args parameter (dbuser2)." - echo "An example for passing extra arguments: --extra-args=\"dbuser2=newuser,dbhost2=127.0.0.1\"" - exit 1 - fi +# Aliases to create. +function cmd_account_add() { + cmd_account_create "$@" +} + +# Aliases to create. +function cmd_account_new() { + cmd_account_create "$@" +} - local SQL_QUERY="RENAME USER '${DBUSER}'@'${DBHOST}' TO '${DBUSER2}'@'${DBHOST2}';" +# Aliases to users. +function cmd_account_list() { + cmd_account_users "$@" +} - if ! "${DRYRUN}"; then - if [[ "${DBUSER}" = "root" || "${DBUSER}" = "lemper" ]]; then - error "You are not allowed to rename this account." - exit 1 - else - if "${MYSQLCLI}" -u root -p"${DBROOT_PASS}" -e "${SQL_QUERY}"; then - success "Database account '${DBUSER}'@'${DBHOST}' has been renamed to '${DBUSER2}'@'${DBHOST2}'." +# Initialize account subcommand. +function init_cmd_account() { + # Check command line arguments. + if [[ -n "${1}" ]]; then + local SUBCOMMAND && \ + SUBCOMMAND=$(str_trim "${1}") + shift # Pass the remaining arguments to the next function. + + case "${SUBCOMMAND}" in + help | -h | --help) + cmd_account_help + exit 0 + ;; + version | -v | --version) + cmd_account_version + exit 0 + ;; + *) + if declare -F "cmd_account_${SUBCOMMAND}" &>/dev/null; then + "cmd_account_${SUBCOMMAND}" "$@" else - error "Unable to rename database account '${DBUSER}'@'${DBHOST}'." + echo "${CMD_PARENT} ${CMD_NAME} account: unrecognized command '${SUBCOMMAND}'" >&2 + echo "Run '${CMD_PARENT} ${CMD_NAME} account --help' for a list of known commands." >&2 exit 1 fi - fi - else - info "SQL query: \"${SQL_QUERY}\"" - fi - } - - # List all database users - function cmd_account_users() { - DBUSER=${DBUSER:-"root"} - DBPASS=${DBPASS:-""} - [[ "${DBUSER}" = "root" && -z "${DBPASS}" ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" - - echo "List all existing database users." - - run "${MYSQLCLI}" -u "${DBUSER}" -p"${DBPASS}" -e "SELECT user,host FROM mysql.user;" - } - - # Aliases to create. - function cmd_account_add() { - cmd_account_create "$@" - } - - # Aliases to create. - function cmd_account_new() { - cmd_account_create "$@" - } - - # Aliases to users. - function cmd_account_list() { - cmd_account_users "$@" - } - - # Initialize account subcommand. - function init_cmd_account() { - # Check command line arguments. - if [[ -n "${1}" ]]; then - local SUBCOMMAND && \ - SUBCOMMAND=$(str_trim "${1}") - shift # Pass the remaining arguments to the next function. - - case "${SUBCOMMAND}" in - help | -h | --help) - cmd_account_help - exit 0 - ;; - version | -v | --version) - cmd_account_version - exit 0 - ;; - *) - if declare -F "cmd_account_${SUBCOMMAND}" &>/dev/null; then - "cmd_account_${SUBCOMMAND}" "$@" - else - echo "${CMD_PARENT} ${CMD_NAME} account: unrecognized command '${SUBCOMMAND}'" >&2 - echo "Run '${CMD_PARENT} ${CMD_NAME} account --help' for a list of known commands." >&2 - exit 1 - fi - ;; - esac - else - echo "${CMD_PARENT} ${CMD_NAME} account: missing required arguments." - echo "See '${CMD_PARENT} ${CMD_NAME} account --help' for more information." - exit 1 - fi - } + ;; + esac + else + echo "${CMD_PARENT} ${CMD_NAME} account: missing required arguments." + echo "See '${CMD_PARENT} ${CMD_NAME} account --help' for more information." + exit 1 + fi +} +## +# Initialize account sub command. +## +function sub_cmd_account() { init_cmd_account "$@" } ## -# Main Database Operations. +# Database Operations. ## -function db_ops() { +function db_operations() { OPTS=$(getopt -o a:H:P:u:p:n:b:C:g:f:q:x:DrhVv \ -l action:,dbhost:,dbport:,dbuser:,dbpass:,dbname:,dbprefix:,dbcollation:,dbprivileges:,dbfile:,dbquery:,extra-args: \ -l dry-run,root,help,verbose,version \ - -n "${CMD_PARENT} ${CMD_NAME}" -- "$@") + -n "${PROG_NAME}" -- "$@") eval set -- "${OPTS}" @@ -516,7 +332,7 @@ function db_ops() { ;; -H | --dbhost) shift - DBHOST=${1} + DBHOST="${1}" shift ;; -n | --dbname) @@ -531,7 +347,7 @@ function db_ops() { ;; -P | --dbport) shift - DBPORT=${1} + DBPORT="${1}" shift ;; -q | --dbquery) @@ -584,7 +400,7 @@ function db_ops() { esac done - if [ ${MAIN_ARGS} -ge 1 ]; then + if [[ "${MAIN_ARGS}" -ge 1 ]]; then # Set default value. DBHOST=${DBHOST:-"localhost"} DBPORT=${DBPORT:-"3306"} @@ -605,7 +421,9 @@ function db_ops() { SAVEIFS=${IFS} # Save current IFS IFS=', ' read -r -a FIELDS <<< "${EXTRA_ARGS}" IFS=${SAVEIFS} # Restore IFS - for FIELD in "${FIELDS[@]}"; do + + for FIELD in "${FIELDS[@]}"; + do #export "${FIELD}" SAVEIFS=${IFS} # Save current IFS IFS='= ' read -r -a ARG_PARTS <<< "${FIELD}" @@ -623,18 +441,21 @@ function db_ops() { elif [[ -n $(command -v mysql) ]]; then MYSQLCLI=$(command -v mysql) else - fail "MariaDB / MySQL is required to perform database operations, but not available on your stack. Please install it first!" + fail "MariaDB/MySQL is required to perform database operations, but it is not available in your current stack. Please install one of them first." fi # Database operations based on supplied action argument. case "${ACTION}" in + # Database account operations. "account") sub_cmd_account "$@" "${BYPASSED_ARGS}" ;; + # Create / add new database. "create" | "add") DBUSER=${DBUSER:-"root"} DBPASS=${DBPASS:-""} + [[ -z "${DBPASS}" || ${USEROOT} == true ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" DBNAME=${DBNAME:-"${LEMPER_USERNAME}_db$(openssl rand -base64 32 | tr -dc 'a-z0-9' | fold -w 6 | head -n 1)"} @@ -643,7 +464,7 @@ function db_ops() { echo "Creating new MySQL database '${DBNAME}' grants access to '${DBUSER}'@'${DBHOST}'..." until ! "${MYSQLCLI}" -u root -p"${DBPASS}" -e "SHOW DATABASES;" | grep -qwE "${DBNAME}"; do - echo "Database ${DBNAME} already exist, try another one..." + echo "Database '${DBNAME}' already exist, try another one..." DBNAME="${LEMPER_USERNAME}_db$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | fold -w 6 | head -n 1)" echo "New auto-generated MySQL database '${DBNAME}'" done @@ -655,20 +476,20 @@ function db_ops() { success "MySQL database '${DBNAME}' has been created." exit 0 else - error "Failed creating database '${DBNAME}'." - exit 1 + fail "Failed creating database '${DBNAME}'." fi ;; + # List all databases. "databases" | "list") DBUSER=${DBUSER:-"root"} local DATABASES - if [[ -z "${DBPASS}" || ${USEROOT} == true ]]; then + if [[ -z "${DBPASS}" || "${USEROOT}" == true ]]; then [[ -z "${DBPASS}" ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" - DATABASES=$(mysql -u root -p"${DBPASS}" -h "${DBHOST}" -P "${DBPORT}" -e "SELECT Db,Host FROM mysql.db WHERE User='${DBUSER}' AND Grant_priv='Y';") + DATABASES=$("${MYSQLCLI}" -u root -p"${DBPASS}" -h "${DBHOST}" -P "${DBPORT}" -e "SELECT Db,Host FROM mysql.db WHERE User='${DBUSER}';") else - DATABASES=$(mysql -u "${DBUSER}" -p"${DBPASS}" -h "${DBHOST}" -P "${DBPORT}" -e "SHOW DATABASES;" | grep -vE "Database|mysql|*_schema") + DATABASES=$("${MYSQLCLI}" -u "${DBUSER}" -p"${DBPASS}" -h "${DBHOST}" -P "${DBPORT}" -e "SHOW DATABASES;" | grep -vE "Database|mysql|*_schema") fi if [[ -n "${DATABASES}" ]]; then @@ -680,34 +501,32 @@ function db_ops() { IFS=${SAVEIFS} # Restore IFS echo "There are ${#DBS[@]} databases granted to '${DBUSER}'." - echo "+------------------------------+" - echo "| 'database'@'host'" - echo "+------------------------------+" + echo "+-------------------------------------+" + echo "| 'database'@'host' |" + echo "+-------------------------------------+" - #for DB in "${DBS[@]}"; do - # echo "| ${DB}" - #done for ((i=0; i<${#DBS[@]}; i++)); do # shellcheck disable=SC2206 ROW=(${DBS[${i}]}) echo "| '${ROW[0]}'@'${ROW[1]}'" done - echo "+------------------------------+" + echo "+-------------------------------------+" else echo "No database found." fi ;; + # Drope / delete database. "drop" | "delete") if [[ -z "${DBNAME}" ]]; then - fail "Please specify the name of database using --dbname parameter." + fail "Please specify the database name using the --dbname parameter." fi DBUSER=${DBUSER:-"root"} + [[ "${DBUSER}" = "root" && -z "${DBPASS}" ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" - #if [ -d "/var/lib/mysql/${DBNAME}" ]; then if "${MYSQLCLI}" -u root -p"${DBPASS}" -e "SHOW DATABASES;" | grep -qwE "${DBNAME}"; then echo "Deleting database ${DBNAME}..." @@ -716,21 +535,21 @@ function db_ops() { if ! "${MYSQLCLI}" -u root -p"${DBPASS}" -e "SHOW DATABASES LIKE '${DBNAME}';" | grep -qwE "${DBNAME}"; then success "Database '${DBNAME}' has been dropped." else - error "Failed deleting database '${DBNAME}'." - exit 1 + fail "Failed deleting database '${DBNAME}'." fi else - error "Specified database '${DBNAME}' does not exist." - exit 1 + fail "The specified database '${DBNAME}' does not exist." fi ;; + # Export / dump database to file. "export") if [[ -z "${DBNAME}" ]]; then - fail "Please specify the name of database using --dbname parameter." + fail "Please specify the database name using the --dbname parameter." fi DBUSER=${DBUSER:-"root"} + [[ "${DBUSER}" = "root" && -z "${DBPASS}" ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" DBFILE=${DBFILE:-"${DBNAME}_$(date '+%d-%m-%Y_%T').sql"} @@ -741,58 +560,64 @@ function db_ops() { if [[ -n $(command -v mysqldump) ]]; then if "${MYSQLCLI}" -u "${DBUSER}" -p"${DBPASS}" -e "SHOW DATABASES;" | grep -qwE "${DBNAME}"; then run mysqldump -u "${DBUSER}" -p"${DBPASS}" --databases "${DBNAME}" > "${DBFILE}" - [ -f "${DBFILE}" ] && success "database ${DBNAME} exported to ${DBFILE}." + + if [[ -f "${DBFILE}" ]]; then + success "Database '${DBNAME}' has been successfully exported to '${DBFILE}'." + else + fail "Failed to export the database '${DBNAME}'." + fi else - error "Specified database '${DBNAME}' does not exist." - exit 1 + fail "The specified database '${DBNAME}' does not exist." fi else - fail "Mysqldump is required to export database, but not available on your stack. Please install it first!" + fial "Mysqldump is required to export database, but it is not available in your current stack. Please install it first." fi ;; + # Import database from file. "import") if [[ -z "${DBNAME}" ]]; then - fail "Please specify the name of database using --dbname parameter." + fail "Please specify the database name using the --dbname parameter." fi DBUSER=${DBUSER:-"root"} + [[ "${DBUSER}" = "root" && -z "${DBPASS}" ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" # Import database tables. if [[ -n "${DBFILE}" && -e "${DBFILE}" ]]; then - echo "Importing '${DBNAME}' database's tables..." + echo "Importing database ${DBNAME}'s tables..." if "${MYSQLCLI}" -u "${DBUSER}" -p"${DBPASS}" -e "SHOW DATABASES;" | grep -qwE "${DBNAME}"; then run "${MYSQLCLI}" -u "${DBUSER}" -p"${DBPASS}" "${DBNAME}" < "${DBFILE}" - echo "Database file '${DBFILE}' imported to '${DBNAME}'." + echo "Database file '${DBFILE}' has been successfully imported to '${DBNAME}'." else - error "Specified database '${DBNAME}' does not exist." - exit 1 + fail "The specified database '${DBNAME}' does not exist." fi else fail "Please specifiy the database file (.sql) to import using --dbfile parameter." fi ;; + # Perform SQL query. "query") if [[ -z "${DBNAME}" ]]; then - fail "Please specify the name of database using --dbname parameter." + fail "Please specify the database name using the --dbname parameter." fi DBUSER=${DBUSER:-"root"} + [[ "${DBUSER}" = "root" && -z "${DBPASS}" ]] && DBPASS="${MYSQL_ROOT_PASSWORD}" - echo "Executes a SQL query against the database." + echo "Executing the SQL query against the database '${DBNAME}'..." local SQL_QUERY=${DBQUERY:-""} - if ! "${DRYRUN}"; then + if [[ "${DRYRUN}" != true ]]; then if "${MYSQLCLI}" -u "${DBUSER}" -p"${DBPASS}" -D "${DBNAME}" -e "${SQL_QUERY}"; then - success "SQL query applied to ${DBNAME} as '${DBUSER}'@'${DBHOST}'." + success "The SQL query was applied to '${DBNAME}' using the account '${DBUSER}'@'${DBHOST}'." else - error "Unable to execute SQL query on ${DBNAME} as '${DBUSER}'@'${DBHOST}'." - exit 1 + fail "Failed to execute the SQL query on '${DBNAME}' using the account '${DBUSER}'@'${DBHOST}'." fi else info "SQL query: \"${SQL_QUERY}\"" @@ -800,7 +625,9 @@ function db_ops() { ;; *) - fail "Something went wrong." + echo "${CMD_PARENT} ${CMD_NAME}: '${ACTION}' is not valid sub command." + echo "See '${CMD_PARENT} ${CMD_NAME} --help' for more information." + exit 1 ;; esac else @@ -810,6 +637,172 @@ function db_ops() { fi } +function cmd_account() { + db_operations "--action=account" "$@" +} + +function cmd_create() { + db_operations "--action=create" "$@" +} + +function cmd_add() { + db_operations "--action=add" "$@" +} + +function cmd_databases() { + db_operations "--action=databases" "$@" +} + +function cmd_drop() { + db_operations "--action=drop" "$@" +} + +function cmd_delete() { + db_operations "--action=delete" "$@" +} + +function cmd_export() { + db_operations "--action=export" "$@" +} + +function cmd_import() { + db_operations "--action=import" "$@" +} + +function cmd_optimize() { + echo "Optimizes the database." + db_operations "--action=optimize" "$@" +} + +function cmd_query() { + db_operations "--action=query" "$@" +} + +function cmd_repair() { + echo "Repairs the database." + db_operations "--action=repair" "$@" +} + +function cmd_reset() { + echo "Removes all tables from the database." + db_operations "--action=reset" "$@" +} + +function cmd_search() { + echo "Finds a string in the database." + db_operations "--action=search" "$@" +} + +function cmd_size() { + echo "Displays the database name and size." + db_operations "--action=size" "$@" +} + +function cmd_tables() { + echo "Lists the database tables." + db_operations "--action=tables" "$@" +} + +function cmd_users() { + echo "Lists users." + db_operations "--action=users" "$@" +} + +function cmd_user() { + cmd_account "$@" +} + +# Aliases of cmd database. +function cmd_show() { + cmd_databases "$@" +} + +function cmd_list() { + cmd_databases "$@" +} + +## +# Prints help. +## +function cmd_help() { + cat <<- EOL +${CMD_PARENT} ${CMD_NAME} ${PROG_VERSION} +LEMPer Stack database manager, +create, update, delete, and manage MySQL/MariaDB database on Debian/Ubuntu server. + +Usage: ${CMD_PARENT} ${CMD_NAME} [--version] [--help] + [] + +Default options are read from the following files in the given order: +/etc/lemper/lemper.conf + +These are common ${CMD_PARENT} ${CMD_NAME} subcommands used in various situations: + account Manage database account. + create Creates a new database. + databases Lists the databases. + drop Deletes the database. + export Exports a database to a file or to STDOUT. + import Imports a database from a file or from STDIN. + list An aliases of databases sub command. + optimize Optimizes the database. + query Executes a SQL query against the database. + repair Repairs the database. + reset Removes all tables from the database. + search Finds a string in the database. + show An aliases of databases subcommand. + size Displays the database name and size. + tables Lists all tables from the database. + user An aliases of account subcommand. + + +GLOBAL PARAMETERS + + --dbhost= + MySQL database host / server address, default is localhost. + + --dbport= + MySQL database host / server port, default is 3306. + + --dbuser= + MySQL database account username. + + --dbpass= + MySQL database account password. + + --dbname= + Selected database that will be used for operations. + + --dbprefix= + Database name prefix, such as prefix_. + + --dbcollation= + A set of rules used to compare characters in a particular character set, default is utf8_unicode_ci. + + --dbprivileges= + Granted to a MySQL account determine which operations the account can perform. + + --dbfile= + Path to the SQL database file. + + --dbquery= + A set of SQL query. + + --extra-args= + Passes extra arguments to the command or subcommand operations. + + +Example: + ${CMD_PARENT} ${CMD_NAME} account create --dbuser=user --dbpass=secret + +For help with each command run: +${CMD_PARENT} ${CMD_NAME} -h|--help +EOL +} + +function cmd_version() { + echo "${CMD_PARENT} ${CMD_NAME} version ${PROG_VERSION}" +} + ## # Main Database CLI Wrapper ## diff --git a/lib/lemper-fixpermission.sh b/lib/lemper-fixpermission.sh index 4cb3cd0..61cd286 100755 --- a/lib/lemper-fixpermission.sh +++ b/lib/lemper-fixpermission.sh @@ -32,4 +32,4 @@ function fixpermission() { # Start running things from a call at the end so if this script is executed # after a partial download it doesn't do anything. -fixpermission "$@" \ No newline at end of file +fixpermission "$@" diff --git a/lib/lemper-manage.sh b/lib/lemper-manage.sh index 6d6a345..d66be7e 100755 --- a/lib/lemper-manage.sh +++ b/lib/lemper-manage.sh @@ -16,9 +16,7 @@ # +-------------------------------------------------------------------------+ # Version control. -PROG_NAME=$(basename "$0") -PROG_VER="2.x.x" -CMD_PARENT="lemper-cli" +CMD_PARENT="${PROG_NAME}" CMD_NAME="manage" # Make sure only root can access and not direct access. @@ -37,9 +35,9 @@ fi ## function show_usage() { cat <<- EOL -${CMD_PARENT} ${CMD_NAME} ${PROG_VER} -Simple Nginx virtual host (vHost) manager, -enable/disable/remove Nginx vHost on Debian/Ubuntu Server. +${CMD_PARENT} ${CMD_NAME} ${PROG_VERSION} +LEMPer Stack virtual host (vhost) manager, +enable, disable, remove Nginx vhost on Debian/Ubuntu server. Requirements: * LEMP stack setup uses [LEMPer](https://github.com/joglomedia/LEMPer) @@ -66,10 +64,6 @@ Options: Enable Gzip compression. --disable-compression Disable Gzip/Brotli compression. - -p, --enable-pagespeed - Enable Mod PageSpeed. - --disable-pagespeed - Disable Mod PageSpeed. -r, --remove Remove virtual host configuration. -s, --enable-ssl @@ -357,77 +351,6 @@ function disable_fastcgi_cache() { fi } -## -# Enable Nginx's Mod PageSpeed. -## -function enable_mod_pagespeed() { - # Verify user input hostname (domain name) - local DOMAIN=${1} - verify_vhost "${DOMAIN}" - - echo "Enabling Mod PageSpeed for ${DOMAIN}..." - - if [[ -f /etc/nginx/includes/mod_pagespeed.conf && -f /etc/nginx/modules-enabled/50-mod-pagespeed.conf ]]; then - # Enable mod pagespeed. - run sed -i "s|#include\ /etc/nginx/mod_pagespeed|include\ /etc/nginx/mod_pagespeed|g" /etc/nginx/nginx.conf - run sed -i "s|#include\ /etc/nginx/includes/mod_pagespeed.conf|include\ /etc/nginx/includes/mod_pagespeed.conf|g" \ - "/etc/nginx/sites-available/${DOMAIN}.conf" - run sed -i "s|#pagespeed\ EnableFilters|pagespeed\ EnableFilters|g" \ - "/etc/nginx/sites-available/${DOMAIN}.conf" - run sed -i "s|#pagespeed\ Disallow|pagespeed\ Disallow|g" "/etc/nginx/sites-available/${DOMAIN}.conf" - run sed -i "s|#pagespeed\ Domain|pagespeed\ Domain|g" "/etc/nginx/sites-available/${DOMAIN}.conf" - - # If SSL enabled, ensure to also enable PageSpeed related vars. - #if grep -qwE "^\ include\ /etc/nginx/includes/ssl.conf" "/etc/nginx/sites-available/${DOMAIN}.conf"; then - # run sed -i "s/#pagespeed\ FetchHttps/pagespeed\ FetchHttps/g" \ - # "/etc/nginx/sites-available/${DOMAIN}.conf" - # run sed -i "s/#pagespeed\ MapOriginDomain/pagespeed\ MapOriginDomain/g" \ - # "/etc/nginx/sites-available/${DOMAIN}.conf" - #fi - - # Reload Nginx. - reload_nginx - else - info "Mod PageSpeed is not enabled. Nginx must be installed with PageSpeed module." - exit 1 - fi -} - -## -# Disable Nginx's Mod PageSpeed. -## -function disable_mod_pagespeed() { - # Verify user input hostname (domain name) - local DOMAIN=${1} - verify_vhost "${DOMAIN}" - - echo "Disabling Mod PageSpeed for ${DOMAIN}..." - - if [[ -f /etc/nginx/includes/mod_pagespeed.conf && -f /etc/nginx/modules-enabled/50-mod-pagespeed.conf ]]; then - # Disable mod pagespeed - #run sed -i "s|^\ include\ /etc/nginx/mod_pagespeed|\ #include\ /etc/nginx/mod_pagespeed|g" /etc/nginx/nginx.conf - run sed -i "s|^\ include\ /etc/nginx/includes/mod_pagespeed.conf|\ #include\ /etc/nginx/includes/mod_pagespeed.conf|g" \ - "/etc/nginx/sites-available/${DOMAIN}.conf" - run sed -i "s|^\ pagespeed\ EnableFilters|\ #pagespeed\ EnableFilters|g" "/etc/nginx/sites-available/${DOMAIN}.conf" - run sed -i "s|^\ pagespeed\ Disallow|\ #pagespeed\ Disallow|g" "/etc/nginx/sites-available/${DOMAIN}.conf" - run sed -i "s|^\ pagespeed\ Domain|\ #pagespeed\ Domain|g" "/etc/nginx/sites-available/${DOMAIN}.conf" - - # If SSL enabled, ensure to also disable PageSpeed related vars. - #if grep -qwE "\ include /etc/nginx/includes/ssl.conf" "/etc/nginx/sites-available/${DOMAIN}.conf"; then - # run sed -i "s/^\ pagespeed\ FetchHttps/\ #pagespeed\ FetchHttps/g" \ - # "/etc/nginx/sites-available/${DOMAIN}.conf" - # run sed -i "s/^\ pagespeed\ MapOriginDomain/\ #pagespeed\ MapOriginDomain/g" \ - # "/etc/nginx/sites-available/${DOMAIN}.conf" - #fi - - # Reload Nginx. - reload_nginx - else - info "Mod PageSpeed is not enabled. Nginx must be installed with PageSpeed module." - exit 1 - fi -} - ## # Enable HTTPS (HTTP over SSL). ## @@ -509,16 +432,6 @@ function enable_ssl() { run sed -i "s|#include\ /etc/nginx/includes/ssl.conf|include\ /etc/nginx/includes/ssl.conf|g" \ "/etc/nginx/sites-available/${DOMAIN}.conf" - # Adjust PageSpeed if enabled. - #if grep -qwE "^\ include\ /etc/nginx/includes/mod_pagespeed.conf" \ - # "/etc/nginx/sites-available/${DOMAIN}.conf"; then - # echo "Adjusting PageSpeed configuration..." - # run sed -i "s/#pagespeed\ FetchHttps/pagespeed\ FetchHttps/g" \ - # "/etc/nginx/sites-available/${DOMAIN}.conf" - # run sed -i "s/#pagespeed\ MapOriginDomain/pagespeed\ MapOriginDomain/g" \ - # "/etc/nginx/sites-available/${DOMAIN}.conf" - #fi - # Append HTTP <=> HTTPS redirection block. cat >> "/etc/nginx/sites-available/${DOMAIN}.conf" <> \ "/etc/lemper/ssl/${DOMAIN}/fullchain.pem" - #run ln -s "/etc/lemper/ssl/${DOMAIN}/cert.pem" "/etc/lemper/ssl/${HOSTNAME}/fullchain.pem" if [ -f "/etc/lemper/ssl/${DOMAIN}/cert.pem" ]; then success "Self-signed SSL certificate has been successfully generated." else - fail "An error occurred when generating self-signed SSL certificate." + fail "An error occurred while generating self-signed SSL certificate." fi } @@ -938,10 +852,9 @@ function get_ip_public() { # Main Manage CLI Wrapper ## function init_lemper_manage() { - OPTS=$(getopt -o c:d:e:f:p:r:s:bghv \ + OPTS=$(getopt -o c:d:e:f:r:s:bghv \ -l enable:,disable:,remove:,enable-fail2ban:,disable-fail2ban:,enable-fastcgi-cache:,disable-fastcgi-cache: \ - -l enable-pagespeed:,disable-pagespeed:,enable-ssl:,disable-ssl:,remove-ssl:,renew-ssl: \ - -l enable-brotli:,enable-gzip:,disable-compression:,help,version \ + -l enable-ssl:,disable-ssl:,remove-ssl:,renew-ssl:,enable-brotli:,enable-gzip:,disable-compression:,help,version \ -n "${PROG_NAME}" -- "$@") eval set -- "${OPTS}" @@ -984,16 +897,6 @@ function init_lemper_manage() { shift 2 exit 0 ;; - -p | --enable-pagespeed) - enable_mod_pagespeed "${2}" - shift 2 - exit 0 - ;; - --disable-pagespeed) - disable_mod_pagespeed "${2}" - shift 2 - exit 0 - ;; -s | --enable-ssl) enable_ssl "${2}" shift 2 @@ -1035,11 +938,13 @@ function init_lemper_manage() { exit 0 ;; -v | --version) - echo "${PROG_NAME} version ${PROG_VER}" + echo "${PROG_NAME} version ${PROG_VERSION}" shift 2 exit 0 ;; - --) shift + --) + # End of all options, shift to the next (non getopt) argument as $1. + shift break ;; *) @@ -1049,8 +954,8 @@ function init_lemper_manage() { esac done - echo "${PROG_NAME}: missing required argument" - echo "See '${PROG_NAME} --help' for more information." + echo "${CMD_PARENT} ${CMD_NAME}: missing required argument" + echo "See '${CMD_PARENT} ${CMD_NAME} --help' for more information." } # Start running things from a call at the end so if this script is executed diff --git a/lib/lemper-selfssl.sh b/lib/lemper-selfssl.sh index 0b1aa6b..f73c30f 100755 --- a/lib/lemper-selfssl.sh +++ b/lib/lemper-selfssl.sh @@ -16,10 +16,8 @@ # +-------------------------------------------------------------------------+ # Version control. -#PROG_NAME=$(basename "$0") -#PROG_VER="2.x.x" -#CMD_PARENT="lemper-cli" -#CMD_NAME="sslgen" +CMD_PARENT="${PROG_NAME}" +CMD_NAME="selfssl" # Make sure only root can access and not direct access. if [[ "$(type -t requires_root)" != "function" ]]; then @@ -27,15 +25,69 @@ if [[ "$(type -t requires_root)" != "function" ]]; then exit 1 fi -# Usage: sslgen -function sslgen() { +## +# Show usage +# output to STDERR. +## +function show_usage() { +cat <<- EOL +${CMD_PARENT} ${CMD_NAME} ${PROG_VERSION} +Generates self-signed SSL certificate on Debian/Ubuntu server. + +Requirements: + * LEMP stack setup uses [LEMPer](https://github.com/joglomedia/LEMPer) + +Usage: + ${CMD_PARENT} ${CMD_NAME} [OPTION]... + +Options: + -4, --ipv4 + Any valid IPv4 addreess for listening on. + -6, --ipv6 + Any valid IPv6 addreess for listening on. + -d, --domain-name + Any valid domain name and/or sub domain name is allowed, i.e. example.app or sub.example.app. + + -h, --help + Print this message and exit. + -v, --version + Output version information and exit. + +Example: + ${CMD_PARENT} ${CMD_NAME} --domain-name example.com + +For more informations visit https://masedi.net/lemper +Mail bug reports and suggestions to +EOL +} + +## +# Validate FQDN domain. +## +function validate_fqdn() { + local FQDN=${1} + + if grep -qP "(?=^.{4,253}\.?$)(^((?!-)[a-zA-Z0-9-]{1,63}(? +## +function generate_selfsigned_ssl() { DOMAIN=${1} SERVER_IP=${2:-$(hostname -I | awk '{print $1}')} KEY_HASH_LENGTH=2048 if [ -z "${DOMAIN}" ]; then - echo "Please specify domain name." - exit 1 + fail "Please specify domain name." + fi + + if [[ $(validate_fqdn "${DOMAIN}") == false ]]; then + fail "Your Domain name is not valid 'Fully Qualified Domain Name (FQDN)' format!" fi if [ ! -d "/etc/lemper/ssl/${DOMAIN}" ]; then @@ -43,26 +95,21 @@ function sslgen() { fi # Self-signed certificate for local development environment. - sed -i "s|^CN\ =\ .*|CN\ =\ ${DOMAIN}|g" /etc/lemper/ssl/ca.conf && \ - sed -i "s|^CN\ =\ .*|CN\ =\ ${DOMAIN}|g" /etc/lemper/ssl/csr.conf && \ - sed -i "s|^DNS\.1\ =\ .*|DNS\.1\ =\ ${DOMAIN}|g" /etc/lemper/ssl/csr.conf && \ - sed -i "s|^DNS\.2\ =\ .*|DNS\.2\ =\ www\.${DOMAIN}|g" /etc/lemper/ssl/csr.conf && \ - sed -r -i "s|^IP.1\ =\ (\b[0-9]{1,3}\.){3}[0-9]{1,3}\b$|IP.1\ =\ ${SERVER_IP}|g" /etc/lemper/ssl/csr.conf && \ - sed -r -i "s|^IP.2\ =\ (\b[0-9]{1,3}\.){3}[0-9]{1,3}\b$|IP.2\ =\ ${SERVER_IP}|g" /etc/lemper/ssl/csr.conf && \ - sed -i "s|^DNS\.1\ =\ .*|DNS\.1\ =\ ${DOMAIN}|g" /etc/lemper/ssl/cert.conf + run sed -i "s|^CN\ =\ .*|CN\ =\ ${DOMAIN}|g" /etc/lemper/ssl/ca.conf && \ + run sed -i "s|^CN\ =\ .*|CN\ =\ ${DOMAIN}|g" /etc/lemper/ssl/csr.conf && \ + run sed -i "s|^DNS\.1\ =\ .*|DNS\.1\ =\ ${DOMAIN}|g" /etc/lemper/ssl/csr.conf && \ + run sed -i "s|^DNS\.2\ =\ .*|DNS\.2\ =\ www\.${DOMAIN}|g" /etc/lemper/ssl/csr.conf && \ + run sed -r -i "s|^IP.1\ =\ (\b[0-9]{1,3}\.){3}[0-9]{1,3}\b$|IP.1\ =\ ${SERVER_IP}|g" /etc/lemper/ssl/csr.conf && \ + run sed -r -i "s|^IP.2\ =\ (\b[0-9]{1,3}\.){3}[0-9]{1,3}\b$|IP.2\ =\ ${SERVER_IP}|g" /etc/lemper/ssl/csr.conf && \ + run sed -i "s|^DNS\.1\ =\ .*|DNS\.1\ =\ ${DOMAIN}|g" /etc/lemper/ssl/cert.conf # Create Certificate Authority (CA). - if [[ ! -f /etc/lemper/ssl/lemperCA.key || ! -f /etc/lemper/ssl/lemperCA.crt ]]; then - run openssl req -x509 -sha256 -days 365000 -nodes -newkey "rsa:${KEY_HASH_LENGTH}" \ - -keyout "/etc/lemper/ssl/${DOMAIN}-ca.key" -out "/etc/lemper/ssl/${DOMAIN}-ca.crt" \ - -config /etc/lemper/ssl/ca.conf + run openssl req -x509 -sha256 -days 365000 -nodes -newkey rsa:2048 \ + -keyout "/etc/lemper/ssl/${DOMAIN}/ca.key" -out "/etc/lemper/ssl/${DOMAIN}/ca.crt" \ + -config /etc/lemper/ssl/ca.conf - CA_KEY_FILE="/etc/lemper/ssl/${DOMAIN}-ca.key" - CA_CRT_FILE="/etc/lemper/ssl/${DOMAIN}-ca.crt" - else - CA_KEY_FILE="/etc/lemper/ssl/lemperCA.key" - CA_CRT_FILE="/etc/lemper/ssl/lemperCA.crt" - fi + CA_KEY_FILE="/etc/lemper/ssl/${DOMAIN}/ca.key" + CA_CRT_FILE="/etc/lemper/ssl/${DOMAIN}/ca.crt" # Create Server Private Key. run openssl genrsa -out "/etc/lemper/ssl/${DOMAIN}/privkey.pem" "${KEY_HASH_LENGTH}" && \ @@ -82,16 +129,84 @@ function sslgen() { "/etc/lemper/ssl/${DOMAIN}/fullchain.pem" if [ -f "/etc/lemper/ssl/${DOMAIN}/cert.pem" ]; then - echo "Self-signed SSL certificate has been successfully generated." + info "Self-signed SSL certificate has been successfully generated." echo "Certificate file: /etc/lemper/ssl/${DOMAIN}/cert.pem" echo "Private key file: /etc/lemper/ssl/${DOMAIN}/privkey.pem" + echo "Full chain file: /etc/lemper/ssl/${DOMAIN}/fullchain.pem" exit 0 else - echo "An error occurred when generating self-signed SSL certificate." - exit 1 + fail "An error occurred while generating self-signed SSL certificate." + fi +} + +## +# Main App +# +function init_selfsigned_ssl() { + # Command line arguments. + OPTS=$(getopt -o d:4:6: \ + -l domain-name:,ipv4:,ipv6: \ + -n "${PROG_NAME}" -- "$@") + + eval set -- "${OPTS}" + + # Default parameter values. + DOMAIN="" + IPv4="" + IPv6="" + + # Args counter + MAIN_ARGS=0 + + # Parse flags + while true; do + case "${1}" in + -4 | --ipv4) + shift + IPv4="${1}" + shift + ;; + -6 | --ipv6) + shift + IPv6="${1}" + shift + ;; + -d | --domain-name) + shift + DOMAIN="${1}" + MAIN_ARGS=$((MAIN_ARGS + 1)) + shift + ;; + -h | --help) + shift + show_usage + exit 0 + ;; + -v | --version) + shift + echo "${PROG_NAME} version ${PROG_VERSION}" + exit 0 + ;; + --) + # End of all options, shift to the next (non getopt) argument as $1. + shift + break + ;; + *) + fail "Invalid argument: ${1}" + exit 1 + ;; + esac + done + + if [[ "${MAIN_ARGS}" -ge 1 ]]; then + generate_selfsigned_ssl "${DOMAIN}" "${IPv4}" "${IPv6}" + else + echo "${CMD_PARENT} ${CMD_NAME}: missing required arguments." + echo "See '${CMD_PARENT} ${CMD_NAME} --help' for more information." fi } # Start running things from a call at the end so if this script is executed # after a partial download it doesn't do anything. -sslgen "$@" +init_selfsigned_ssl "$@" diff --git a/lib/lemper-site.sh b/lib/lemper-site.sh index 998a39f..0c34e8f 100755 --- a/lib/lemper-site.sh +++ b/lib/lemper-site.sh @@ -15,18 +15,16 @@ # | Authors: Edi Septriyanto | # +-------------------------------------------------------------------------+ +# Version control. +CMD_PARENT="${PROG_NAME}" +CMD_NAME="site" + # Make sure only root can access and not direct access. if [[ "$(type -t requires_root)" != "function" ]]; then echo "Direct access to this script is not permitted." exit 1 fi -# Version control. -#PROG_NAME=$(basename "$0") -#PROG_VER="2.x.x" -CMD_PARENT="lemper-cli" -CMD_NAME="site" - if [ -z "${CLI_PLUGINS_DIR}" ]; then CLI_PLUGINS_DIR="/etc/lemper/cli-plugins" fi