Benjamin Harris преди 2 месеца
родител
ревизия
5c03126514
променени са 5 файла, в които са добавени 23 реда и са изтрити 27 реда
  1. 3 1
      .claude/settings.local.json
  2. 0 15
      lib/geocode.rb
  3. 10 6
      lib/http.rb
  4. 0 5
      tools/backfill_geocode.rb
  5. 10 0
      web/index.php

+ 3 - 1
.claude/settings.local.json

@@ -12,7 +12,9 @@
       "Bash(python3 -c ':*)",
       "Bash(grep -n \"FROM \\\\`{\" /f/GIT_REPO/tas_councils/web/index.php)",
       "Bash(grep -n '\\\\$t\\\\|tableHasColumn\\\\|tableExists' /f/GIT_REPO/tas_councils/web/index.php)",
-      "Bash(xargs sed:*)"
+      "Bash(xargs sed:*)",
+      "Bash(grep -n \"Open3\\\\|capture2\\\\|backtick\\\\|\\\\`#{\" f:/GIT_REPO/tas_councils/lib/http.rb)",
+      "Bash(grep -n \"validate_table_name\\\\|FROM \\\\`{\\\\|SHOW COLUMNS\" f:/GIT_REPO/tas_councils/web/index.php)"
     ]
   }
 }

+ 0 - 15
lib/geocode.rb

@@ -35,21 +35,6 @@ module Geocode
     @cache_table_ready = true
   end
 
-  # Add columns to any da_* table to store normalized fields
-  def self.ensure_da_columns!(table)
-    DB.validate_table_name!(table)
-    esc = DB.client.escape(table)
-    DB.client.query("ALTER TABLE `#{esc}` ADD COLUMN IF NOT EXISTS address_std VARCHAR(255) NULL")
-    DB.client.query("ALTER TABLE `#{esc}` ADD COLUMN IF NOT EXISTS street VARCHAR(255) NULL")
-    DB.client.query("ALTER TABLE `#{esc}` ADD COLUMN IF NOT EXISTS locality VARCHAR(120) NULL")
-    DB.client.query("ALTER TABLE `#{esc}` ADD COLUMN IF NOT EXISTS state VARCHAR(10) NULL")
-    DB.client.query("ALTER TABLE `#{esc}` ADD COLUMN IF NOT EXISTS postcode VARCHAR(10) NULL")
-    DB.client.query("ALTER TABLE `#{esc}` ADD COLUMN IF NOT EXISTS lat DECIMAL(10,7) NULL")
-    DB.client.query("ALTER TABLE `#{esc}` ADD COLUMN IF NOT EXISTS lng DECIMAL(10,7) NULL")
-  rescue Mysql2::Error => e
-    Log.warn "geocode", "ensure columns skipped for #{table}: #{e.message}"
-  end
-
   # Public helper to geocode and return a hash of normalized components
   # Returns nil on hard failures
   def self.format_au(raw_address, council_hint: "TAS")

+ 10 - 6
lib/http.rb

@@ -2,6 +2,7 @@
 require "net/http"
 require "uri"
 require "openssl"
+require "open3"
 
 module Http
   BASE_HEADERS = {
@@ -87,12 +88,15 @@ def self.get(url, headers: {}, tries: 4, referer: nil)
         end
 
         if [403, 406].include?(code)
-          # final curl fallback
-          ua = BASE_HEADERS["User-Agent"]
-          acc = BASE_HEADERS["Accept"]
-          lang = BASE_HEADERS["Accept-Language"]
-          cmd = %Q{curl -sSL --compressed -A "#{ua}" -H "Accept: #{acc}" -H "Accept-Language: #{lang}" -e "#{ref}" "#{uri}"}
-          out = `#{cmd}`
+          # final curl fallback — use array form to avoid shell injection
+          out, = Open3.capture2(
+            "curl", "-sSL", "--compressed",
+            "-A", BASE_HEADERS["User-Agent"],
+            "-H", "Accept: #{BASE_HEADERS["Accept"]}",
+            "-H", "Accept-Language: #{BASE_HEADERS["Accept-Language"]}",
+            "-e", ref,
+            uri.to_s
+          )
           return out unless out.to_s.strip.empty?
         end
 

+ 0 - 5
tools/backfill_geocode.rb

@@ -28,10 +28,6 @@ def discover_da_tables
   arr
 end
 
-def ensure_columns!(table)
-  Geocode.ensure_da_columns!(table)
-end
-
 def need_update_clause(overwrite:)
   if overwrite
     # touch everything, so we also overwrite address if desired
@@ -127,7 +123,6 @@ rescue StandardError => e
 end
 
 def process_table(table)
-  ensure_columns!(table)
   sel_stmt, upd_stmt, over_stmt = prep_statements(table, overwrite: OVERWRITE_ADDRESS)
 
   processed = 0

+ 10 - 0
web/index.php

@@ -54,6 +54,13 @@ function aliasFirstExisting(PDO $pdo, string $table, array $candidates, string $
     return "'' AS `$alias`";
 }
 
+/** Abort if $table is not a safe da_* or da_*_stages identifier. */
+function validate_table_name(string $table): void {
+    if (!preg_match('/\Ada_[a-z0-9_]+\z/', $table)) {
+        http_response_code(500);
+        exit("Invalid table name");
+    }
+}
 function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
 function council_name_from_key(string $k): string {
     $base = preg_replace('/^da_/', '', $k);
@@ -73,6 +80,7 @@ function days_left(?string $ymd): ?int {
     return (int)$today->diff($d)->format('%r%a');
 }
 function tableHasColumn(PDO $pdo, string $table, string $col): bool {
+    validate_table_name($table);
     $q = $pdo->prepare("SHOW COLUMNS FROM `{$table}` LIKE ?");
     $q->execute([$col]);
     return (bool)$q->fetch();
@@ -114,6 +122,7 @@ $stagesByRef = [];
 foreach ($tables as $t) {
     $stageT = $t . '_stages';
     if (!tableExists($pdo, $stageT)) continue;
+    validate_table_name($stageT);
 
     // Pull everything (small tables) – adjust/WHERE if needed
     $st2 = $pdo->query("SELECT * FROM `{$stageT}`");
@@ -184,6 +193,7 @@ foreach ($tables as $t) {
     $cols[] = tableHasColumn($pdo, $t, 'document_url')        ? "COALESCE(document_url,'') AS document_url"     : "'' AS document_url";
     $cols[] = tableHasColumn($pdo, $t, 'local_document_url')  ? "COALESCE(local_document_url,'') AS local_document_url" : "'' AS local_document_url";
 
+    validate_table_name($t);
     $selects[] = "SELECT ".implode(", ", $cols)." FROM `{$t}`";
 }
 $sql = "SELECT * FROM (".implode(" UNION ALL ", $selects).") AS x";