public void TestKeyBlacklistingAndWhitelisting()
        {
            var ip  = GetRandomIP();
            var key = GetRandomKey();

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Allow traffic on {0} from {1}", key, ip));

            HackerSprayer.BlacklistKeyAsync(key, TimeSpan.FromMinutes(5)).Run();

            Assert.AreEqual(
                HackerSprayer.Result.KeyBlocked,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Block traffic on {0} from {1}", key, ip));

            Assert.AreEqual(
                HackerSprayer.Result.KeyBlocked,
                HackerSprayer.DefendAsync(key, GetRandomIP()).Run(),
                string.Format("Allow any traffic from {1}", key, ip));

            HackerSprayer.WhitelistKeyAsync(key).Run();

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Allow traffic on {0} from {1} after whitelist", key, ip));
        }
        public void TestKeyBlacklisting()
        {
            var key = GetRandomKey();
            var ip  = GetRandomIP();

            var interval = TimeSpan.FromMinutes(1);

            Assert.AreEqual(
                false,
                HackerSprayer.IsKeyBlacklistedAsync(key).Run(),
                "Key must not be blacklisted");

            var startTime = DateTime.Now;

            HackerSprayer.BlacklistKeyAsync(key, interval).Run();

            Assert.AreEqual(
                true,
                HackerSprayer.IsKeyBlacklistedAsync(key).Run(),
                "Key must be blacklisted");

            string [] blacklistedKeys = HackerSprayer.GetKeyBlacklists().Run();
            Assert.IsTrue(Array.Exists(blacklistedKeys, k => k == key),
                          "Key must be in the blacklist");

            WaitForIntervalToElapse(interval, startTime);

            Assert.AreEqual(
                false,
                HackerSprayer.IsKeyBlacklistedAsync(key).Run(),
                "Key must not be blacklisted after expiration time");
        }
        public static async Task <HackerSprayer.Result> DefendURL(HttpContext context)
        {
            HackerSprayer.Result result = HackerSprayer.Result.Allowed;

            if (!Initialized)
            {
                lock (lockObject)
                {
                    if (!Initialized)
                    {
                        Initialized         = true;
                        HackerSprayer.Store = new RedisDefenceStore(HackerSprayConfig.Settings.Redis,
                                                                    HackerSprayConfig.Settings.Prefix,
                                                                    HackerSprayer.Config);
                    }
                }
            }

            // This handles load balancers passing the original client IP
            // through this header.
            // WARNING: If your load balancer is not passing original client IP
            // through this header, then you will be blocking your load balancer,
            // causing a total outage. Also ensure this Header cannot be spoofed.
            // Your load balancer should be configured in a way that it does not accept
            // this header from the request, instead it always sets it itself.
            var originIP = IPAddress.Parse(context.Request.Headers["X-Forward-For"]
                                           ?? context.Request.UserHostAddress).MapToIPv4();

            foreach (var path in HackerSprayConfig.Settings.Paths)
            {
                if ((path.Post && context.Request.HttpMethod == "POST") ||
                    (!path.Post && context.Request.HttpMethod == "GET") &&
                    path.Name == context.Request.Path)
                {
                    if (path.Mode == "perkey")
                    {
                        result = await HackerSprayer.DefendAsync(context.Request.Path, originIP,
                                                                 path.Interval, path.MaxAttempts,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 TimeSpan.MaxValue, long.MaxValue);
                    }
                    else if (path.Mode == "perorigin")
                    {
                        result = await HackerSprayer.DefendAsync(context.Request.Path, originIP,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 path.Interval, path.MaxAttempts,
                                                                 TimeSpan.MaxValue, long.MaxValue);
                    }
                    else //(path.Mode == "perkeyorigin")
                    {
                        result = await HackerSprayer.DefendAsync(context.Request.Path, originIP,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 path.Interval, path.MaxAttempts);
                    }

                    // Blacklist origin. After that, it becomes least expensive to block requests
                    if (result == HackerSprayer.Result.TooManyHitsFromOrigin)
                    {
                        await HackerSprayer.BlacklistOriginAsync(originIP, path.Interval);
                    }
                    else if (result == HackerSprayer.Result.TooManyHitsOnKey)
                    {
                        await HackerSprayer.BlacklistKeyAsync(path.Name, path.Interval);
                    }
                    //else if (result == HackerSprayer.Result.TooManyHitsOnKeyFromOrigin)
                    // There is nothing for that, because we neither want to block the key for all ip,
                    // nor do we want to block the ip for all key. It just has to be checked each
                    // and every time. Thus this is the most expensive check.
                    break;
                }
            }

            return(result);
        }