![]() |
VOOZH | about |
dotnet add package Mostlylucid.GeoDetection.Contributor --version 1.0.0
NuGet\Install-Package Mostlylucid.GeoDetection.Contributor -Version 1.0.0
<PackageReference Include="Mostlylucid.GeoDetection.Contributor" Version="1.0.0" />
<PackageVersion Include="Mostlylucid.GeoDetection.Contributor" Version="1.0.0" />Directory.Packages.props
<PackageReference Include="Mostlylucid.GeoDetection.Contributor" />Project file
paket add Mostlylucid.GeoDetection.Contributor --version 1.0.0
#r "nuget: Mostlylucid.GeoDetection.Contributor, 1.0.0"
#:package Mostlylucid.GeoDetection.Contributor@1.0.0
#addin nuget:?package=Mostlylucid.GeoDetection.Contributor&version=1.0.0Install as a Cake Addin
#tool nuget:?package=Mostlylucid.GeoDetection.Contributor&version=1.0.0Install as a Cake Tool
Geographic bot detection contributor for Mostlylucid.BotDetection
This package demonstrates the contributor plugin pattern for extending bot detection with domain-specific signals.
dotnet add package Mostlylucid.GeoDetection
dotnet add package Mostlylucid.GeoDetection.Contributor
var builder = WebApplication.CreateBuilder(args);
// Add core geo-location services
builder.Services.AddGeoLocationServices();
// Add bot detection with orchestrator
builder.Services.AddBotDetection();
// Add geo-detection contributor (that's it!)
builder.Services.AddGeoDetectionContributor(options =>
{
options.EnableBotVerification = true; // Verify known bots (Googlebot, etc.)
options.EnableInconsistencyDetection = true; // Detect locale/geo mismatches
options.FlagHostingIps = true; // Flag datacenter IPs
options.FlagVpnIps = true; // Flag VPN/proxy IPs
});
app.UseBotDetection();
That's it! The contributor automatically:
The GeoDetection integration showcases the extensibility of the bot detection system:
Once registered, contributors work automatically with:
Contributors communicate via typed signals on the blackboard:
// GeoContributor writes
signals.Add(GeoSignalKeys.GeoCountryCode, "US");
// Other contributors/detectors read
var country = state.GetSignal<string>(GeoSignalKeys.GeoCountryCode);
This enables composable detection without tight coupling.
Just one line:
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IContributingDetector, GeoContributor>());
Want to add custom bot detection logic? Follow this simple pattern:
using Mostlylucid.BotDetection.Models;
using Mostlylucid.BotDetection.Orchestration;
public class MyCustomContributor : ContributingDetectorBase
{
public override string Name => "MyCustom";
public override int Priority => 150; // Run order (lower = earlier)
// Optional: Only run after certain signals are available
public override IReadOnlyList<TriggerCondition> TriggerConditions =>
[TriggerCondition.RequireSignal(GeoSignalKeys.GeoCountryCode)];
public override async Task<IReadOnlyList<DetectionContribution>> ContributeAsync(
BlackboardState state,
CancellationToken cancellationToken)
{
// Read signals from blackboard
var country = state.GetSignal<string>(GeoSignalKeys.GeoCountryCode);
var userAgent = state.UserAgent;
// Your custom detection logic
if (IsSuspiciousPattern(country, userAgent))
{
return Single(DetectionContribution.Bot(
Name, "MyCustomCheck",
confidenceDelta: 0.6,
reason: "Custom rule triggered",
botType: BotType.Unknown,
weight: 1.5
));
}
return None();
}
private bool IsSuspiciousPattern(string country, string userAgent) => false;
}
public static class MyCustomContributorExtensions
{
public static IServiceCollection AddMyCustomContributor(
this IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IContributingDetector, MyCustomContributor>());
return services;
}
}
builder.Services.AddBotDetection();
builder.Services.AddMyCustomContributor(); // Done!
Your contributor automatically:
Signal keys use partial class for extension:
// In Mostlylucid.GeoDetection.Contributor
public static partial class GeoSignalKeys
{
public const string GeoCountryCode = "geo.country_code";
public const string GeoIsVpn = "geo.is_vpn";
// ... more geo signals
}
// In your custom package
public static partial class MySignalKeys
{
public const string MyCustomSignal = "my.custom_signal";
}
The GeoContributor verifies known bot origins:
private static readonly Dictionary<string, string[]> KnownBotOrigins = new()
{
["googlebot"] = ["US"],
["bingbot"] = ["US"],
["yandexbot"] = ["RU", "FI", "NL"],
["baiduspider"] = ["CN", "HK"]
};
If a User-Agent claims to be "Googlebot" but the IP is from China:
This catches bot impersonation attempts.
| Signal Key | Type | Description |
|---|---|---|
geo.country_code |
string | ISO 3166-1 alpha-2 country code |
geo.country_name |
string | Full country name |
geo.city |
string | City name |
geo.timezone |
string | IANA timezone |
geo.is_vpn |
bool | IP is from VPN/proxy |
geo.is_hosting |
bool | IP is from datacenter/hosting |
geo.is_suspicious_country |
bool | Country is in suspicious list |
geo.bot_verified |
bool | Known bot verified from expected country |
geo.bot_origin_mismatch |
bool | Bot claims identity but wrong country |
{
"BotDetection": {
"Geo": {
"EnableBotVerification": true,
"EnableInconsistencyDetection": true,
"FlagHostingIps": true,
"FlagVpnIps": true,
"SuspiciousCountries": ["KP", "CN"],
"TrustedCountries": ["US", "GB", "DE"],
"VerifiedBotConfidenceBoost": 0.3,
"BotOriginMismatchPenalty": 0.8,
"SignalWeight": 1.0,
"Priority": 100
}
}
}
The contributor pattern allows:
This is the plugin architecture in action!
MIT
A bot detection contributor that provides detailed geographic location analysis for request validation. This package bridges Mostlylucid.GeoDetection with Mostlylucid.BotDetection to enable geo-based bot detection.
dotnet add package Mostlylucid.GeoDetection.Contributor
// In Program.cs or Startup.cs
services.AddGeoLocationServices(options =>
{
options.DefaultProvider = GeoProvider.MaxMind;
options.GeoLite2DatabasePath = "/path/to/GeoLite2-City.mmdb";
});
services.AddBotDetection(options => { /* ... */ });
// Add the geo contributor
services.AddGeoDetectionContributor(options =>
{
options.EnableBotVerification = true;
options.EnableInconsistencyDetection = true;
options.SuspiciousCountries = ["CN", "RU", "KP"]; // Optional
});
The contributor emits the following signals to the blackboard:
| Signal Key | Type | Description |
|---|---|---|
geo.country_code |
string | ISO 3166-1 alpha-2 country code |
geo.country_name |
string | Full country name |
geo.region_code |
string | Region/state code |
geo.city |
string | City name |
geo.latitude |
double | Latitude coordinate |
geo.longitude |
double | Longitude coordinate |
geo.timezone |
string | Timezone (e.g., "America/New_York") |
geo.is_vpn |
bool | Whether IP is known VPN |
geo.is_hosting |
bool | Whether IP is from hosting provider |
geo.continent_code |
string | Continent code (e.g., "NA", "EU") |
The contributor detects several types of geo-based inconsistencies:
Known search engine bots should originate from specific countries:
| Bot | Expected Countries |
|---|---|
| Googlebot | US |
| Bingbot | US |
| Yandex | RU |
| Baidu | CN |
If a User-Agent claims to be Googlebot but the IP is from China, this is flagged as highly suspicious.
If the Accept-Language header suggests a specific locale (e.g., "en-US") but the IP originates from a different timezone, this is flagged.
Browser User-Agents claiming consumer locales from datacenter IPs are flagged.
public class GeoContributorOptions
{
// Enable verification that known bots come from expected countries
public bool EnableBotVerification { get; set; } = true;
// Enable geo-inconsistency detection
public bool EnableInconsistencyDetection { get; set; } = true;
// Countries to flag as suspicious (higher weight)
public List<string> SuspiciousCountries { get; set; } = [];
// Countries to always trust (lower weight)
public List<string> TrustedCountries { get; set; } = [];
// Priority for this detector (lower = runs earlier)
public int Priority { get; set; } = 15;
}
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 94 | 4/18/2026 |