From 69ab3e4304ca858b04fefcba19f38f62ef89ba05 Mon Sep 17 00:00:00 2001 From: Jamie Zaharopoulos Date: Tue, 22 Apr 2025 14:29:31 -0400 Subject: [PATCH 1/2] Enable support for dynamic configuration --- .editorconfig | 16 ++ .gitignore | 1 - .vscode/extensions.json | 5 + .vscode/settings.json | 9 + Dockerfile | 12 +- docker-compose.yml | 17 ++ run_tests.sh | 0 scripts/channels/britishairways.sh | 34 ++++ scripts/channels/farelogix.sh | 114 ++++++++++++ scripts/channels/travelfusion.sh | 37 ++++ scripts/common.sh | 72 ++++++++ scripts/setup_nginx.sh | 151 ++++++++++++++++ start.sh | 162 ------------------ templates/base.conf.template | 36 ++++ .../channels/britishairways.conf.template | 19 ++ templates/channels/farelogix.conf.template | 40 +++++ templates/channels/travelfusion.conf.template | 47 +++++ tests/test_proxy.py | 8 +- 18 files changed, 612 insertions(+), 168 deletions(-) create mode 100644 .editorconfig create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json mode change 100644 => 100755 run_tests.sh create mode 100644 scripts/channels/britishairways.sh create mode 100644 scripts/channels/farelogix.sh create mode 100644 scripts/channels/travelfusion.sh create mode 100644 scripts/common.sh create mode 100644 scripts/setup_nginx.sh delete mode 100644 start.sh create mode 100644 templates/base.conf.template create mode 100644 templates/channels/britishairways.conf.template create mode 100644 templates/channels/farelogix.conf.template create mode 100644 templates/channels/travelfusion.conf.template diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..63678e8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true + +# Nginx configuration files +[*.{conf,conf.template}] +indent_style = space +indent_size = 4 diff --git a/.gitignore b/.gitignore index e0416e7..c25186a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,7 +38,6 @@ docker-compose.override.yml # IDE .idea/ -.vscode/ *.swp *.swo .DS_Store diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..de8ee23 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ahmadalli.vscode-nginx-conf" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ac5566c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "*.conf.template": "nginx", + "*.conf": "nginx" + }, + "editor.detectIndentation": true, + "editor.insertSpaces": true, + "editor.tabSize": 4 +} diff --git a/Dockerfile b/Dockerfile index 8a27733..e80090a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,12 +5,16 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ dos2unix \ && rm -rf /var/lib/apt/lists/* -COPY nginx.conf /etc/nginx/nginx.conf.template +RUN mkdir -p /etc/nginx/includes /etc/nginx/templates -WORKDIR / -COPY start.sh / +COPY templates /etc/nginx/templates +COPY scripts /usr/local/bin/scripts COPY travelfusion.lua / +RUN chmod -R +x /usr/local/bin/scripts + +WORKDIR / + STOPSIGNAL SIGTERM -CMD ["bash", "-x", "/start.sh"] +CMD ["/usr/local/bin/scripts/setup_nginx.sh", "start"] diff --git a/docker-compose.yml b/docker-compose.yml index 76576d3..5be4a54 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,8 @@ services: - WP_CHANNELS_TRAVELFUSION_LOGIN_ID=test-login - WP_CHANNELS_TRAVELFUSION_XML_LOGIN_ID=test-login - 'WP_CHANNELS_TRAVELFUSION_SUPPLIER_PARAMETERS={"test-iata": {"test-supplier": {"test-login-key": "test-login-value"}}}' + # Farelogix legacy config for backwards compatibility + # Comment out the following lines if you want to use the new config - WP_CHANNELS_FARELOGIX_AA_HOST=mockserver - WP_CHANNELS_FARELOGIX_AA_PROXY_PASS=http://mockserver:80 - WP_CHANNELS_FARELOGIX_AA_API_KEY=test-aa-key @@ -24,6 +26,18 @@ services: - WP_CHANNELS_FARELOGIX_AA_PASSWORD=test-pass - WP_CHANNELS_FARELOGIX_AA_AGENT_USER=test-agent-user - WP_CHANNELS_FARELOGIX_AA_AGENT_PASSWORD=test-agent-pass + # Farelogix new config with multiple account IDs + # Comment out the following lines if you want to use the old config + # Also, make sure to set the WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS environment variable on the test container + # - WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS=true + # - WP_CHANNELS_FARELOGIX_AA_CAD_HOST=mockserver + # - WP_CHANNELS_FARELOGIX_AA_CAD_PROXY_PASS=http://mockserver:80 + # - WP_CHANNELS_FARELOGIX_AA_CAD_API_KEY=test-aa-key + # - WP_CHANNELS_FARELOGIX_AA_CAD_AGENT=test-agent + # - WP_CHANNELS_FARELOGIX_AA_CAD_USERNAME=test-user + # - WP_CHANNELS_FARELOGIX_AA_CAD_PASSWORD=test-pass + # - WP_CHANNELS_FARELOGIX_AA_CAD_AGENT_USER=test-agent-user + # - WP_CHANNELS_FARELOGIX_AA_CAD_AGENT_PASSWORD=test-agent-pass depends_on: mockserver: condition: service_healthy @@ -62,6 +76,9 @@ services: environment: - PROXY_HOST=proxy - PROXY_PORT=8080 + # Make sure this matches the WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS environment variable on the proxy container + # Uncomment this line if you want to use the new config + # - WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS=true depends_on: proxy: condition: service_healthy diff --git a/run_tests.sh b/run_tests.sh old mode 100644 new mode 100755 diff --git a/scripts/channels/britishairways.sh b/scripts/channels/britishairways.sh new file mode 100644 index 0000000..a82dce5 --- /dev/null +++ b/scripts/channels/britishairways.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# shellcheck source=/dev/null +. "$(dirname "$0")/common.sh" + +setup_britishairways() { + debug_log "Setting up British Airways configuration" + + if check_any_vars "WP_CHANNELS_BA_API_KEY"; then + info_log "Found British Airways API key, proceeding with setup" + + if ! validate_env_vars "WP_CHANNELS_BA_API_KEY"; then + error_log "Failed to validate required environment variables" + fi + + export WP_CHANNELS_BA_HOST=${WP_CHANNELS_BA_HOST:-api.ba.com} + export WP_CHANNELS_BA_PROXY_PASS=${WP_CHANNELS_BA_PROXY_PASS:-${WP_SERVER_PROXY_PASS:-"https://${WP_CHANNELS_BA_HOST}"}} + + debug_log "Using host: ${WP_CHANNELS_BA_HOST}" + debug_log "Using proxy pass: ${WP_CHANNELS_BA_PROXY_PASS}" + + debug_log "Generating nginx configuration file" + # shellcheck disable=SC2016 + generate_nginx_config \ + "/etc/nginx/templates/channels/britishairways.conf.template" \ + "/etc/nginx/includes/britishairways.conf" \ + '${WP_CHANNELS_BA_PROXY_PASS} ${WP_CHANNELS_BA_HOST} ${WP_CHANNELS_BA_API_KEY}' + debug_log "Nginx configuration generated successfully" + else + info_log "No British Airways API key found, skipping setup" + fi +} + +setup_britishairways diff --git a/scripts/channels/farelogix.sh b/scripts/channels/farelogix.sh new file mode 100644 index 0000000..88677f6 --- /dev/null +++ b/scripts/channels/farelogix.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +# shellcheck source=/dev/null +. "$(dirname "$0")/common.sh" + +generate_farelogix_config() { + local airline_code=$1 + local account_id=$2 + local prefix="WP_CHANNELS_FARELOGIX" + + info_log "Generating Farelogix config for airline_code: $airline_code, account_id: ${account_id:-none}" + + if [ -n "$account_id" ]; then + prefix="${prefix}_${airline_code}_${account_id}" + else + prefix="${prefix}_${airline_code}" + fi + + debug_log "Using environment variable prefix: $prefix" + + local host_var="${prefix}_HOST" + local proxy_pass_var="${prefix}_PROXY_PASS" + local host="${!host_var:-${airline_code,,}.farelogix.com}" + local proxy_pass="${!proxy_pass_var:-https://${host}}" + + debug_log "Host: $host" + debug_log "Proxy pass: $proxy_pass" + + local auth_vars=( + "${prefix}_API_KEY" + "${prefix}_AGENT" + "${prefix}_USERNAME" + "${prefix}_PASSWORD" + "${prefix}_AGENT_USER" + "${prefix}_AGENT_PASSWORD" + ) + + if check_any_vars "${auth_vars[@]}"; then + debug_log "Found authentication variables for $prefix" + if ! validate_env_vars "${auth_vars[@]}"; then + error_log "Failed to validate environment variables for $prefix" + fi + + ( + export HOST="$host" + export PROXY_PASS="$proxy_pass" + local api_key_var="${prefix}_API_KEY" + local agent_var="${prefix}_AGENT" + local username_var="${prefix}_USERNAME" + local password_var="${prefix}_PASSWORD" + local agent_user_var="${prefix}_AGENT_USER" + local agent_password_var="${prefix}_AGENT_PASSWORD" + + export API_KEY="${!api_key_var}" + export AGENT="${!agent_var}" + export USERNAME="${!username_var}" + export PASSWORD="${!password_var}" + export AGENT_USER="${!agent_user_var}" + export AGENT_PASSWORD="${!agent_password_var}" + + local airline_code_lower + local account_id_lower + airline_code_lower="$(echo "$airline_code" | tr '[:upper:]' '[:lower:]')" + account_id_lower="$(echo "$account_id" | tr '[:upper:]' '[:lower:]')" + + if [ -n "$account_id" ]; then + export LOCATION_PATH="${airline_code_lower}/${account_id_lower}" + else + export LOCATION_PATH="${airline_code_lower}" + fi + + local output_file="/etc/nginx/includes/farelogix_${airline_code_lower}" + [ -n "$account_id" ] && output_file="${output_file}_${account_id_lower}" + output_file="${output_file}.conf" + + debug_log "Generating config file: $output_file" + debug_log "Location path: $LOCATION_PATH" + + # shellcheck disable=SC2016 + generate_nginx_config \ + "/etc/nginx/templates/channels/farelogix.conf.template" \ + "$output_file" \ + '${LOCATION_PATH} ${HOST} ${PROXY_PASS} ${API_KEY} ${AGENT} ${USERNAME} ${PASSWORD} ${AGENT_USER} ${AGENT_PASSWORD}' + + debug_log "Config file generated successfully: $output_file" + ) + else + debug_log "No authentication variables found for $prefix" + fi +} + +debug_log "WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS=${WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS:-false}" + +if [ "${WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS:-false}" = "false" ]; then + info_log "Running in legacy mode (no account IDs)" + mapfile -t airline_codes < <(env | grep '^WP_CHANNELS_FARELOGIX_' | grep -v '_USE_ACCOUNT_IDS' | cut -d'_' -f4 | sort -u) + for airline_code in "${airline_codes[@]}"; do + debug_log "Found airline code: $airline_code" + if ! generate_farelogix_config "$airline_code"; then + error_log "Failed to generate config for airline code: $airline_code" + fi + done +else + info_log "Running in new mode with account IDs" + mapfile -t combinations < <(env | grep '^WP_CHANNELS_FARELOGIX_' | grep -v '_USE_ACCOUNT_IDS' | grep '_[^_]*_[^_]*_' | cut -d'_' -f4,5 | sort -u) + for line in "${combinations[@]}"; do + airline_code=$(echo "$line" | cut -d'_' -f1) + account_id=$(echo "$line" | cut -d'_' -f2) + debug_log "Found airline code: $airline_code with account ID: $account_id" + if ! generate_farelogix_config "$airline_code" "$account_id"; then + error_log "Failed to generate config for airline code: $airline_code with account ID: $account_id" + fi + done +fi diff --git a/scripts/channels/travelfusion.sh b/scripts/channels/travelfusion.sh new file mode 100644 index 0000000..77b7308 --- /dev/null +++ b/scripts/channels/travelfusion.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# shellcheck source=/dev/null +. "$(dirname "$0")/common.sh" + +setup_travelfusion() { + debug_log "Setting up Travelfusion configuration" + + if [ -n "${WP_CHANNELS_TRAVELFUSION_LOGIN_ID}" ] || [ -n "${WP_CHANNELS_TRAVELFUSION_XML_LOGIN_ID}" ]; then + info_log "Found Travelfusion credentials, proceeding with setup" + + if ! validate_env_vars "WP_CHANNELS_TRAVELFUSION_LOGIN_ID" "WP_CHANNELS_TRAVELFUSION_XML_LOGIN_ID" "WP_CHANNELS_TRAVELFUSION_SUPPLIER_PARAMETERS"; then + error_log "Failed to validate required environment variables" + fi + + export WP_CHANNELS_TRAVELFUSION_HOST=${WP_CHANNELS_TRAVELFUSION_HOST:-api.travelfusion.com} + export WP_CHANNELS_TRAVELFUSION_PROXY_PASS=${WP_CHANNELS_TRAVELFUSION_PROXY_PASS:-${WP_SERVER_PROXY_PASS:-"https://${WP_CHANNELS_TRAVELFUSION_HOST}"}} + + debug_log "Using host: ${WP_CHANNELS_TRAVELFUSION_HOST}" + debug_log "Using proxy pass: ${WP_CHANNELS_TRAVELFUSION_PROXY_PASS}" + + debug_log "Writing supplier parameters to tf_config.json" + echo "${WP_CHANNELS_TRAVELFUSION_SUPPLIER_PARAMETERS:-}" > tf_config.json + + debug_log "Generating nginx configuration file" + # shellcheck disable=SC2016 + generate_nginx_config \ + "/etc/nginx/templates/channels/travelfusion.conf.template" \ + "/etc/nginx/includes/travelfusion.conf" \ + '${WP_CHANNELS_TRAVELFUSION_LOGIN_ID} ${WP_CHANNELS_TRAVELFUSION_XML_LOGIN_ID} ${WP_CHANNELS_TRAVELFUSION_HOST} ${WP_CHANNELS_TRAVELFUSION_PROXY_PASS}' + debug_log "Nginx configuration generated successfully" + else + info_log "No Travelfusion credentials found, skipping setup" + fi +} + +setup_travelfusion diff --git a/scripts/common.sh b/scripts/common.sh new file mode 100644 index 0000000..41e996e --- /dev/null +++ b/scripts/common.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +export WP_SERVER_DEBUG=${WP_SERVER_DEBUG:-false} + +generate_nginx_config() { + local template="$1" + local output="$2" + local vars="$3" + + envsubst "$vars" < "$template" > "$output" +} + +validate_env_vars() { + local vars=("$@") + local missing=() + + debug_log "Validating required environment variables: ${vars[*]}" + + for var in "${vars[@]}"; do + debug_log "Checking variable '$var' with value '${!var}'" + if [ -z "${!var}" ]; then + missing+=("$var") + debug_log "Variable '$var' is missing or empty" + else + debug_log "Variable '$var' is valid" + fi + done + + if [ ${#missing[@]} -gt 0 ]; then + warning_log "Validation failed - missing variables: ${missing[*]}" + return 1 + fi + + debug_log "All required variables are valid" + return 0 +} + +check_any_vars() { + local vars=("$@") + + debug_log "Checking if any of these variables are set: ${vars[*]}" + + for var in "${vars[@]}"; do + debug_log "Checking variable '$var' with value '${!var}'" + if [ -n "${!var}" ]; then + debug_log "Found set variable '$var'" + return 0 + fi + done + + debug_log "None of the variables are set" + return 1 +} + +debug_log() { + if [ "${WP_SERVER_DEBUG}" = true ]; then + echo "[DEBUG] $1" + fi +} + +info_log() { + echo "[INFO] $1" +} + +warning_log() { + echo "[WARNING] $1" +} + +error_log() { + echo "[ERROR] $1" + exit 1 +} diff --git a/scripts/setup_nginx.sh b/scripts/setup_nginx.sh new file mode 100644 index 0000000..3c15b4f --- /dev/null +++ b/scripts/setup_nginx.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +set -e + +# shellcheck source=/dev/null +source "$(dirname "$0")/common.sh" + +setup_tls_config() { + debug_log "Setting up TLS configuration" + + if [ "${WP_SERVER_TLS_ENABLED}" = true ]; then + debug_log "TLS is enabled, checking certificate configuration" + + if [ -z "$WP_SERVER_TLS_CERTIFICATE" ]; then + error_log "TLS enabled but no certificate provided. Please set WP_SERVER_TLS_CERTIFICATE." + fi + + if [ -z "$WP_SERVER_TLS_CERTIFICATE_KEY" ]; then + error_log "TLS enabled but no certificate key provided. Please set WP_SERVER_TLS_CERTIFICATE_KEY." + fi + + debug_log "Writing TLS certificate and key files" + base64 -d <<< "$WP_SERVER_TLS_CERTIFICATE" > /etc/nginx/cert.crt + base64 -d <<< "$WP_SERVER_TLS_CERTIFICATE_KEY" > /etc/nginx/cert.key + dos2unix /etc/nginx/cert.crt /etc/nginx/cert.key + + WP_SERVER_TLS_PORT=${WP_SERVER_TLS_PORT:-18443} + WP_SERVER_TLS_SERVER_NAME=${WP_SERVER_TLS_SERVER_NAME:-} + + debug_log "Using TLS port: ${WP_SERVER_TLS_PORT}" + debug_log "Using TLS server name: ${WP_SERVER_TLS_SERVER_NAME:-}" + + ssl_directives="listen ${WP_SERVER_TLS_PORT} ssl;" + ssl_directives="${ssl_directives} server_name ${WP_SERVER_TLS_SERVER_NAME};" + ssl_directives="${ssl_directives} ssl_certificate /etc/nginx/cert.crt;" + ssl_directives="${ssl_directives} ssl_certificate_key /etc/nginx/cert.key;" + ssl_directives="${ssl_directives} ssl_protocols TLSv1.2 TLSv1.3;" + + export WP_SERVER_TLS_DIRECTIVES="${ssl_directives}" + info_log "TLS configuration completed successfully" + else + info_log "TLS is disabled, skipping TLS configuration" + fi +} + +setup_basic_auth() { + debug_log "Setting up basic authentication" + + if [ -n "$WP_SERVER_HTTP_USER" ] && [ -n "$WP_SERVER_HTTP_PASS" ]; then + debug_log "Basic auth credentials provided, creating .htpasswd file" + htpasswd -c -b /etc/nginx/.htpasswd "${WP_SERVER_HTTP_USER}" "${WP_SERVER_HTTP_PASS}" + chmod 644 /etc/nginx/.htpasswd + export WP_SERVER_BASIC_AUTH="Restricted" + info_log "Basic authentication enabled" + else + info_log "No basic auth credentials provided, disabling basic auth" + export WP_SERVER_BASIC_AUTH="off" + fi +} + +setup_additional_includes() { + debug_log "Setting up additional include files" + + WP_SERVER_PATH_INCLUDES=${WP_SERVER_PATH_INCLUDES:-} + if [ -n "$WP_SERVER_PATH_INCLUDES" ]; then + info_log "Processing additional include files" + for include_file in $(echo "$WP_SERVER_PATH_INCLUDES" | tr "," "\n"); do + if [ -f "$include_file" ]; then + filename=$(basename "$include_file") + target_path="/etc/nginx/includes/${filename}" + + if [ ! -f "$target_path" ]; then + debug_log "Creating symlink for $include_file to $target_path" + ln -s "$include_file" "$target_path" + else + debug_log "File $filename already exists in includes directory" + fi + else + warning_log "Warning: Include file $include_file not found" + fi + done + else + info_log "No additional include files specified" + fi +} + +process_channel_configs() { + debug_log "Processing channel configurations" + for script in "$(dirname "$0")"/channels/*.sh; do + if [ -f "$script" ]; then + debug_log "Processing channel script: $script" + # shellcheck source=/dev/null + source "$script" + fi + done + debug_log "Finished processing channel configurations" +} + +show_debug_info() { + debug_log "Displaying detailed nginx configuration" + echo "=== Main Nginx Configuration ===" + cat /etc/nginx/nginx.conf + echo + echo "=== Include Files ===" + for include in /etc/nginx/includes/*.conf; do + if [ -f "$include" ]; then + echo "--- $include ---" + cat "$include" + echo + fi + done + debug_log "Finished displaying nginx configuration" +} + +setup_nginx() { + info_log "Starting nginx setup" + + export WP_SERVER_PORT=${WP_SERVER_PORT:-8080} + export WP_SERVER_RESOLVER=${WP_SERVER_RESOLVER:-'8.8.8.8'} + export DOLLAR='$' + + debug_log "Using server port: ${WP_SERVER_PORT}" + debug_log "Using DNS resolver: ${WP_SERVER_RESOLVER}" + + setup_tls_config + setup_basic_auth + setup_additional_includes + process_channel_configs + + debug_log "Generating main nginx configuration file" + envsubst < /etc/nginx/templates/base.conf.template > /etc/nginx/nginx.conf + + debug_log "Nginx configuration generated" + + if [ "${WP_SERVER_DEBUG}" = true ]; then + debug_log "Debug mode enabled, showing detailed configuration" + printf " in debug mode\n" + show_debug_info + else + printf "\n" + fi + + info_log "Nginx setup completed" +} + +setup_nginx + +if [ "$1" == "start" ]; then + info_log "Starting nginx server" + exec nginx -c /etc/nginx/nginx.conf +fi diff --git a/start.sh b/start.sh deleted file mode 100644 index e9cb6b3..0000000 --- a/start.sh +++ /dev/null @@ -1,162 +0,0 @@ -#!/bin/bash - -set -e - -WP_SERVER_DEBUG=${WP_SERVER_DEBUG:-false} - -if [ "${WP_SERVER_DEBUG}" = true ]; then - set -x -fi - -# Replace environment variables in the nginx configuration, and start nginx -# Setup default values for environment variables -export WP_SERVER_PORT=${WP_SERVER_PORT:-8080} -export WP_SERVER_RESOLVER=${WP_SERVER_RESOLVER:-'8.8.8.8'} - -# File includes, generate `include` directives for nginx configuration for every file in WP_SERVER_PATH_INCLUDES -# The variables are comma-separated, so we need to split them into a string "include file1; include file2; ..." -WP_SERVER_PATH_INCLUDES=${WP_SERVER_PATH_INCLUDES:-} -if [ -n "$WP_SERVER_PATH_INCLUDES" ]; then - include_directives="" - for include_file in $(echo "$WP_SERVER_PATH_INCLUDES" | tr "," "\n"); do - include_directives="${include_directives}include ${include_file}; " - done - - export WP_SERVER_FILE_INCLUDES="${include_directives}" -fi - -export WP_SERVER_PROXY_PASS=${WP_SERVER_PROXY_PASS:-} - -# Create htpasswd file -export WP_SERVER_HTTP_USER=${WP_SERVER_HTTP_USER:-} -export WP_SERVER_HTTP_PASS=${WP_SERVER_HTTP_PASS:-} - -if [ -n "$WP_SERVER_HTTP_USER" ] && [ -n "$WP_SERVER_HTTP_PASS" ]; then - htpasswd -c -b /etc/nginx/.htpasswd "${WP_SERVER_HTTP_USER}" "${WP_SERVER_HTTP_PASS}" - chmod 644 /etc/nginx/.htpasswd - - export WP_SERVER_BASIC_AUTH="Restricted" -else - export WP_SERVER_BASIC_AUTH="off" -fi - -# TLS -CERTIFICATE_CONTENT=${WP_SERVER_TLS_CERTIFICATE:-} -if [ -n "$CERTIFICATE_CONTENT" ]; then - if [ "${WP_SERVER_TLS_ENABLED}" = false ]; then - echo "TLS certificate provided but TLS is not enabled. Please set WP_SERVER_TLS_ENABLED=true to enable TLS." - exit 1 - fi - - base64 -d <<< "$CERTIFICATE_CONTENT" > /etc/nginx/cert.crt - dos2unix /etc/nginx/cert.crt - echo "Wrote certificate to /etc/nginx/cert.crt" -fi - -CERTIFICATE_KEY_CONTENT=${WP_SERVER_TLS_CERTIFICATE_KEY:-} -if [ -n "$CERTIFICATE_KEY_CONTENT" ]; then - if [ "${WP_SERVER_TLS_ENABLED}" = false ]; then - echo "TLS certificate key provided but TLS is not enabled. Please set WP_SERVER_TLS_ENABLED=true to enable TLS." - exit 1 - fi - - base64 -d <<< "$CERTIFICATE_KEY_CONTENT" > /etc/nginx/cert.key - dos2unix /etc/nginx/cert.key - echo "Wrote certificate key to /etc/nginx/cert.key" -fi - -WP_SERVER_TLS_ENABLED=${WP_SERVER_TLS_ENABLED:-false} - -# TLS certificates, write them to files if provided. If TLS is enabled, the certificates are required and must be provided (exit if not) -if [ "${WP_SERVER_TLS_ENABLED}" = true ]; then - if [ -z "$WP_SERVER_TLS_CERTIFICATE" ]; then - echo "TLS enabled but no certificate provided. Please set WP_SERVER_TLS_CERTIFICATE to the content of the certificate file." - exit 1 - fi - - if [ -z "$WP_SERVER_TLS_CERTIFICATE_KEY" ]; then - echo "TLS enabled but no certificate key provided. Please set WP_SERVER_TLS_CERTIFICATE_KEY to the content of the certificate key file." - exit 1 - fi - - WP_SERVER_TLS_PORT=${WP_SERVER_TLS_PORT:-18443} - WP_SERVER_TLS_SERVER_NAME=${WP_SERVER_TLS_SERVER_NAME:-} - - ssl_directives="listen ${WP_SERVER_TLS_PORT} ssl;" - ssl_directives="${ssl_directives} server_name ${WP_SERVER_TLS_SERVER_NAME};" - ssl_directives="${ssl_directives} ssl_certificate /etc/nginx/cert.crt;" - ssl_directives="${ssl_directives} ssl_certificate_key /etc/nginx/cert.key;" - ssl_directives="${ssl_directives} ssl_protocols TLSv1.2 TLSv1.3;" - - export WP_SERVER_TLS_DIRECTIVES="${ssl_directives}" -fi - -# --------- - -# TravelFusion -export WP_CHANNELS_TRAVELFUSION_LOGIN_ID=${WP_CHANNELS_TRAVELFUSION_LOGIN_ID:-} -export WP_CHANNELS_TRAVELFUSION_XML_LOGIN_ID=${WP_CHANNELS_TRAVELFUSION_XML_LOGIN_ID:-} -export WP_CHANNELS_TRAVELFUSION_HOST=${WP_CHANNELS_TRAVELFUSION_HOST:-api.travelfusion.com} -export WP_CHANNELS_TRAVELFUSION_PROXY_PASS=${WP_CHANNELS_TRAVELFUSION_PROXY_PASS:-${WP_SERVER_PROXY_PASS:-"https://${WP_CHANNELS_TRAVELFUSION_HOST}"}} - -# If travelfusion is enabled (WP_CHANNELS_TRAVELFUSION_LOGIN_ID is set), the supplier parameters are required - exit if not -if [ -n "${WP_CHANNELS_TRAVELFUSION_LOGIN_ID}" ]; then - if [ -z "${WP_CHANNELS_TRAVELFUSION_SUPPLIER_PARAMETERS}" ]; then - echo "TravelFusion enabled but no supplier parameters provided. Please set WP_CHANNELS_TRAVELFUSION_SUPPLIER_PARAMETERS." - exit 1 - fi -fi - -echo "${WP_CHANNELS_TRAVELFUSION_SUPPLIER_PARAMETERS:-}" > tf_config.json - -# British Airways NDC -export WP_CHANNELS_BA_API_KEY=${WP_CHANNELS_BA_API_KEY:-} -export WP_CHANNELS_BA_MERCHANT_ID=${WP_CHANNELS_BA_MERCHANT_ID:-} -export WP_CHANNELS_BA_HOST=${WP_CHANNELS_BA_HOST:-api.ba.com} -export WP_CHANNELS_BA_PROXY_PASS=${WP_CHANNELS_BA_PROXY_PASS:-${WP_SERVER_PROXY_PASS:-"https://${WP_CHANNELS_BA_HOST}"}} - -# Farelogix AA -export WP_CHANNELS_FARELOGIX_AA_HOST=${WP_CHANNELS_FARELOGIX_AA_HOST:-aa.farelogix.com} -export WP_CHANNELS_FARELOGIX_AA_PROXY_PASS=${WP_CHANNELS_FARELOGIX_AA_PROXY_PASS:-${WP_SERVER_PROXY_PASS:-"https://${WP_CHANNELS_FARELOGIX_AA_HOST}"}} -export WP_CHANNELS_FARELOGIX_AA_API_KEY=${WP_CHANNELS_FARELOGIX_AA_API_KEY:-} -export WP_CHANNELS_FARELOGIX_AA_AGENT=${WP_CHANNELS_FARELOGIX_AA_AGENT:-} -export WP_CHANNELS_FARELOGIX_AA_USERNAME=${WP_CHANNELS_FARELOGIX_AA_USERNAME:-} -export WP_CHANNELS_FARELOGIX_AA_PASSWORD=${WP_CHANNELS_FARELOGIX_AA_PASSWORD:-} -export WP_CHANNELS_FARELOGIX_AA_AGENT_USER=${WP_CHANNELS_FARELOGIX_AA_AGENT_USER:-} -export WP_CHANNELS_FARELOGIX_AA_AGENT_PASSWORD=${WP_CHANNELS_FARELOGIX_AA_AGENT_PASSWORD:-} - -# Farelogix LH -export WP_CHANNELS_FARELOGIX_LH_HOST=${WP_CHANNELS_FARELOGIX_LH_HOST:-lhg.farelogix.com} -export WP_CHANNELS_FARELOGIX_LH_PROXY_PASS=${WP_CHANNELS_FARELOGIX_LH_PROXY_PASS:-${WP_SERVER_PROXY_PASS:-"https://${WP_CHANNELS_FARELOGIX_LH_HOST}"}} -export WP_CHANNELS_FARELOGIX_LH_API_KEY=${WP_CHANNELS_FARELOGIX_LH_API_KEY:-} -export WP_CHANNELS_FARELOGIX_LH_AGENT=${WP_CHANNELS_FARELOGIX_LH_AGENT:-} -export WP_CHANNELS_FARELOGIX_LH_USERNAME=${WP_CHANNELS_FARELOGIX_LH_USERNAME:-} -export WP_CHANNELS_FARELOGIX_LH_PASSWORD=${WP_CHANNELS_FARELOGIX_LH_PASSWORD:-} -export WP_CHANNELS_FARELOGIX_LH_AGENT_USER=${WP_CHANNELS_FARELOGIX_LH_AGENT_USER:-} -export WP_CHANNELS_FARELOGIX_LH_AGENT_PASSWORD=${WP_CHANNELS_FARELOGIX_LH_AGENT_PASSWORD:-} - -# Farelogix UA -export WP_CHANNELS_FARELOGIX_UA_HOST=${WP_CHANNELS_FARELOGIX_UA_HOST:-ua.farelogix.com} -export WP_CHANNELS_FARELOGIX_UA_PROXY_PASS=${WP_CHANNELS_FARELOGIX_UA_PROXY_PASS:-${WP_SERVER_PROXY_PASS:-"https://${WP_CHANNELS_FARELOGIX_UA_HOST}"}} -export WP_CHANNELS_FARELOGIX_UA_API_KEY=${WP_CHANNELS_FARELOGIX_UA_API_KEY:-} -export WP_CHANNELS_FARELOGIX_UA_AGENT=${WP_CHANNELS_FARELOGIX_UA_AGENT:-} -export WP_CHANNELS_FARELOGIX_UA_USERNAME=${WP_CHANNELS_FARELOGIX_UA_USERNAME:-} -export WP_CHANNELS_FARELOGIX_UA_PASSWORD=${WP_CHANNELS_FARELOGIX_UA_PASSWORD:-} -export WP_CHANNELS_FARELOGIX_UA_AGENT_USER=${WP_CHANNELS_FARELOGIX_UA_AGENT_USER:-} -export WP_CHANNELS_FARELOGIX_UA_AGENT_PASSWORD=${WP_CHANNELS_FARELOGIX_UA_AGENT_PASSWORD:-} - -# --------- - -# Replace environment variables in the nginx configuration -export DOLLAR='$' # Escape $ for envsubst -envsubst < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf - -printf "Starting nginx" - -if [ "${WP_SERVER_DEBUG}" = true ]; then - printf " in debug mode\n" - cat /etc/nginx/nginx.conf -fi - -# Start nginx -exec nginx -c /etc/nginx/nginx.conf diff --git a/templates/base.conf.template b/templates/base.conf.template new file mode 100644 index 0000000..23b8662 --- /dev/null +++ b/templates/base.conf.template @@ -0,0 +1,36 @@ +events {} + +daemon off; + +http { + server { + listen $WP_SERVER_PORT; + + $WP_SERVER_TLS_DIRECTIVES + + keepalive_timeout 70; + + gzip on; + + auth_basic "$WP_SERVER_BASIC_AUTH"; + auth_basic_user_file /etc/nginx/.htpasswd; + + location = / { + return 200 'Welcome to Wenrix Proxy\n'; + } + + resolver $WP_SERVER_RESOLVER; + + # Include all channel configurations + include /etc/nginx/includes/*.conf; + + location /metrics { + stub_status; + } + + error_page 404 /404.html; + location = /404.html { + internal; + } + } +} diff --git a/templates/channels/britishairways.conf.template b/templates/channels/britishairways.conf.template new file mode 100644 index 0000000..a48c73b --- /dev/null +++ b/templates/channels/britishairways.conf.template @@ -0,0 +1,19 @@ +location ~ ^/channel/britishairways/(.*) { + proxy_pass $WP_CHANNELS_BA_PROXY_PASS/$1; + proxy_set_header Host $WP_CHANNELS_BA_HOST; + proxy_ssl_server_name on; + proxy_connect_timeout 30; + proxy_send_timeout 120; + proxy_read_timeout 120; + send_timeout 120; + + # Drop HTTP headers that are not needed (Wenrix headers) + proxy_set_header x-wenrix-operation ""; + proxy_set_header x-wenrix-trace-id ""; + proxy_set_header authorization ""; + proxy_set_header x-real-ip ""; + proxy_set_header x-forwarded-for ""; + + # Add the Authorization header + proxy_set_header Client-Key "$WP_CHANNELS_BA_API_KEY"; +} diff --git a/templates/channels/farelogix.conf.template b/templates/channels/farelogix.conf.template new file mode 100644 index 0000000..1d676d6 --- /dev/null +++ b/templates/channels/farelogix.conf.template @@ -0,0 +1,40 @@ +location ~ ^/channel/farelogix-${LOCATION_PATH}/(.*) { + proxy_pass ${PROXY_PASS}/$1; + proxy_set_header Host ${HOST}; + proxy_ssl_server_name on; + proxy_connect_timeout 30; + proxy_send_timeout 120; + proxy_read_timeout 120; + send_timeout 120; + + # Drop HTTP headers that are not needed (Wenrix headers) + proxy_set_header x-wenrix-operation ""; + proxy_set_header x-wenrix-trace-id ""; + proxy_set_header authorization ""; + proxy_set_header x-real-ip ""; + proxy_set_header x-forwarded-for ""; + + # Add API key header + proxy_set_header Ocp-Apim-Subscription-Key "${API_KEY}"; + + lua_need_request_body on; + + access_by_lua_block { + local agent = "${AGENT}" + local username = "${USERNAME}" + local password = "${PASSWORD}" + local agent_user = "${AGENT_USER}" + local agent_password = "${AGENT_PASSWORD}" + + ngx.req.read_body() + local body = ngx.req.get_body_data() + if body then + body = ngx.re.gsub(body, "#FLX_USERNAME#", username) + body = ngx.re.gsub(body, "#FLX_PASSWORD#", password) + body = ngx.re.gsub(body, "#FLX_AGENT#", agent) + body = ngx.re.gsub(body, "#FLX_AGENT_USER#", agent_user) + body = ngx.re.gsub(body, "#FLX_AGENT_PASSWORD#", agent_password) + end + ngx.req.set_body_data(body) + } +} diff --git a/templates/channels/travelfusion.conf.template b/templates/channels/travelfusion.conf.template new file mode 100644 index 0000000..653201c --- /dev/null +++ b/templates/channels/travelfusion.conf.template @@ -0,0 +1,47 @@ +location ~ ^/channel/travelfusion(?:/(.*))?$ { + # If $1 is empty, this effectively proxies to $WP_CHANNELS_TRAVELFUSION_PROXY_PASS/ + proxy_pass $WP_CHANNELS_TRAVELFUSION_PROXY_PASS/$1; + + proxy_set_header Host $WP_CHANNELS_TRAVELFUSION_HOST; + proxy_set_header Content-Type text/xml; + proxy_ssl_server_name on; + proxy_connect_timeout 30; + proxy_send_timeout 120; + proxy_read_timeout 120; + send_timeout 120; + + # Drop HTTP headers that are not needed (Wenrix headers) + proxy_set_header x-wenrix-operation ""; + proxy_set_header x-wenrix-trace-id ""; + proxy_set_header x-wenrix-iata-number ""; + proxy_set_header x-wenrix-supplier ""; + proxy_set_header authorization ""; + proxy_set_header x-real-ip ""; + proxy_set_header x-forwarded-for ""; + + lua_need_request_body on; + + access_by_lua_block { + require "travelfusion" + + local login_id = "$WP_CHANNELS_TRAVELFUSION_LOGIN_ID" + local xml_login_id = "$WP_CHANNELS_TRAVELFUSION_XML_LOGIN_ID" + ngx.req.read_body() + local body = ngx.req.get_body_data() + + local config = load_config() + local iata_number = ngx.req.get_headers()["x-wenrix-iata-number"] + local supplier = ngx.req.get_headers()["x-wenrix-supplier"] + local supplier_list = "" + if iata_number and supplier and config[iata_number] and config[iata_number][supplier] then + supplier_list = build_supplier_labels(supplier, config[iata_number][supplier]) + end + + if body then + body = ngx.re.gsub(body, "PLACEHOLDER", "" .. login_id .. "") + body = ngx.re.gsub(body, "PLACEHOLDER", "" .. xml_login_id .. "") + body = ngx.re.gsub(body, "PLACEHOLDER", "" .. supplier_list .. "") + end + ngx.req.set_body_data(body) + } +} diff --git a/tests/test_proxy.py b/tests/test_proxy.py index 54e858a..536408d 100644 --- a/tests/test_proxy.py +++ b/tests/test_proxy.py @@ -1,5 +1,7 @@ """Tests for the proxy functionality.""" +import os + import requests import xmltodict from test_utils import print_debug_info, print_request_debug, verify_headers @@ -56,7 +58,11 @@ def test_farelogix_aa_request(proxy_url): request_headers = {"test-header": "should-remain"} - response = requests.post(f"{proxy_url}/channel/farelogix-aa/anything", json=test_body, headers=request_headers) + base_path = "/channel/farelogix-aa" + if os.getenv("WP_CHANNELS_FARELOGIX_USE_ACCOUNT_IDS", "").lower() == "true": + base_path = f"{base_path}/cad" + + response = requests.post(f"{proxy_url}{base_path}/anything", json=test_body, headers=request_headers) if response.status_code != 200: print_request_debug(response, test_body, request_headers) assert response.status_code == 200 From de81d1093ed15eda074aecc6f9600c02609fd662 Mon Sep 17 00:00:00 2001 From: Jamie Zaharopoulos Date: Tue, 22 Apr 2025 14:34:19 -0400 Subject: [PATCH 2/2] Linting --- .vscode/extensions.json | 2 +- scripts/setup_nginx.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index de8ee23..0233a3f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,4 +2,4 @@ "recommendations": [ "ahmadalli.vscode-nginx-conf" ] -} \ No newline at end of file +} diff --git a/scripts/setup_nginx.sh b/scripts/setup_nginx.sh index 3c15b4f..0e49e43 100644 --- a/scripts/setup_nginx.sh +++ b/scripts/setup_nginx.sh @@ -68,7 +68,7 @@ setup_additional_includes() { if [ -f "$include_file" ]; then filename=$(basename "$include_file") target_path="/etc/nginx/includes/${filename}" - + if [ ! -f "$target_path" ]; then debug_log "Creating symlink for $include_file to $target_path" ln -s "$include_file" "$target_path"