diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 52ba7f0..22a287f 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -78,6 +78,7 @@ jobs: - name: Check deployment scripts and asset syntax run: | bash -n scripts/deploy-file.sh + bash -n scripts/deploy-theme.sh node --check deploy/production/3w-newsletter-popup/assets/newsletter-popup.js bash tests/scripts/deploy-file.test.sh diff --git a/scripts/deploy-file.sh b/scripts/deploy-file.sh index f13a1de..38eb525 100755 --- a/scripts/deploy-file.sh +++ b/scripts/deploy-file.sh @@ -148,8 +148,9 @@ if [[ "$TARGET" == "production" ]]; then fi case "$DEPLOY_SCHEME" in - ftp|ftps) DEFAULT_PORT=21 ;; - sftp) DEFAULT_PORT=22 ;; + ftp) DEFAULT_PORT=21; LFTP_SCHEME=ftp ;; + ftps) DEFAULT_PORT=21; LFTP_SCHEME=ftp ;; + sftp) DEFAULT_PORT=22; LFTP_SCHEME=sftp ;; *) echo "Unsupported THREEW_DEPLOY_SCHEME '$DEPLOY_SCHEME'. Use ftp, ftps, or sftp." >&2 exit 1 @@ -170,7 +171,9 @@ if [[ -z "$FTP_PASS" && ! ( "$DEPLOY_SCHEME" == "sftp" && -n "$SSH_KEY_PATH" ) ] echo fi -LFTP_URI="${DEPLOY_SCHEME}://${FTP_HOST}:${FTP_PORT}" +# lftp's ftps:// URI means implicit TLS. Hostinger uses explicit TLS (AUTH TLS) +# on port 21, represented by an ftp:// URI plus ftp:ssl-force below. +LFTP_URI="${LFTP_SCHEME}://${FTP_HOST}:${FTP_PORT}" FTP_SETUP_CMDS="set cmd:fail-exit yes set ssl:verify-certificate $SSL_VERIFY set xfer:clobber yes" diff --git a/scripts/deploy-theme.sh b/scripts/deploy-theme.sh index e48c9b3..1a4747a 100755 --- a/scripts/deploy-theme.sh +++ b/scripts/deploy-theme.sh @@ -116,12 +116,15 @@ REMOTE_THEME_DIR=${CUSTOM_REMOTE_DIR:-$REMOTE_THEME_DIR} case "$DEPLOY_SCHEME" in ftp) DEFAULT_PORT=21 + LFTP_SCHEME=ftp ;; ftps) DEFAULT_PORT=21 + LFTP_SCHEME=ftp ;; sftp) DEFAULT_PORT=22 + LFTP_SCHEME=sftp ;; *) echo "Unsupported THREEW_DEPLOY_SCHEME '$DEPLOY_SCHEME'. Use ftp, ftps, or sftp." >&2 @@ -134,7 +137,9 @@ if [[ "$TARGET" == "production" ]]; then FTP_PORT=${THREEW_PROD_FTP_PORT:-$FTP_PORT} fi -LFTP_URI="${DEPLOY_SCHEME}://${FTP_HOST}:${FTP_PORT}" +# lftp's ftps:// URI means implicit TLS. Hostinger uses explicit TLS (AUTH TLS) +# on port 21, represented by an ftp:// URI plus ftp:ssl-force below. +LFTP_URI="${LFTP_SCHEME}://${FTP_HOST}:${FTP_PORT}" FTP_SETUP_CMDS="set ssl:verify-certificate $SSL_VERIFY" diff --git a/tests/scripts/deploy-file.test.sh b/tests/scripts/deploy-file.test.sh index 1975ab6..bfbd9a4 100755 --- a/tests/scripts/deploy-file.test.sh +++ b/tests/scripts/deploy-file.test.sh @@ -10,8 +10,14 @@ mkdir -p "$TMP/bin" cat > "$TMP/bin/lftp" <<'FAKE_LFTP' #!/usr/bin/env bash set -euo pipefail +if [[ -n "${FAKE_LFTP_ARGS_LOG:-}" ]]; then + printf '%s\n' "$*" >> "$FAKE_LFTP_ARGS_LOG" +fi did_put=false while IFS= read -r line; do + if [[ -n "${FAKE_LFTP_STDIN_LOG:-}" ]]; then + printf '%s\n' "$line" >> "$FAKE_LFTP_STDIN_LOG" + fi if [[ "$line" =~ ^get\ \"([^\"]+)\"\ -o\ \"([^\"]+)\"$ ]]; then destination=${BASH_REMATCH[2]} if [[ "$did_put" == true && -n "${FAKE_CORRUPT_READBACK_ONCE:-}" && -f "${FAKE_CORRUPT_STATE}" ]]; then @@ -78,6 +84,34 @@ env "${COMMON_ENV[@]}" "$SCRIPT" \ --expected-remote-sha256 "$LOCAL_HASH" [[ $(sha256sum "$TMP/remote.js" | awk '{print $1}') == "$LOCAL_HASH" ]] +# Explicit FTPS uses an ftp:// URI plus AUTH TLS rather than implicit ftps://. +: > "$TMP/lftp-args.log" +: > "$TMP/lftp-stdin.log" +env "${COMMON_ENV[@]}" \ + THREEW_DEPLOY_SCHEME=ftps \ + "FAKE_LFTP_ARGS_LOG=$TMP/lftp-args.log" \ + "FAKE_LFTP_STDIN_LOG=$TMP/lftp-stdin.log" \ + "$SCRIPT" \ + --target staging \ + --local-file "$TMP/local.js" \ + --remote-file newsletter-popup.js \ + --backup-file "$TMP/backup.js" \ + --verified-file "$TMP/verified.js" \ + --expected-remote-sha256 "$ORIGINAL_HASH" \ + --expected-remote-sha256 "$LOCAL_HASH" +grep -Fq 'ftp://fake.invalid:21' "$TMP/lftp-args.log" +if grep -Fq 'ftps://fake.invalid:21' "$TMP/lftp-args.log"; then + echo 'Expected explicit FTPS to avoid the implicit-TLS URI scheme' >&2 + exit 1 +fi +grep -Fxq 'set ftp:ssl-force true' "$TMP/lftp-stdin.log" +grep -Fxq 'set ftp:ssl-protect-data true' "$TMP/lftp-stdin.log" +grep -Fxq 'set ftp:ssl-auth TLS' "$TMP/lftp-stdin.log" + +# The theme mirror must use the same explicit-FTPS URI mapping. +grep -Fq 'LFTP_SCHEME=ftp' "$REPO_ROOT/scripts/deploy-theme.sh" +grep -Fq 'LFTP_URI="${LFTP_SCHEME}://' "$REPO_ROOT/scripts/deploy-theme.sh" + # Unknown remote bytes must fail before upload. printf 'unreviewed remote edit' > "$TMP/remote.js" if run_deploy >/dev/null 2>&1; then