1/** 2 * File: /assets/js/tfcm-client-script.js 3 * 4 * Fetches the client IP address and logs the HTTP request via AJAX. 5 * 6 * NOTE: This script exists **specifically** to log requests that cannot be captured otherwise 7 * due to page caching. Therefore, it **should NOT** include cache-busting mechanisms like 8 * adding a timestamp or random query strings to request URLs. 9 * 10 * @package TrafficMonitor 11 */ 12document.addEventListener("DOMContentLoaded", function () { 13 const TFCM_DEBUG = false; // Set to true for debugging 14 if (TFCM_DEBUG) console.log("tfcm-client-script.js loaded."); 15 16 // Fetch IP from WordPress internal AJAX endpoint. This is necessary because: 17 // 1. $_SERVER['REMOTE_ADDR'] can be spoofed and is unreliable for logging real user IPs. 18 // 2. AJAX requests do not include X-Forwarded-For headers, making server-side IP detection incomplete. 19 // 3. This ensures consistency with HTTP request logging, which uses a best-IP selection logic. 20 // 4. External services like ipify may return ipv6 while the http request logs ipv4 21 fetch(tfcmClientAjax.ajax_url, { 22 method: "POST", 23 headers: { "Content-Type": "application/x-www-form-urlencoded" }, 24 body: new URLSearchParams({ 25 action: "tfcm_get_ip" 26 }) 27 }) 28 .then(response => response.json()) 29 .then(data => { 30 if (TFCM_DEBUG) console.log("IP fetch response:", data); 31 if (data.success && data.data.ip) { 32 sendTfcmAjaxRequest(data.data.ip); 33 } else { 34 sendTfcmAjaxRequest(null); 35 } 36 }) 37 .catch(() => { 38 sendTfcmAjaxRequest(null); 39 }); 40 41 /** 42 * Sends an AJAX request to log the HTTP request. 43 * 44 * @param {string|null} ip - The client IP address (or null if not available). 45 */ 46 function sendTfcmAjaxRequest(ip) { 47 const xhr = new XMLHttpRequest(); 48 const fullUrl = window.location.href; 49 const urlObj = fullUrl ? new URL(fullUrl) : null; 50 const referrer = document.referrer; 51 const referrerObj = referrer ? new URL(referrer) : null; 52 53 const params = new URLSearchParams({ 54 action: "tfcm_log_ajax_request", 55 nonce: tfcmClientAjax.logging_nonce, 56 ip_address: ip || "server-detected", 57 request_url: urlObj ? urlObj.origin + urlObj.pathname : '', // Strip query string 58 request_query: urlObj ? urlObj.search.substring(1) : '', 59 referrer_url: referrerObj ? referrerObj.origin + referrerObj.pathname : '', // Strip query string 60 referrer_query: referrerObj ? referrerObj.search.substring(1) : '' 61 }); 62 63 if (TFCM_DEBUG) console.log("tfcm-client-script.js ip_address: ", params.get("ip_address")); 64 if (TFCM_DEBUG) console.log("tfcm-client-script.js request_url: ", params.get("request_url")); 65 if (TFCM_DEBUG) console.log("tfcm-client-script.js request_query: ", params.get("request_query")); 66 if (TFCM_DEBUG) console.log("tfcm-client-script.js referrer_url: ", params.get("referrer_url")); 67 if (TFCM_DEBUG) console.log("tfcm-client-script.js referrer_query: ", params.get("referrer_query")); 68 69 70 xhr.open("POST", tfcmClientAjax.ajax_url, true); 71 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 72 73 xhr.onreadystatechange = function () { 74 if (xhr.readyState === XMLHttpRequest.DONE) { 75 if (xhr.status >= 200 && xhr.status < 300) { 76 if (TFCM_DEBUG) console.log("Success:", JSON.parse(xhr.responseText).data.message); 77 } else { 78 if (TFCM_DEBUG) console.error("AJAX error:", xhr.responseText); 79 } 80 } 81 }; 82 83 xhr.send(params.toString()); 84 } 85});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.