private static bool CheckForFlooding(IInvocation invocation, Boolean blockWhenFlooding)
        {
            bool blockRequest = false;

            string requestIP    = Helper.MapRequestIP();
            string obfuscatedIP = Helper.HashAndTruncate(requestIP);

            if (Holder.connectionStore.ContainsKey(requestIP) && Holder.connectionStore[requestIP].LastDataSend != null)
            {
                // We have seen this IP before
                PersistentMapAPI.Settings settings = Helper.LoadSettings();

                UserInfo info            = Holder.connectionStore[requestIP];
                string   lastDateSendISO = info.LastDataSend.ToString("u");
                DateTime now             = DateTime.UtcNow;
                DateTime blockedUntil    = info.LastDataSend.AddMinutes(settings.minMinutesBetweenPost);
                TimeSpan delta           = now.Subtract(info.LastDataSend);
                string   deltaS          = $"{(int)delta.TotalMinutes}:{delta.Seconds:00}";

                if (now >= blockedUntil)
                {
                    // The user hasn't sent a message within the time limit, so just note it when tracing is enabled
                    logger.Trace($"IP:{(settings.Debug ? requestIP : obfuscatedIP)} last send a request {deltaS} ago.");
                }
                else
                {
                    // User is flooding. We should send back a 429 (Too Many Requests) but WCF isn't there yet. Send back a 403 for now.
                    // TODO: Verify this breaks the client as expected - with an error (cannot upload)
                    // TOOD: Add a better error message on the client for this case
                    string floodingMsg = $"IP: Flooding from IP:({(settings.Debug ? requestIP : obfuscatedIP)}) - last successful request was ({lastDateSendISO}) which was {deltaS} ago.";
                    if (blockWhenFlooding)
                    {
                        logger.Info(floodingMsg);
                        blockRequest = true;
                    }
                    else
                    {
                        // The attribute is marked as log only, so log a warning
                        logger.Warn(floodingMsg);
                    }
                }
            }
            else
            {
                // We haven't seen this IP before, so go ahead and let it through
                logger.Trace($"IP: Unrecognized IP, so allowing request.");
            }

            return(blockRequest);
        }
Beispiel #2
0
        // Find all of the players that have been active within N minutes. Return their UserInfos keyed by system name
        private static Dictionary <string, List <UserInfo> > GetSystemsWithActivePlayers(int numSystems)
        {
            PersistentMapAPI.Settings settings = Helper.LoadSettings();
            DateTime now = DateTime.UtcNow;
            Dictionary <string, List <UserInfo> > playersBySystem = Holder.connectionStore
                                                                    .AsParallel()
                                                                    .Where(x => x.Value.LastDataSend.AddMinutes(settings.MinutesForActive) > now)
                                                                    .AsSequential()
                                                                    .GroupBy(p => p.Value.lastSystemFoughtAt)
                                                                    .ToDictionary(p => p.Key, p => p.Select(g => g.Value).ToList());

            logger.Trace($"Mapped players to { playersBySystem.Keys.Count} systems.");

            return(playersBySystem);
        }
Beispiel #3
0
        public void Intercept(IInvocation invocation)
        {
            bool preventMethodInvocation = false;

            foreach (System.Attribute attribute in invocation.GetConcreteMethod().GetCustomAttributes(false))
            {
                if (attribute.GetType() == typeof(AdminKeyRequiredAttribute))
                {
                    // Method is decorated
                    var settings   = Helper.LoadSettings();
                    var properties = OperationContext.Current.IncomingMessageProperties;
                    var property   = properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
                    WebHeaderCollection headers = property.Headers;
                    var headerValue             = headers != null && headers.Get(AdminKeyRequiredAttribute.HeaderName) != null?
                                                  headers.Get(AdminKeyRequiredAttribute.HeaderName) : "";

                    if (!headerValue.Equals(settings.AdminKey))
                    {
                        // Header value doesn't match, block access. Otherwise, let it through
                        preventMethodInvocation = true;
                    }
                }
            }
            if (preventMethodInvocation)
            {
                // Prevent the method from executing
                WebOperationContext context = WebOperationContext.Current;
                context.OutgoingResponse.StatusCode        = HttpStatusCode.Forbidden;
                context.OutgoingResponse.StatusDescription = $"Access denied.";
                invocation.ReturnValue = null;

                IncomingWebRequestContext requestContext = WebOperationContext.Current.IncomingRequest;
                string serviceMethod = requestContext.UriTemplateMatch != null?requestContext.UriTemplateMatch.Data.ToString() : "UNMAPPED";

                string requestIP    = Helper.MapRequestIP();
                string obfuscatedIP = Helper.HashAndTruncate(requestIP);
                PersistentMapAPI.Settings settings = Helper.LoadSettings();
                logger.Warn($"Prevented unauthorized access from ({( settings.Debug ? requestIP : obfuscatedIP )}) to method {serviceMethod}");
            }
            else
            {
                // Allow the method to execute normally
                invocation.Proceed();
            }
        }