/// <summary> /// Returns whether or not the user is valid /// </summary> /// <param name="state" type="NoBotState">NoBot state</param> /// <returns>Whether user is valid</returns> public bool IsValid(out NoBotState state) { EnsureChildControls(); CheckResponseAndStoreState(); state = _state; return(NoBotState.Valid == state); }
// Check the last response (if any) and prepare for the next one void CheckResponseAndStoreState() { if (NoBotState.InvalidUnknown != _state) { return; } try { // Report valid when page first loaded (to avoid breaking pages that unconditionally check IsValid) if (!Page.IsPostBack) { _state = NoBotState.Valid; return; } // Report invalid if response arrives too soon var responseTime = (DateTime)ViewState[ResponseTimeKey]; var utcNow = DateTime.UtcNow; if (utcNow < responseTime) { _state = NoBotState.InvalidResponseTooSoon; return; } // Report invalid if too many responses from same IP address // NOTE: The performance of the following code can be improved // if performance becomes an issue. lock (_pastAddresses) { // Add user address to address cache, taking care not to duplicate keys var userAddress = Page.Request.UserHostAddress; var utcAdd = utcNow; while (_pastAddresses.ContainsKey(utcAdd)) { utcAdd = utcAdd.AddTicks(1); } _pastAddresses.Add(utcAdd, userAddress); // Calculate cutoff window for cached addresses var utcCutoff = utcNow.AddSeconds(-_cutoffWindowSeconds); // Determine number of expired addresses var cutoffs = 0; foreach (var time in _pastAddresses.Keys) { if (time < utcCutoff) { cutoffs++; } else { break; } } // Remove expired addresses while (0 < cutoffs) { _pastAddresses.RemoveAt(0); cutoffs--; } // Determine number of instances of user address in cache var instances = 0; foreach (var address in _pastAddresses.Values) { if (userAddress == address) { instances++; } } // Fail if too many if (_cutoffMaximumInstances < instances) { _state = NoBotState.InvalidAddressTooActive; return; } } // Report invalid if response is wrong var sessionKey = (string)ViewState[SessionKeyKey]; var requiredResponse = (string)Page.Session[sessionKey]; Page.Session.Remove(sessionKey); if (requiredResponse != _extender.ClientState) { _state = NoBotState.InvalidBadResponse; return; } // All checks OK, report valid _state = NoBotState.Valid; } catch (NullReferenceException) { _state = NoBotState.InvalidBadSession; } }
public bool IsValid(out NoBotState state) { EnsureChildControls(); CheckResponseAndStoreState(); state = _state; return (NoBotState.Valid == state); }
// Check the last response (if any) and prepare for the next one private void CheckResponseAndStoreState() { if (NoBotState.InvalidUnknown == _state) { try { // Report valid when page first loaded (to avoid breaking pages that unconditionally check IsValid) // if (!Page.IsPostBack) { _state = NoBotState.Valid; return; } // Report invalid if response arrives too soon // DateTime responseTime = (DateTime)ViewState[ResponseTimeKey]; DateTime utcNow = DateTime.UtcNow; if (utcNow < responseTime) { _state = NoBotState.InvalidResponseTooSoon; return; } // Report invalid if too many responses from same IP address // NOTE: The performance of the following code can be improved // if performance becomes an issue. // lock (_pastAddresses) { // Add user address to address cache, taking care not to duplicate keys string userAddress = Page.Request.UserHostAddress; DateTime utcAdd = utcNow; while (_pastAddresses.ContainsKey(utcAdd)) { utcAdd = utcAdd.AddTicks(1); } _pastAddresses.Add(utcAdd, userAddress); // Calculate cutoff window for cached addresses DateTime utcCutoff = utcNow.AddSeconds(-_cutoffWindowSeconds); // Determine number of expired addresses int cutoffs = 0; foreach (DateTime time in _pastAddresses.Keys) { if (time < utcCutoff) { cutoffs++; } else { break; } } // Remove expired addresses while (0 < cutoffs) { _pastAddresses.RemoveAt(0); cutoffs--; } // Determine number of instances of user address in cache int instances = 0; foreach (string address in _pastAddresses.Values) { if (userAddress == address) { instances++; } } // Fail if too many if (_cutoffMaximumInstances < instances) { _state = NoBotState.InvalidAddressTooActive; return; } } // Report invalid if response is wrong // string sessionKey = (string)ViewState[SessionKeyKey]; string requiredResponse = (string)Page.Session[sessionKey]; Page.Session.Remove(sessionKey); if (requiredResponse != _extender.ClientState) { _state = NoBotState.InvalidBadResponse; return; } // All checks OK, report valid // _state = NoBotState.Valid; } catch (NullReferenceException) { _state = NoBotState.InvalidBadSession; } } }