install-github-token-test.sh 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/bin/bash
  2. set -euo pipefail
  3. ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
  4. TEMP_DIR=$(mktemp -d)
  5. trap 'rm -rf "$TEMP_DIR"' EXIT
  6. cat > "$TEMP_DIR/curl" <<'EOF'
  7. #!/bin/bash
  8. printf '%s\n' "$@" > "$CURL_ARGS_LOG"
  9. env > "${CURL_ARGS_LOG}.env"
  10. cat > "${CURL_ARGS_LOG}.stdin"
  11. EOF
  12. chmod +x "$TEMP_DIR/curl"
  13. mkdir "$TEMP_DIR/home"
  14. cat > "$TEMP_DIR/home/.curlrc" <<'EOF'
  15. url = "https://example.com/collect"
  16. header = "X-Leaked-From-Curlrc: yes"
  17. EOF
  18. run_api_curl() {
  19. CURL_ARGS_LOG="$1" HOME="$TEMP_DIR/home" PATH="$TEMP_DIR:$PATH" UPDATE_GITHUB_TOKEN="${2:-}" \
  20. GITHUB_TOKEN="github-fallback" GH_TOKEN="gh-fallback" \
  21. bash -c 'source <(head -n -1 "$1"); github_api_curl -s "$2"' bash \
  22. "$ROOT_DIR/deploy/install.sh" "https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest"
  23. }
  24. run_api_curl "$TEMP_DIR/authenticated" "update-secret"
  25. test "$(head -n 1 "$TEMP_DIR/authenticated")" = '-q'
  26. grep -Fxq -- '--config' "$TEMP_DIR/authenticated"
  27. grep -Fxq -- '-' "$TEMP_DIR/authenticated"
  28. grep -Fxq -- '--globoff' "$TEMP_DIR/authenticated"
  29. grep -Fxq 'header = "Authorization: Bearer update-secret"' "$TEMP_DIR/authenticated.stdin"
  30. if grep -Fq 'update-secret' "$TEMP_DIR/authenticated"; then
  31. echo "installer exposed the update token in curl argv" >&2
  32. exit 1
  33. fi
  34. if grep -Eq 'update-secret|github-fallback|gh-fallback' "$TEMP_DIR/authenticated.env"; then
  35. echo "installer exposed a token in curl environment" >&2
  36. exit 1
  37. fi
  38. test "$(grep -Fxc 'https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest' "$TEMP_DIR/authenticated")" -eq 1
  39. if grep -Fq 'example.com/collect' "$TEMP_DIR/authenticated" || grep -Fq 'X-Leaked-From-Curlrc' "$TEMP_DIR/authenticated" ||
  40. grep -Fq 'example.com/collect' "$TEMP_DIR/authenticated.stdin" || grep -Fq 'X-Leaked-From-Curlrc' "$TEMP_DIR/authenticated.stdin"; then
  41. echo "installer allowed hostile curl config into authenticated invocation" >&2
  42. exit 1
  43. fi
  44. run_api_curl "$TEMP_DIR/anonymous"
  45. test "$(head -n 1 "$TEMP_DIR/anonymous")" = '-q'
  46. if grep -Eq 'github-fallback|gh-fallback' "$TEMP_DIR/anonymous.env"; then
  47. echo "installer exposed a fallback token in anonymous curl environment" >&2
  48. exit 1
  49. fi
  50. if grep -Fq 'Authorization:' "$TEMP_DIR/anonymous"; then
  51. echo "installer unexpectedly used a fallback token" >&2
  52. exit 1
  53. fi
  54. test ! -s "$TEMP_DIR/anonymous.stdin"
  55. test "$(grep -Fxc 'https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest' "$TEMP_DIR/anonymous")" -eq 1
  56. if grep -Fq 'example.com/collect' "$TEMP_DIR/anonymous" || grep -Fq 'X-Leaked-From-Curlrc' "$TEMP_DIR/anonymous"; then
  57. echo "installer allowed hostile curl config into anonymous invocation" >&2
  58. exit 1
  59. fi
  60. assert_unsafe_invocation_rejected() {
  61. local name=$1
  62. shift
  63. rm -f "$TEMP_DIR/$name" "$TEMP_DIR/$name.stdin"
  64. if CURL_ARGS_LOG="$TEMP_DIR/$name" PATH="$TEMP_DIR:$PATH" UPDATE_GITHUB_TOKEN="update-secret" \
  65. bash -c 'source <(head -n -1 "$1"); shift; github_api_curl "$@"' bash \
  66. "$ROOT_DIR/deploy/install.sh" "$@" 2>/dev/null; then
  67. echo "installer accepted unsafe curl invocation: $name" >&2
  68. exit 1
  69. fi
  70. if [ -e "$TEMP_DIR/$name" ]; then
  71. echo "installer invoked curl for unsafe request: $name" >&2
  72. exit 1
  73. fi
  74. }
  75. assert_unsafe_invocation_rejected non-api -s \
  76. "https://github.com/Wei-Shaw/sub2api/releases/download/v1/asset"
  77. assert_unsafe_invocation_rejected mixed-host -s \
  78. "https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest" \
  79. "https://example.com/collect"
  80. assert_unsafe_invocation_rejected multiple-api -s \
  81. "https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest" \
  82. "https://api.github.com/repos/Wei-Shaw/sub2api/releases"
  83. assert_unsafe_invocation_rejected url-option -s --url \
  84. "https://example.com/collect" \
  85. "https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest"
  86. # Every installer release API request must use the scoped helper.
  87. test "$(grep -c 'github_api_curl .*https://api.github.com/' "$ROOT_DIR/deploy/install.sh")" -eq 3
  88. # Asset and checksum downloads must continue to call curl directly.
  89. grep -Fq 'curl -sL "$download_url"' "$ROOT_DIR/deploy/install.sh"
  90. grep -Fq 'curl -sL "$checksum_url"' "$ROOT_DIR/deploy/install.sh"
  91. echo "install GitHub token checks passed"