Files
mattermost/install-update-oidc-mobile-bridge.sh
T

1354 lines
42 KiB
Bash
Executable File

#!/usr/bin/env bash
script_name="$(basename $(realpath $0))"
working_dir="$(dirname $(realpath $0))"
LOCK_DIR="/tmp/$(basename $0).$$.LOCK"
log_file="${LOCK_DIR}/${script_name%%.*}.log"
backup_date="$(date +%Y-%m-%d-%H%M%S)"
MM_OIDC_REPOSITORY="https://github.com/server-camp/mattermost-oidc-plugin.git"
MM_BRIDGE_SOURCE_BASE="/usr/local/src/mattermost-oidc/mobile-bridge"
MM_BRIDGE_INSTALL_DIR="/usr/local/sbin"
MM_BRIDGE_NAME="mattermost-oidc-mobile-bridge"
MM_BRIDGE_LINK="${MM_BRIDGE_INSTALL_DIR}/${MM_BRIDGE_NAME}"
MM_BRIDGE_SERVICE="mattermost-oidc-mobile-bridge.service"
MM_SERVICE="mattermost.service"
MM_USER="mattermost"
MM_GROUP="mattermost"
MM_BRIDGE_LISTEN="127.0.0.1:8066"
MM_BRIDGE_UPSTREAM="http://127.0.0.1:8065"
MM_CONFIG_FILE="/opt/mattermost/config/config.json"
MM_SITE_URL=""
INSTALLATION_MODE=""
MM_CURRENT_VERSION=""
MM_CURRENT_TARGET=""
MM_NEW_VERSION=""
MM_LATEST_VERSION=""
MM_SOURCE_DIR=""
MM_BRIDGE_BIN=""
NGINX_CONFIG_FILE=""
NGINX_CHANGED=false
SYMLINK_CHANGED=false
UNIT_CREATED=false
ROLLBACK_TARGET=""
LEGACY_BRIDGE_BACKUP=""
REINSTALL_BRIDGE_BACKUP=""
# ----------
# Base Function(s)
# ----------
clean_up() {
rm -rf "$LOCK_DIR"
blank_line
exit $1
}
echononl(){
if $terminal ; then
echo X\\c > /tmp/shprompt$$
if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then
echo -e -n " $*\\c" 1>&2
else
echo -e -n " $*" 1>&2
fi
rm /tmp/shprompt$$
fi
}
fatal(){
echo ""
if $terminal ; then
echo -e " [ \033[31m\033[1mFatal\033[m ] $*"
else
echo -e " [ Fatal ] $*"
fi
echo ""
if $terminal ; then
echo -e " \033[1mScript terminated\033[m.."
else
echo -e " Script terminated.."
fi
echo ""
clean_up 1
}
error (){
echo ""
if $terminal ; then
echo -e " [ \033[31m\033[1mError\033[m ] $*"
else
echo " [ Error ] $*"
fi
echo ""
}
warn (){
echo ""
if $terminal ; then
echo -e " [ \033[33m\033[1mWarning\033[m ] $*"
else
echo " [ Warning ] $*"
fi
echo ""
}
info (){
if $terminal ; then
echo ""
echo -e " [ \033[32m\033[1mInfo\033[m ] $*"
echo ""
fi
}
echo_ok() {
if $terminal ; then
echo -e "\033[85G[ \033[32mok\033[m ]"
fi
}
echo_failed(){
if $terminal ; then
echo -e "\033[85G[ \033[1;31mfailed\033[m ]"
fi
}
echo_skipped() {
if $terminal ; then
echo -e "\033[85G[ \033[33m\033[1mskipped\033[m ]"
fi
}
echo_wait(){
if $terminal ; then
echo -en "\033[85G[ \033[5m\033[1m..\033[m ]"
fi
}
blank_line() {
if $terminal ; then
echo ""
fi
}
ask_yes_no() {
local question="$1"
local default_answer="${2:-no}"
local answer=""
local prompt="[yes/no]"
if [[ "$default_answer" = "yes" ]]; then
prompt="[yes/no, default: yes]"
elif [[ "$default_answer" = "no" ]]; then
prompt="[yes/no, default: no]"
fi
while true ; do
echononl "$question $prompt: "
read answer
answer="${answer,,}"
[[ -z "$answer" ]] && answer="$default_answer"
case "$answer" in
yes) return 0 ;;
no) return 1 ;;
*) warn "Wrong entry! Please enter 'yes' or 'no'." ;;
esac
done
}
rollback_bridge() {
local rollback_failed=false
local rollback_path=""
local rollback_tmp_link="${MM_BRIDGE_LINK}.rollback.$$"
[[ "$SYMLINK_CHANGED" = true ]] || return 0
if [[ "$INSTALLATION_MODE" = "initial-installation" ]]; then
warn "The new bridge did not pass all checks. Cleaning up the initial activation."
systemctl stop "$MM_BRIDGE_SERVICE" >> "$log_file" 2>&1 || true
if [[ "$UNIT_CREATED" = true ]]; then
systemctl disable "$MM_BRIDGE_SERVICE" >> "$log_file" 2>&1 || rollback_failed=true
fi
rm -f "$MM_BRIDGE_LINK" >> "$log_file" 2>&1 || rollback_failed=true
if [[ "$NGINX_CHANGED" = true && -n "$NGINX_BACKUP" && -f "$NGINX_BACKUP" ]]; then
warn "Restoring the nginx configuration from before the initial bridge installation."
if cp -a "$NGINX_BACKUP" "$NGINX_CONFIG_FILE" >> "$log_file" 2>&1 \
&& nginx -t >> "$log_file" 2>&1 \
&& systemctl reload nginx.service >> "$log_file" 2>&1 ; then
info "Previous nginx configuration was restored and reloaded."
else
rollback_failed=true
error "Could not fully restore/reload the previous nginx configuration. Check nginx manually."
fi
fi
if [[ "$rollback_failed" = true ]]; then
error "Initial-install cleanup was not fully successful. Please check '${MM_BRIDGE_LINK}', '${MM_BRIDGE_SERVICE}' and nginx manually."
return 1
else
info "Initial activation was removed. The new binary, source directory and unit file were kept for analysis."
return 0
fi
fi
warn "The new bridge did not pass all checks. Trying to restore the previous installation."
if [[ -n "$ROLLBACK_TARGET" ]]; then
if [[ "$ROLLBACK_TARGET" = /* ]]; then
rollback_path="$ROLLBACK_TARGET"
else
rollback_path="${MM_BRIDGE_INSTALL_DIR}/${ROLLBACK_TARGET}"
fi
fi
# A same-version reinstall replaces the file referenced by ROLLBACK_TARGET.
# Restore that saved binary first; changing the symlink alone would otherwise
# still point to the newly installed (and possibly broken) binary.
if [[ -n "$REINSTALL_BRIDGE_BACKUP" ]]; then
echononl "Restore previous same-version bridge binary.."
_restore_tmp="${MM_BRIDGE_BIN}.restore.$$"
rm -f "$_restore_tmp"
if [[ -f "$REINSTALL_BRIDGE_BACKUP" ]] \
&& cp -a "$REINSTALL_BRIDGE_BACKUP" "$_restore_tmp" >> "$log_file" 2>&1 \
&& mv -Tf "$_restore_tmp" "$MM_BRIDGE_BIN" >> "$log_file" 2>&1 ; then
echo_ok
else
rm -f "$_restore_tmp"
echo_failed
error "Could not restore '${REINSTALL_BRIDGE_BACKUP}' to '${MM_BRIDGE_BIN}'."
rollback_failed=true
fi
fi
if [[ "$rollback_failed" = false ]]; then
if [[ -n "$ROLLBACK_TARGET" && -e "$rollback_path" ]]; then
echononl "Restore previous stable bridge symlink.."
rm -f "$rollback_tmp_link"
if ln -s "$ROLLBACK_TARGET" "$rollback_tmp_link" >> "$log_file" 2>&1 \
&& mv -Tf "$rollback_tmp_link" "$MM_BRIDGE_LINK" >> "$log_file" 2>&1 ; then
echo_ok
else
rm -f "$rollback_tmp_link"
echo_failed
error "Could not restore stable bridge symlink '${MM_BRIDGE_LINK}' -> '${ROLLBACK_TARGET}'."
rollback_failed=true
fi
elif [[ -n "$LEGACY_BRIDGE_BACKUP" && -f "$LEGACY_BRIDGE_BACKUP" ]]; then
echononl "Restore previous legacy bridge binary.."
if rm -f "$MM_BRIDGE_LINK" >> "$log_file" 2>&1 \
&& cp -a "$LEGACY_BRIDGE_BACKUP" "$MM_BRIDGE_LINK" >> "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
error "Could not restore legacy bridge binary from '${LEGACY_BRIDGE_BACKUP}'."
rollback_failed=true
fi
else
error "No usable rollback target was found."
rollback_failed=true
fi
fi
if [[ "$rollback_failed" = false ]]; then
echononl "Restart previous Mattermost OIDC Mobile Bridge service.."
if systemctl restart "$MM_BRIDGE_SERVICE" >> "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
error "Could not restart '${MM_BRIDGE_SERVICE}' after rollback."
rollback_failed=true
fi
fi
if [[ "$NGINX_CHANGED" = true && -n "$NGINX_BACKUP" && -f "$NGINX_BACKUP" ]]; then
echononl "Restore previous nginx configuration.."
if cp -a "$NGINX_BACKUP" "$NGINX_CONFIG_FILE" >> "$log_file" 2>&1 \
&& nginx -t >> "$log_file" 2>&1 \
&& systemctl reload nginx.service >> "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
error "Could not fully restore/reload the previous nginx configuration. Check nginx manually."
rollback_failed=true
fi
fi
if [[ "$rollback_failed" = true ]]; then
error "Automatic rollback failed. Please check the bridge installation, '${MM_BRIDGE_SERVICE}' and nginx configuration manually."
return 1
else
info "Previous bridge installation was restored and restarted."
return 0
fi
}
bridge_test() {
local response=""
local location=""
local http_code=""
local headers_file="${LOCK_DIR}/bridge-redirect-headers"
echononl "Check bridge service status.."
if systemctl is-active --quiet "$MM_BRIDGE_SERVICE" ; then
echo_ok
else
echo_failed
return 1
fi
echononl "Check bridge listener '${MM_BRIDGE_LISTEN}'.."
_listener_ready=false
for _listener_try in {1..10}; do
if ss -lnt | awk -v listen="$MM_BRIDGE_LISTEN" '$4 == listen {found=1} END {exit !found}' ; then
_listener_ready=true
break
fi
sleep 1
done
if [[ "$_listener_ready" = true ]]; then
echo_ok
else
echo_failed
return 1
fi
echononl "Test mobile client configuration endpoint.."
if response="$(curl -fsS --max-time 10 \
-A 'Mattermost Mobile/2.0' \
"http://${MM_BRIDGE_LISTEN}/api/v4/config/client" 2>> "$log_file")" \
&& printf '%s' "$response" | python3 -c '
import json, sys
try:
value = json.load(sys.stdin).get("EnableSignUpWithOpenId")
except Exception:
raise SystemExit(1)
raise SystemExit(0 if value in (True, "true") else 1)
' ; then
echo_ok
else
echo_failed
return 1
fi
echononl "Test browser client configuration endpoint.."
if response="$(curl -fsS --max-time 10 \
-A 'Mozilla/5.0' \
"http://${MM_BRIDGE_LISTEN}/api/v4/config/client" 2>> "$log_file")" \
&& printf '%s' "$response" | python3 -c '
import json, sys
try:
value = json.load(sys.stdin).get("EnableSignUpWithOpenId")
except Exception:
raise SystemExit(1)
raise SystemExit(0 if value in (False, "false") else 1)
' ; then
echo_ok
else
echo_failed
return 1
fi
echononl "Test mobile OIDC redirect endpoint.."
: > "$headers_file"
http_code="$(curl -sS --max-time 10 \
-o /dev/null -D "$headers_file" -w '%{http_code}' \
"http://${MM_BRIDGE_LISTEN}/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback" \
2>> "$log_file")"
location="$(awk 'BEGIN{IGNORECASE=1} /^Location:/ {sub(/^[^:]*:[[:space:]]*/,""); sub(/\r$/,""); print; exit}' "$headers_file")"
if [[ "$http_code" = "302" ]] \
&& [[ "$location" == /plugins/mattermost-oidc/oauth2/connect* ]] \
&& [[ "$location" == *"mobile_redirect="* ]]; then
echo_ok
else
echo_failed
return 1
fi
return 0
}
nginx_e2e_test() {
local response=""
local location=""
local http_code=""
local headers_file="${LOCK_DIR}/nginx-redirect-headers"
[[ -n "$MM_SITE_URL" ]] || return 0
echononl "Test mobile client configuration endpoint through nginx.."
if response="$(curl -fsS --max-time 10 \
-A 'Mattermost Mobile/2.0' \
"${MM_SITE_URL%/}/api/v4/config/client" 2>> "$log_file")" \
&& printf '%s' "$response" | python3 -c '
import json, sys
try:
value = json.load(sys.stdin).get("EnableSignUpWithOpenId")
except Exception:
raise SystemExit(1)
raise SystemExit(0 if value in (True, "true") else 1)
' ; then
echo_ok
else
echo_failed
return 1
fi
echononl "Test browser client configuration endpoint through nginx.."
if response="$(curl -fsS --max-time 10 \
-A 'Mozilla/5.0' \
"${MM_SITE_URL%/}/api/v4/config/client" 2>> "$log_file")" \
&& printf '%s' "$response" | python3 -c '
import json, sys
try:
value = json.load(sys.stdin).get("EnableSignUpWithOpenId")
except Exception:
raise SystemExit(1)
raise SystemExit(0 if value in (False, "false") else 1)
' ; then
echo_ok
else
echo_failed
return 1
fi
echononl "Test mobile OIDC redirect endpoint through nginx.."
: > "$headers_file"
http_code="$(curl -sS --max-time 10 \
-o /dev/null -D "$headers_file" -w '%{http_code}' \
"${MM_SITE_URL%/}/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback" \
2>> "$log_file")"
location="$(awk 'BEGIN{IGNORECASE=1} /^Location:/ {sub(/^[^:]*:[[:space:]]*/,""); sub(/\r$/,""); print; exit}' "$headers_file")"
if [[ "$http_code" = "302" ]] \
&& [[ "$location" == /plugins/mattermost-oidc/oauth2/connect* ]] \
&& [[ "$location" == *"mobile_redirect="* ]]; then
echo_ok
else
echo_failed
return 1
fi
return 0
}
# ----------
# Jobhandling
# ----------
trap 'clean_up 1' SIGHUP SIGINT SIGTERM
if ! mkdir "$LOCK_DIR" 2>/dev/null ; then
echo "Cannot create lock directory '$LOCK_DIR'."
exit 1
fi
if [[ -t 1 ]] ; then
terminal=true
else
fatal "Script must run in a terminal."
fi
# ==========
# Begin Main Script
# ==========
if $terminal ; then
echo ""
echo -e "\033[1m----------\033[m"
echo -e "\033[32m\033[1mRunning script \033[m\033[1m$script_name\033[32m .. \033[m"
echo -e "\033[1m----------\033[m"
fi
blank_line
# ----------
# Some checks
# ----------
echononl "Check if script is running as root.."
if [[ "$(id -u)" -eq 0 ]]; then
echo_ok
else
echo_failed
fatal "This script must be run as root."
fi
for _cmd in git systemctl systemd-analyze curl ss awk grep sed sort file install readlink ln mv cp mkdir python3 ; do
echononl "Check for command '${_cmd}'.."
if command -v "$_cmd" > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Required command '${_cmd}' was not found."
fi
done
echononl "Check Mattermost user '${MM_USER}'.."
if id "$MM_USER" > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Mattermost user '${MM_USER}' does not exist."
fi
echononl "Check Mattermost group '${MM_GROUP}'.."
if getent group "$MM_GROUP" > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Mattermost group '${MM_GROUP}' does not exist."
fi
echononl "Check Mattermost service '${MM_SERVICE}'.."
if systemctl cat "$MM_SERVICE" > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Mattermost service '${MM_SERVICE}' was not found."
fi
# ----------
# Detect installation mode
# ----------
echononl "Detect existing Mattermost OIDC Mobile Bridge installation.."
if [[ -L "$MM_BRIDGE_LINK" ]]; then
MM_CURRENT_TARGET="$(readlink "$MM_BRIDGE_LINK")"
if [[ ! -e "$MM_BRIDGE_LINK" ]]; then
echo_failed
fatal "Broken symlink '${MM_BRIDGE_LINK}' -> '${MM_CURRENT_TARGET}'."
fi
if [[ "$MM_CURRENT_TARGET" =~ ^${MM_BRIDGE_NAME}-([0-9]+\.[0-9]+\.[0-9]+.*)$ ]]; then
MM_CURRENT_VERSION="${BASH_REMATCH[1]}"
else
echo_failed
fatal "Cannot determine installed bridge version from symlink target '${MM_CURRENT_TARGET}'."
fi
INSTALLATION_MODE="upgrade"
ROLLBACK_TARGET="$MM_CURRENT_TARGET"
echo_ok
elif [[ -e "$MM_BRIDGE_LINK" ]]; then
INSTALLATION_MODE="legacy-upgrade"
echo_ok
else
INSTALLATION_MODE="initial-installation"
echo_ok
fi
# ----------
# Determine latest stable release
# ----------
echononl "Determine latest stable Mattermost OIDC release.."
MM_LATEST_VERSION="$(git ls-remote --tags --refs "$MM_OIDC_REPOSITORY" 2> "$log_file" \
| awk '{print $2}' \
| sed -nE 's#refs/tags/v([0-9]+\.[0-9]+\.[0-9]+)$#\1#p' \
| sort -V \
| tail -1)"
if [[ -n "$MM_LATEST_VERSION" ]]; then
echo_ok
else
echo_failed
fatal "Could not determine latest stable release from '${MM_OIDC_REPOSITORY}'. $(cat "$log_file")"
fi
blank_line
if [[ "$INSTALLATION_MODE" = "initial-installation" ]]; then
echo " Installation mode....................: Initial installation"
elif [[ "$INSTALLATION_MODE" = "legacy-upgrade" ]]; then
echo " Installation mode....................: Upgrade of legacy/unversioned installation"
echo " Currently installed version.........: unknown"
else
echo " Installation mode....................: Upgrade"
echo " Currently installed version.........: ${MM_CURRENT_VERSION}"
fi
echo " Latest stable version...............: ${MM_LATEST_VERSION}"
blank_line
while true ; do
echononl "New Mattermost OIDC Mobile Bridge Version [${MM_LATEST_VERSION}]: "
read MM_NEW_VERSION
MM_NEW_VERSION="${MM_NEW_VERSION#v}"
[[ -z "$MM_NEW_VERSION" ]] && MM_NEW_VERSION="$MM_LATEST_VERSION"
echononl "Check release tag 'v${MM_NEW_VERSION}'.."
if git ls-remote --exit-code --tags "$MM_OIDC_REPOSITORY" \
"refs/tags/v${MM_NEW_VERSION}" "refs/tags/v${MM_NEW_VERSION}^{}" \
> /dev/null 2> "$log_file" ; then
echo_ok
break
else
echo_failed
warn "Tag 'v${MM_NEW_VERSION}' does not exist in the upstream repository."
fi
done
if [[ "$INSTALLATION_MODE" = "upgrade" && "$MM_NEW_VERSION" = "$MM_CURRENT_VERSION" ]]; then
blank_line
warn "Mattermost OIDC Mobile Bridge ${MM_CURRENT_VERSION} is already installed."
if ! ask_yes_no "Reinstall version ${MM_NEW_VERSION}" "no" ; then
info "Version ${MM_CURRENT_VERSION} is already installed. Nothing to do."
clean_up 0
fi
fi
MM_SOURCE_DIR="${MM_BRIDGE_SOURCE_BASE}/mattermost-oidc-plugin-${MM_NEW_VERSION}"
MM_BRIDGE_BIN="${MM_BRIDGE_INSTALL_DIR}/${MM_BRIDGE_NAME}-${MM_NEW_VERSION}"
if [[ -r "$MM_CONFIG_FILE" ]]; then
MM_SITE_URL="$(python3 - "$MM_CONFIG_FILE" 2>> "$log_file" <<'PY_EOF'
import json, sys
try:
with open(sys.argv[1], encoding="utf-8") as f:
data = json.load(f)
print(data.get("ServiceSettings", {}).get("SiteURL", ""))
except Exception:
pass
PY_EOF
)"
fi
# ----------
# Check systemd and nginx state
# ----------
UNIT_EXISTS=false
if systemctl cat "$MM_BRIDGE_SERVICE" > /dev/null 2>&1 ; then
UNIT_EXISTS=true
fi
NGINX_AVAILABLE=false
if command -v nginx > /dev/null 2>&1 ; then
NGINX_AVAILABLE=true
fi
if [[ "$NGINX_AVAILABLE" = true ]]; then
echononl "Try to detect active Mattermost nginx configuration.."
_nginx_candidates=()
_mm_site_host=""
if [[ -n "$MM_SITE_URL" ]]; then
_mm_site_host="$(python3 - "$MM_SITE_URL" <<'PY_EOF'
from urllib.parse import urlparse
import sys
try:
print(urlparse(sys.argv[1]).hostname or "")
except Exception:
pass
PY_EOF
)"
fi
if [[ -n "$_mm_site_host" ]]; then
mapfile -t _nginx_candidates < <(nginx -T 2>/dev/null \
| awk -v host="$_mm_site_host" '
/^# configuration file \/.*:$/ {f=$0; sub(/^# configuration file /,"",f); sub(/:$/,"",f)}
/^[[:space:]]*server_name[[:space:]]+/ {
line=$0; sub(/#.*/,"",line); gsub(/;/,"",line)
n=split(line,a,/[[:space:]]+/)
for (i=2; i<=n; i++) if (a[i] == host && f != "") print f
}
' | sort -u)
fi
if [[ ${#_nginx_candidates[@]} -eq 0 ]]; then
mapfile -t _nginx_candidates < <(nginx -T 2>/dev/null \
| awk -v upstream="$MM_BRIDGE_UPSTREAM" '
/^# configuration file \/.*:$/ {f=$0; sub(/^# configuration file /,"",f); sub(/:$/,"",f)}
index($0, "proxy_pass " upstream) {if (f != "") print f}
' | sort -u)
fi
if [[ ${#_nginx_candidates[@]} -eq 1 && -f "${_nginx_candidates[0]}" ]]; then
NGINX_CONFIG_FILE="${_nginx_candidates[0]}"
echo_ok
else
echo_skipped
fi
fi
if [[ -n "$NGINX_CONFIG_FILE" ]]; then
echo
echo " Detected Mattermost nginx vHost configuration:"
echo " ${NGINX_CONFIG_FILE}"
echononl "Configuration file [RETURN = use detected file]: "
read _nginx_input
[[ -n "$_nginx_input" ]] && NGINX_CONFIG_FILE="$_nginx_input"
elif [[ "$NGINX_AVAILABLE" = true ]]; then
echo
echo " Mattermost nginx vHost configuration could not be detected automatically."
echo " Enter the full path to the nginx vHost configuration file."
echo " Press RETURN without entering a path to skip nginx setup."
echononl "Configuration file: "
read NGINX_CONFIG_FILE
fi
if [[ -n "$NGINX_CONFIG_FILE" && ! -f "$NGINX_CONFIG_FILE" ]]; then
fatal "nginx configuration file '${NGINX_CONFIG_FILE}' does not exist."
fi
# Work on the real file, not on a sites-enabled symlink. This also makes
# timestamped backups independent from the live symlink.
if [[ -n "$NGINX_CONFIG_FILE" ]]; then
NGINX_CONFIG_FILE="$(readlink -f "$NGINX_CONFIG_FILE")"
[[ -f "$NGINX_CONFIG_FILE" ]] || fatal "Could not resolve nginx configuration file."
fi
# ----------
# Summary
# ----------
blank_line
echo -e "\033[37m\033[1mMattermost OIDC Mobile Bridge installation settings:\033[m"
blank_line
echo " Installation mode....................: ${INSTALLATION_MODE}"
[[ -n "$MM_CURRENT_VERSION" ]] && echo " Current bridge version...............: ${MM_CURRENT_VERSION}"
echo " New bridge version...................: ${MM_NEW_VERSION}"
echo " Latest stable version................: ${MM_LATEST_VERSION}"
echo " Repository...........................: ${MM_OIDC_REPOSITORY}"
echo " Source directory.....................: ${MM_SOURCE_DIR}"
echo " Versioned binary.....................: ${MM_BRIDGE_BIN}"
echo " Stable symlink.......................: ${MM_BRIDGE_LINK}"
echo " Bridge service.......................: ${MM_BRIDGE_SERVICE}"
echo " Bridge listen address................: ${MM_BRIDGE_LISTEN}"
echo " Mattermost upstream..................: ${MM_BRIDGE_UPSTREAM}"
if [[ -n "$NGINX_CONFIG_FILE" ]]; then
echo " nginx configuration..................: ${NGINX_CONFIG_FILE}"
else
echo " nginx configuration..................: not selected"
fi
blank_line
if ! ask_yes_no "einverstanden" "no" ; then
fatal "Stopped by user"
fi
# ----------
# Prepare source tree
# ----------
blank_line
echo -e "\033[37m\033[1mBuild Mattermost OIDC Mobile Bridge..\033[m"
blank_line
echononl "Create source base directory.."
if mkdir -p "$MM_BRIDGE_SOURCE_BASE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
if [[ -e "$MM_SOURCE_DIR" ]]; then
echononl "Backup existing source directory.."
if mv "$MM_SOURCE_DIR" "${MM_SOURCE_DIR}.${backup_date}" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
else
echononl "Backup existing source directory.."
echo_skipped
fi
echononl "Clone release 'v${MM_NEW_VERSION}'.."
if git clone --depth 1 --branch "v${MM_NEW_VERSION}" "$MM_OIDC_REPOSITORY" "$MM_SOURCE_DIR" \
> "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Verify checked out release tag.."
if [[ "$(git -C "$MM_SOURCE_DIR" describe --tags --exact-match 2> "$log_file")" = "v${MM_NEW_VERSION}" ]]; then
echo_ok
else
echo_failed
fatal "Source tree does not match expected tag 'v${MM_NEW_VERSION}'."
fi
if [[ ! -f "${MM_SOURCE_DIR}/mobile-bridge/go.mod" || ! -f "${MM_SOURCE_DIR}/mobile-bridge/main.go" ]]; then
fatal "Expected mobile-bridge source files were not found in '${MM_SOURCE_DIR}/mobile-bridge'."
fi
GO_REQUIRED_VERSION="$(awk '$1 == "go" {print $2; exit}' "${MM_SOURCE_DIR}/mobile-bridge/go.mod")"
[[ -n "$GO_REQUIRED_VERSION" ]] || fatal "Could not determine required Go version from mobile-bridge/go.mod."
echononl "Check if Go is installed.."
if command -v go > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Go is not installed. Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} requires Go ${GO_REQUIRED_VERSION} or newer."
fi
GO_INSTALLED_VERSION="$(go version 2>/dev/null | awk '{sub(/^go/,"",$3); print $3}')"
[[ -n "$GO_INSTALLED_VERSION" ]] || fatal "Could not determine installed Go version."
echononl "Check Go version (installed: ${GO_INSTALLED_VERSION}, required: ${GO_REQUIRED_VERSION}).."
if [[ "$(printf '%s\n%s\n' "$GO_REQUIRED_VERSION" "$GO_INSTALLED_VERSION" | sort -V | head -1)" = "$GO_REQUIRED_VERSION" ]]; then
echo_ok
else
echo_failed
fatal "Installed Go version '${GO_INSTALLED_VERSION}' is too old. Version '${GO_REQUIRED_VERSION}' or newer is required."
fi
echononl "Build Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION}.."
if ( cd "${MM_SOURCE_DIR}/mobile-bridge" && CGO_ENABLED=0 go build -trimpath -o "${LOCK_DIR}/${MM_BRIDGE_NAME}" . ) \
> "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Verify built bridge binary.."
if [[ -x "${LOCK_DIR}/${MM_BRIDGE_NAME}" ]] \
&& file "${LOCK_DIR}/${MM_BRIDGE_NAME}" | grep -q 'ELF' ; then
echo_ok
else
echo_failed
fatal "Built bridge binary is missing, not executable or not an ELF binary."
fi
# ----------
# Install versioned binary
# ----------
blank_line
echo -e "\033[37m\033[1mInstall Mattermost OIDC Mobile Bridge..\033[m"
blank_line
if [[ -e "$MM_BRIDGE_BIN" ]]; then
echononl "Backup existing bridge binary.."
_bridge_binary_backup="${MM_BRIDGE_BIN}.${backup_date}"
if mv "$MM_BRIDGE_BIN" "$_bridge_binary_backup" > "$log_file" 2>&1 ; then
# During a same-version reinstall this backup is the actual rollback
# payload. ROLLBACK_TARGET alone is insufficient because it names the
# same versioned path that is about to be replaced.
if [[ "$INSTALLATION_MODE" = "upgrade" && "$MM_NEW_VERSION" = "$MM_CURRENT_VERSION" ]]; then
REINSTALL_BRIDGE_BACKUP="$_bridge_binary_backup"
fi
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
else
echononl "Backup existing bridge binary.."
echo_skipped
fi
echononl "Install versioned bridge binary.."
if install -o root -g root -m 0755 "${LOCK_DIR}/${MM_BRIDGE_NAME}" "$MM_BRIDGE_BIN" \
> "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
# On an initial installation the systemd unit below already references the
# stable bridge symlink. Create that symlink before systemd-analyze verifies
# the unit. During upgrades, keep the existing symlink untouched until the
# final activation step.
if [[ "$INSTALLATION_MODE" = "initial-installation" ]]; then
echononl "Create initial stable bridge symlink.."
_tmp_link="${MM_BRIDGE_LINK}.new.$$"
rm -f "$_tmp_link"
if ln -s "${MM_BRIDGE_NAME}-${MM_NEW_VERSION}" "$_tmp_link" > "$log_file" 2>&1 \
&& mv -Tf "$_tmp_link" "$MM_BRIDGE_LINK" >> "$log_file" 2>&1 ; then
SYMLINK_CHANGED=true
echo_ok
else
rm -f "$_tmp_link"
echo_failed
fatal "$(cat "$log_file")"
fi
fi
# Preserve an old unversioned installation before replacing it with a symlink.
if [[ "$INSTALLATION_MODE" = "legacy-upgrade" ]]; then
LEGACY_BRIDGE_BACKUP="${MM_BRIDGE_LINK}.${backup_date}"
echononl "Backup legacy bridge binary.."
if mv "$MM_BRIDGE_LINK" "$LEGACY_BRIDGE_BACKUP" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
fi
# ----------
# Install/check systemd unit
# ----------
UNIT_FILE="/etc/systemd/system/${MM_BRIDGE_SERVICE}"
if [[ "$UNIT_EXISTS" = false ]]; then
echononl "Create systemd service '${MM_BRIDGE_SERVICE}'.."
cat > "$UNIT_FILE" <<SYSTEMD_EOF
[Unit]
Description=Mattermost OIDC Mobile Bridge
After=network.target mattermost.service
Requires=mattermost.service
[Service]
Type=simple
User=${MM_USER}
Group=${MM_GROUP}
Environment=LISTEN=${MM_BRIDGE_LISTEN}
Environment=UPSTREAM=${MM_BRIDGE_UPSTREAM}
ExecStart=${MM_BRIDGE_LINK}
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
SYSTEMD_EOF
if [[ $? -eq 0 ]]; then
UNIT_CREATED=true
echo_ok
else
echo_failed
fatal "Failed to create '${UNIT_FILE}'."
fi
echononl "Verify systemd service '${MM_BRIDGE_SERVICE}'.."
if systemd-analyze verify "$UNIT_FILE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Reload systemd configuration.."
if systemctl daemon-reload > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
echononl "Enable '${MM_BRIDGE_SERVICE}'.."
if systemctl enable "$MM_BRIDGE_SERVICE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
else
echononl "Keep existing systemd service '${MM_BRIDGE_SERVICE}'.."
echo_ok
_unit_text="$(systemctl cat "$MM_BRIDGE_SERVICE" 2>/dev/null)"
UNIT_EXECSTART_OK=true
if [[ "$_unit_text" != *"ExecStart=${MM_BRIDGE_LINK}"* ]]; then
UNIT_EXECSTART_OK=false
warn "Existing systemd unit does not contain expected ExecStart=${MM_BRIDGE_LINK}. It will not be changed automatically."
fi
[[ "$_unit_text" == *"LISTEN=${MM_BRIDGE_LISTEN}"* ]] \
|| warn "Existing systemd unit does not contain expected LISTEN=${MM_BRIDGE_LISTEN}. It will not be changed automatically."
[[ "$_unit_text" == *"UPSTREAM=${MM_BRIDGE_UPSTREAM}"* ]] \
|| warn "Existing systemd unit does not contain expected UPSTREAM=${MM_BRIDGE_UPSTREAM}. It will not be changed automatically."
[[ "$_unit_text" == *"User=${MM_USER}"* ]] \
|| warn "Existing systemd unit does not contain expected User=${MM_USER}. It will not be changed automatically."
[[ "$_unit_text" == *"Group=${MM_GROUP}"* ]] \
|| warn "Existing systemd unit does not contain expected Group=${MM_GROUP}. It will not be changed automatically."
if [[ "$UNIT_EXECSTART_OK" = false ]]; then
blank_line
if ! ask_yes_no "Continue although ExecStart differs from the expected stable bridge symlink" "no" ; then
fatal "Stopped by user because existing systemd ExecStart differs."
fi
fi
fi
# Ensure that the bridge service is enabled also when an existing unit is reused.
echononl "Ensure '${MM_BRIDGE_SERVICE}' is enabled.."
if systemctl is-enabled --quiet "$MM_BRIDGE_SERVICE" 2>/dev/null ; then
echo_ok
else
if systemctl enable "$MM_BRIDGE_SERVICE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
fi
# ----------
# Configure nginx if requested
# ----------
if [[ -n "$NGINX_CONFIG_FILE" ]]; then
blank_line
echo -e "\033[37m\033[1mCheck nginx configuration..\033[m"
blank_line
API_LOCATION_STATE="missing"
MOBILE_LOCATION_STATE="missing"
_bridge_proxy_pass="proxy_passhttp://${MM_BRIDGE_LISTEN};"
if grep -Eq '^[[:space:]]*location[[:space:]]*=[[:space:]]*/api/v4/config/client[[:space:]]*\{' "$NGINX_CONFIG_FILE" ; then
if awk -v expected="$_bridge_proxy_pass" '
/^[[:space:]]*location[[:space:]]*=[[:space:]]*\/api\/v4\/config\/client[[:space:]]*\{/ {inloc=1; depth=1; next}
inloc {depth += gsub(/\{/ ,"{"); depth -= gsub(/\}/,"}"); line=$0; gsub(/[[:space:]]/,"",line); if (line == expected) ok=1; if (depth<=0) exit}
END {exit !ok}
' "$NGINX_CONFIG_FILE" ; then
API_LOCATION_STATE="ok"
else
API_LOCATION_STATE="different"
fi
fi
if grep -Eq '^[[:space:]]*location[[:space:]]*=[[:space:]]*/oauth/openid/mobile_login[[:space:]]*\{' "$NGINX_CONFIG_FILE" ; then
if awk -v expected="$_bridge_proxy_pass" '
/^[[:space:]]*location[[:space:]]*=[[:space:]]*\/oauth\/openid\/mobile_login[[:space:]]*\{/ {inloc=1; depth=1; next}
inloc {depth += gsub(/\{/ ,"{"); depth -= gsub(/\}/,"}"); line=$0; gsub(/[[:space:]]/,"",line); if (line == expected) ok=1; if (depth<=0) exit}
END {exit !ok}
' "$NGINX_CONFIG_FILE" ; then
MOBILE_LOCATION_STATE="ok"
else
MOBILE_LOCATION_STATE="different"
fi
fi
echo " /api/v4/config/client.................: ${API_LOCATION_STATE}"
echo " /oauth/openid/mobile_login............: ${MOBILE_LOCATION_STATE}"
blank_line
if [[ "$API_LOCATION_STATE" = "different" || "$MOBILE_LOCATION_STATE" = "different" ]]; then
warn "At least one required location already exists with a different configuration. Existing location blocks will not be modified automatically."
fi
MISSING_LOCATIONS=false
[[ "$API_LOCATION_STATE" = "missing" ]] && MISSING_LOCATIONS=true
[[ "$MOBILE_LOCATION_STATE" = "missing" ]] && MISSING_LOCATIONS=true
if [[ "$MISSING_LOCATIONS" = true ]]; then
if ask_yes_no "Add missing Mattermost OIDC Mobile Bridge locations to nginx configuration" "yes" ; then
NGINX_BACKUP="${NGINX_CONFIG_FILE}.${backup_date}"
echononl "Backup nginx configuration.."
if cp -a "$NGINX_CONFIG_FILE" "$NGINX_BACKUP" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
NGINX_INSERT_FILE="${LOCK_DIR}/nginx-locations.conf"
: > "$NGINX_INSERT_FILE"
if [[ "$API_LOCATION_STATE" = "missing" ]]; then
cat >> "$NGINX_INSERT_FILE" <<NGINX_API_EOF
location = /api/v4/config/client {
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_pass http://${MM_BRIDGE_LISTEN};
}
NGINX_API_EOF
fi
if [[ "$MOBILE_LOCATION_STATE" = "missing" ]]; then
cat >> "$NGINX_INSERT_FILE" <<NGINX_MOBILE_EOF
location = /oauth/openid/mobile_login {
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_pass http://${MM_BRIDGE_LISTEN};
}
NGINX_MOBILE_EOF
fi
echononl "Insert missing bridge locations before Mattermost 'location /'.."
python3 - "$NGINX_CONFIG_FILE" "$NGINX_INSERT_FILE" "$MM_BRIDGE_UPSTREAM" "$_mm_site_host" <<'PY_EOF' > "$log_file" 2>&1
import re
import sys
from pathlib import Path
config = Path(sys.argv[1])
insert = Path(sys.argv[2]).read_text()
upstream = sys.argv[3].rstrip("/")
site_host = sys.argv[4].strip()
text = config.read_text()
def matching_brace(data, open_pos):
depth = 0
quote = None
escaped = False
comment = False
for pos in range(open_pos, len(data)):
ch = data[pos]
if comment:
if ch == "\n":
comment = False
continue
if quote:
if escaped:
escaped = False
elif ch == "\\":
escaped = True
elif ch == quote:
quote = None
continue
if ch == "#":
comment = True
elif ch in ("\"", "'"):
quote = ch
elif ch == "{":
depth += 1
elif ch == "}":
depth -= 1
if depth == 0:
return pos
return None
all_servers = []
for match in re.finditer(r'(?m)^[ \t]*server[ \t]*\{', text):
open_pos = text.find("{", match.start(), match.end())
close_pos = matching_brace(text, open_pos)
if close_pos is None:
raise SystemExit("Could not parse nginx server block")
body = text[open_pos + 1:close_pos]
all_servers.append((open_pos + 1, close_pos, body))
def general_locations(body):
return list(re.finditer(r'(?m)^[ \t]*location[ \t]+/[ \t]*\{', body))
# Prefer the Mattermost vHost identified by SiteURL/server_name. This works
# with both direct proxy_pass targets and named nginx upstreams. The HTTP
# redirect vHost is excluded because it has no general "location /" block.
servers = []
if site_host:
for server in all_servers:
body = server[2]
names = []
for match in re.finditer(r'(?m)^[ \t]*server_name[ \t]+([^;]+);', body):
names.extend(match.group(1).split())
if site_host in names and len(general_locations(body)) == 1:
servers.append(server)
# Fallback for installations where SiteURL is unavailable: retain the old
# direct-upstream detection.
if not servers:
proxy_re = re.compile(r'proxy_pass\s+' + re.escape(upstream) + r'/?\s*;')
servers = [
server for server in all_servers
if proxy_re.search(server[2]) and len(general_locations(server[2])) == 1
]
if len(servers) != 1:
if site_host:
raise SystemExit(
f"Expected exactly one Mattermost server block for server_name "
f"{site_host} with a general 'location /', found {len(servers)}"
)
raise SystemExit(
f"Expected exactly one server block proxying to {upstream} "
f"with a general 'location /', found {len(servers)}"
)
body_start, body_end, body = servers[0]
locations = general_locations(body)
insert_pos = body_start + locations[0].start()
text = text[:insert_pos] + insert + text[insert_pos:]
config.write_text(text)
PY_EOF
if [[ $? -eq 0 ]]; then
echo_ok
NGINX_CHANGED=true
else
echo_failed
cp -a "$NGINX_BACKUP" "$NGINX_CONFIG_FILE"
fatal "Could not insert nginx location blocks. Original configuration was restored. $(cat "$log_file")"
fi
echononl "Test nginx configuration.."
if nginx -t > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
cp -a "$NGINX_CONFIG_FILE" "${NGINX_CONFIG_FILE}.failed-${backup_date}" 2>/dev/null
cp -a "$NGINX_BACKUP" "$NGINX_CONFIG_FILE"
nginx -t >> "$log_file" 2>&1
fatal "nginx configuration test failed. Original configuration was restored. See '${NGINX_CONFIG_FILE}.failed-${backup_date}' and '${log_file}' while this script is running."
fi
else
warn "Missing nginx location blocks were not added."
fi
fi
fi
# ----------
# Switch stable symlink and start bridge
# ----------
blank_line
echo -e "\033[37m\033[1mActivate Mattermost OIDC Mobile Bridge..\033[m"
blank_line
if [[ "$INSTALLATION_MODE" = "initial-installation" ]] \
&& [[ -L "$MM_BRIDGE_LINK" ]] \
&& [[ "$(readlink "$MM_BRIDGE_LINK")" = "${MM_BRIDGE_NAME}-${MM_NEW_VERSION}" ]]; then
echononl "Keep initial stable bridge symlink to '${MM_BRIDGE_NAME}-${MM_NEW_VERSION}'.."
echo_ok
else
echononl "Switch stable bridge symlink to '${MM_BRIDGE_NAME}-${MM_NEW_VERSION}'.."
_tmp_link="${MM_BRIDGE_LINK}.new.$$"
rm -f "$_tmp_link"
if ln -s "${MM_BRIDGE_NAME}-${MM_NEW_VERSION}" "$_tmp_link" > "$log_file" 2>&1 \
&& mv -Tf "$_tmp_link" "$MM_BRIDGE_LINK" >> "$log_file" 2>&1 ; then
SYMLINK_CHANGED=true
echo_ok
else
rm -f "$_tmp_link"
echo_failed
fatal "$(cat "$log_file")"
fi
fi
if [[ "$NGINX_CHANGED" = true ]]; then
echononl "Reload nginx service.."
if systemctl reload nginx.service > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
error "nginx reload failed. Restoring the previous nginx configuration."
nginx_rollback_failed=false
cp -a "$NGINX_CONFIG_FILE" "${NGINX_CONFIG_FILE}.failed-${backup_date}" 2>/dev/null || true
if cp -a "$NGINX_BACKUP" "$NGINX_CONFIG_FILE" >> "$log_file" 2>&1 \
&& nginx -t >> "$log_file" 2>&1 \
&& systemctl reload nginx.service >> "$log_file" 2>&1 ; then
info "Previous nginx configuration was restored and reloaded."
NGINX_CHANGED=false
else
error "Could not fully restore/reload the previous nginx configuration. Check nginx manually."
nginx_rollback_failed=true
fi
if rollback_bridge ; then
bridge_rollback_failed=false
else
bridge_rollback_failed=true
fi
if [[ "$nginx_rollback_failed" = false && "$bridge_rollback_failed" = false ]]; then
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed because nginx could not be reloaded.\n The previous nginx configuration and bridge installation were successfully restored."
else
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed because nginx could not be reloaded.\n The previous system state could not be fully restored.\n\n Manual intervention is required."
fi
fi
fi
echononl "Restart Mattermost OIDC Mobile Bridge service.."
if systemctl restart "$MM_BRIDGE_SERVICE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
if rollback_bridge ; then
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed because '${MM_BRIDGE_SERVICE}' could not be restarted.\n The previous bridge installation was successfully restored."
else
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed because '${MM_BRIDGE_SERVICE}' could not be restarted.\n The previous installation could not be restored.\n\n Manual intervention is required."
fi
fi
if ! bridge_test ; then
if rollback_bridge ; then
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed.\n The previous bridge installation was successfully restored."
else
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed\n and the previous installation could not be restored.\n\n Manual intervention is required."
fi
fi
if [[ -n "$NGINX_CONFIG_FILE" ]]; then
if [[ -n "$MM_SITE_URL" ]]; then
if ! nginx_e2e_test ; then
if rollback_bridge ; then
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed during the nginx end-to-end test.\n The previous bridge installation was successfully restored."
else
fatal "Installation of Mattermost OIDC Mobile Bridge ${MM_NEW_VERSION} failed during the nginx end-to-end test\n and the previous installation could not be restored.\n\n Manual intervention is required."
fi
fi
else
warn "Mattermost SiteURL could not be read from '${MM_CONFIG_FILE}'. End-to-end nginx tests were skipped."
fi
fi
# ----------
# Remove redundant same-version backup after successful tests
# ----------
if [[ -n "$REINSTALL_BRIDGE_BACKUP" && -f "$REINSTALL_BRIDGE_BACKUP" ]]; then
if cmp -s "$REINSTALL_BRIDGE_BACKUP" "$MM_BRIDGE_BIN"; then
echononl "Remove identical same-version bridge backup.."
if rm -f "$REINSTALL_BRIDGE_BACKUP" > "$log_file" 2>&1 ; then
echo_ok
REINSTALL_BRIDGE_BACKUP=""
else
echo_failed
warn "Could not remove redundant bridge backup '${REINSTALL_BRIDGE_BACKUP}'."
fi
else
echononl "Keep different same-version bridge backup.."
echo_ok
fi
fi
# ----------
# Final information
# ----------
blank_line
echo -e "\033[37m\033[1mMattermost OIDC Mobile Bridge successfully installed.\033[m"
blank_line
echo " Installed version.....................: ${MM_NEW_VERSION}"
echo " Binary................................: ${MM_BRIDGE_BIN}"
echo " Symlink...............................: ${MM_BRIDGE_LINK} -> $(readlink "$MM_BRIDGE_LINK")"
echo " Source directory......................: ${MM_SOURCE_DIR}"
echo " Service...............................: ${MM_BRIDGE_SERVICE}"
if [[ -n "$NGINX_CONFIG_FILE" ]]; then
echo " nginx configuration...................: ${NGINX_CONFIG_FILE}"
fi
blank_line
clean_up 0