using SharedLibraryCore.Helpers; using SharedLibraryCore.Interfaces; using System; using System.Collections.Concurrent; using System.Security.Cryptography; using System.Text; namespace IW4MAdmin.Application.Misc { internal class TokenAuthentication : ITokenAuthentication { private readonly ConcurrentDictionary _tokens; private readonly RandomNumberGenerator _random; private static readonly TimeSpan TimeoutPeriod = new TimeSpan(0, 0, 120); private const short TokenLength = 4; public TokenAuthentication() { _tokens = new ConcurrentDictionary(); _random = RandomNumberGenerator.Create(); } public bool AuthorizeToken(long networkId, string token) { var authorizeSuccessful = _tokens.ContainsKey(networkId) && _tokens[networkId].Token == token; if (authorizeSuccessful) { _tokens.TryRemove(networkId, out _); } return authorizeSuccessful; } public TokenState GenerateNextToken(long networkId) { TokenState state; if (_tokens.ContainsKey(networkId)) { state = _tokens[networkId]; if ((DateTime.Now - state.RequestTime) > TimeoutPeriod) { _tokens.TryRemove(networkId, out _); } else { return state; } } state = new TokenState { NetworkId = networkId, Token = _generateToken(), TokenDuration = TimeoutPeriod }; _tokens.TryAdd(networkId, state); // perform some housekeeping so we don't have built up tokens if they're not ever used foreach (var (key, value) in _tokens) { if ((DateTime.Now - value.RequestTime) > TimeoutPeriod) { _tokens.TryRemove(key, out _); } } return state; } private string _generateToken() { bool ValidCharacter(char c) { // this ensure that the characters are 0-9, A-Z, a-z return (c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123); } var token = new StringBuilder(); var charSet = new byte[1]; while (token.Length < TokenLength) { _random.GetBytes(charSet); if (ValidCharacter((char)charSet[0])) { token.Append((char)charSet[0]); } } _random.Dispose(); return token.ToString(); } } }