I'm trying to protect the password login for a website against automated guessing. After too many failed attempts from an IP address, it presents a mandatory CAPTCHA test to the user.The class is supposed to not forgive the source completely after a successful login attempt, and the more failed attempts the more penalties.Are there any logic or lock fails here?public class BruteforceProtector{    const int max_log_per_source = 20;    private ConcurrentDictionary<string, LinkedList<DateTimeOffset>> requests;    public BruteforceProtector()    {        requests = new ConcurrentDictionary<string, LinkedList<DateTimeOffset>>();    }    public bool isBlocked(string source, int limit)    {        LinkedList<DateTimeOffset> list;        var haslist = requests.TryGetValue(source, out list);        if (!haslist)            return false;        lock (list)        {            removeOld(list);            return list.Count > limit;        }    }    public void ForgiveSource(string source)    {        LinkedList<DateTimeOffset> list;        if (!requests.TryGetValue(source, out list))            return;        lock (list)        {            if (list.Count > 0)                list.RemoveLast();        }    }    public void HandleRequest(string source, int limit, out bool blocked)    {        blocked = true;        bool haslist = true;        var list = requests.GetOrAdd(source, (x) =>        {            var newlist = new LinkedList<DateTimeOffset>();            newlist.AddLast(DateTimeOffset.Now);            haslist = false;            return newlist;        });        if (!haslist)        {            blocked = false;            return;        }        else        {            lock (list)            {                list.AddLast(DateTimeOffset.Now);                removeOld(list);                if (list.Count > max_log_per_source)                    list.RemoveFirst();                blocked = list.Count > limit;            }        }    }    private void removeOld(LinkedList<DateTimeOffset> list)    {        if (list.Count < 1)            return;        var oldest = list.First.Value;        while (oldest.AddHours(list.Count) < DateTimeOffset.Now)        {            list.RemoveFirst();            if (list.Count > 0)                oldest = list.First.Value;            else                break;        }    }}
Bruteforce protector class
c#