130 lines
3.5 KiB
Bash
Executable File
130 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "${script_dir}/.." && pwd)"
|
|
|
|
custom_apps_root="${NEXTCLOUD_CUSTOM_APPS_PATH:-${repo_root}/nextcloud/custom_apps}"
|
|
app_path="${USER_OIDC_APP_PATH:-}"
|
|
dry_run="0"
|
|
|
|
usage() {
|
|
cat <<USAGE
|
|
Usage: ./scripts/patch-user-oidc-invite-flow.sh [options]
|
|
|
|
Apply the NuQloud invite-token bridge to an installed upstream user_oidc app.
|
|
|
|
Options:
|
|
--app-path <path> Path to user_oidc app directory
|
|
--custom-apps-path <path> Nextcloud custom_apps path
|
|
--dry-run Check whether patch is needed without writing
|
|
-h, --help Show this help
|
|
USAGE
|
|
}
|
|
|
|
resolve_path() {
|
|
local raw="${1:-}"
|
|
if [[ -z "${raw}" ]]; then
|
|
printf '%s' ""
|
|
elif [[ "${raw}" == /* ]]; then
|
|
printf '%s' "${raw}"
|
|
else
|
|
printf '%s' "${repo_root}/${raw}"
|
|
fi
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--app-path)
|
|
app_path="${2:-}"
|
|
shift 2
|
|
;;
|
|
--app-path=*)
|
|
app_path="${1#*=}"
|
|
shift
|
|
;;
|
|
--custom-apps-path)
|
|
custom_apps_root="${2:-}"
|
|
shift 2
|
|
;;
|
|
--custom-apps-path=*)
|
|
custom_apps_root="${1#*=}"
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
dry_run="1"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
custom_apps_root="$(resolve_path "${custom_apps_root}")"
|
|
if [[ -z "${app_path}" ]]; then
|
|
app_path="${custom_apps_root}/user_oidc"
|
|
else
|
|
app_path="$(resolve_path "${app_path}")"
|
|
fi
|
|
|
|
login_controller="${app_path}/lib/Controller/LoginController.php"
|
|
if [[ ! -f "${login_controller}" ]]; then
|
|
echo "Missing user_oidc LoginController: ${login_controller}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if grep -q "getParam('invite_token'" "${login_controller}" 2>/dev/null; then
|
|
echo "user_oidc invite bridge already present: ${login_controller}"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "${dry_run}" == "1" ]]; then
|
|
echo "user_oidc invite bridge would be applied: ${login_controller}"
|
|
exit 0
|
|
fi
|
|
|
|
tmp_file="$(mktemp)"
|
|
cleanup() {
|
|
rm -f "${tmp_file}"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
if ! perl -0pe '
|
|
our $patched;
|
|
my $pattern = qr{
|
|
\n([ \t]*)try[ \t]*\{\n
|
|
([ \t]*)\$discovery[ \t]*=[ \t]*\$this->discoveryService->obtainDiscovery\(\$provider\);
|
|
}x;
|
|
if ($_ =~ $pattern) {
|
|
my ($indent, $inner) = ($1, $2);
|
|
my $insert = "\n${indent}\$inviteToken = trim((string)\$this->request->getParam(\"invite_token\", \"\"));\n"
|
|
. "${indent}if (\$inviteToken !== \"\" && preg_match(\"/^[A-Za-z0-9_-]{16,256}$/\", \$inviteToken) === 1) {\n"
|
|
. "${inner}\$data[\"invite_token\"] = \$inviteToken;\n"
|
|
. "${indent}}\n"
|
|
. "${indent}\$inviteEmail = trim((string)\$this->request->getParam(\"invite_email\", \"\"));\n"
|
|
. "${indent}if (\$inviteEmail !== \"\" && filter_var(\$inviteEmail, FILTER_VALIDATE_EMAIL) !== false) {\n"
|
|
. "${inner}\$data[\"invite_email\"] = \$inviteEmail;\n"
|
|
. "${indent}}\n";
|
|
my $replacement = $insert . "\n${indent}try {\n${inner}\$discovery = \$this->discoveryService->obtainDiscovery(\$provider);";
|
|
$_ =~ s/$pattern/$replacement/;
|
|
$patched = 1;
|
|
}
|
|
END { exit($patched ? 0 : 3); }
|
|
' "${login_controller}" > "${tmp_file}"; then
|
|
echo "Unable to patch user_oidc invite bridge; LoginController layout changed." >&2
|
|
exit 1
|
|
fi
|
|
|
|
backup_path="${login_controller}.nuqloud-pre-invite-patch.$(date +%Y%m%d%H%M%S)"
|
|
cp "${login_controller}" "${backup_path}"
|
|
cat "${tmp_file}" > "${login_controller}"
|
|
echo "Applied user_oidc invite bridge: ${login_controller}"
|
|
echo "Backup written: ${backup_path}"
|