summaryrefslogtreecommitdiffstats
path: root/TwoStepsAuthenticator.DotnetCore/UsedCodesManager.cs
blob: 3b21e35645c8ffc2d9c0461b4efc110d0a386a53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using System;
using System.Collections.Generic;
using System.Threading;

namespace TwoStepsAuthenticator
{
    public class UsedCodesManager : IUsedCodesManager
    {
        internal sealed class UsedCode
        {
            public UsedCode(long timestamp, String code, object user)
            {
                this.UseDate = DateTime.Now;
                this.Code = code;
                this.Timestamp = timestamp;
                this.User = user;
            }

            internal DateTime UseDate { get; private set; }
            internal long Timestamp { get; private set; }
            internal String Code { get; private set; }
            internal object User { get; private set; }

            public override bool Equals(object obj)
            {
                if (Object.ReferenceEquals(this, obj))
                {
                    return true;
                }

                var other = obj as UsedCode;
                return (other != null) && this.Code.Equals(other.Code) && this.Timestamp.Equals(other.Timestamp) && this.User.Equals(other.User);
            }
            public override string ToString()
            {
                return String.Format("{0}: {1}", Timestamp, Code);
            }
            public override int GetHashCode()
            {
                return Code.GetHashCode() + (Timestamp.GetHashCode() + User.GetHashCode() * 17) * 17;
            }
        }

        private readonly Queue<UsedCode> codes;
        private readonly System.Threading.ReaderWriterLockSlim rwlock = new System.Threading.ReaderWriterLockSlim();
        private readonly Timer cleaner;

        public UsedCodesManager()
        {
            codes = new Queue<UsedCode>();
            var delay = (int)TimeSpan.FromMinutes(5).TotalMilliseconds;
            cleaner = new Timer(cleaner_Elapsed, null, delay, delay);
        }

        void cleaner_Elapsed(object state)
        {
            var timeToClean = DateTime.Now.AddMinutes(-5);

            try
            {
                rwlock.EnterWriteLock();

                while (codes.Count > 0 && codes.Peek().UseDate < timeToClean)
                {
                    codes.Dequeue();
                }
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
        }

        public void AddCode(long timestamp, String code, object user)
        {
            try
            {
                rwlock.EnterWriteLock();

                codes.Enqueue(new UsedCode(timestamp, code, user));
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
        }

        public bool IsCodeUsed(long timestamp, String code, object user)
        {
            try
            {
                rwlock.EnterWriteLock();

                return codes.Contains(new UsedCode(timestamp, code, user));
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
        }
    }


}