From 9519bc623baa58afff604a8d5e37ef7aa80df16f Mon Sep 17 00:00:00 2001 From: Robert Marshall Date: Sun, 19 Apr 2020 18:16:42 +0100 Subject: [PATCH] Provide mechanism to validate API keys. Re-organise structure to reflect new responsibility --- .../Controllers/ApiControllerTests.cs | 30 +++++++++++ .../{ => Controllers}/AuthControllerTests.cs | 16 +++--- .../Controllers/ApiController.cs | 21 ++++++++ .../{AuthController.cs => UserController.cs} | 8 +-- src/Robware.Api.Auth/Startup.cs | 10 ++-- .../API/ApiKeyValidatorTests.cs | 52 +++++++++++++++++++ .../{ => Users}/AuthenticatorTests.cs | 4 +- .../{ => Users}/CryoptographyProviderTests.cs | 3 +- .../{ => Users}/TestUser.cs | 4 +- src/Robware.Auth/API/ApiKey.cs | 10 ++++ .../API/ApiKeyNotFoundException.cs | 9 ++++ src/Robware.Auth/API/ApiKeyValidator.cs | 22 ++++++++ src/Robware.Auth/API/IApiKeyValidator.cs | 7 +++ src/Robware.Auth/API/IApiKeys.cs | 7 +++ src/Robware.Auth/{ => Users}/Authenticator.cs | 5 +- .../{ => Users}/CryptographyProvider.cs | 2 +- .../{ => Users}/IAuthenticator.cs | 2 +- .../{ => Users}/ICryptographyProvider.cs | 2 +- src/Robware.Auth/{ => Users}/IUsers.cs | 2 +- src/Robware.Auth/{ => Users}/User.cs | 2 +- .../{ => Users}/UserNotFoundException.cs | 2 +- src/Robware.Data/API/ApiKeyRepository.cs | 43 +++++++++++++++ src/Robware.Data/{ => Users}/DatabaseUser.cs | 6 +-- .../{ => Users}/IDatabaseProvider.cs | 2 +- .../{ => Users}/MySQLDatabaseProvider.cs | 2 +- .../{ => Users}/States/UserState.cs | 2 +- .../{ => Users}/UserRepository.cs | 6 +-- 27 files changed, 245 insertions(+), 36 deletions(-) create mode 100644 src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs rename src/Robware.Api.Auth.Tests/{ => Controllers}/AuthControllerTests.cs (80%) create mode 100644 src/Robware.Api.Auth/Controllers/ApiController.cs rename src/Robware.Api.Auth/Controllers/{AuthController.cs => UserController.cs} (80%) create mode 100644 src/Robware.Auth.Tests/API/ApiKeyValidatorTests.cs rename src/Robware.Auth.Tests/{ => Users}/AuthenticatorTests.cs (96%) rename src/Robware.Auth.Tests/{ => Users}/CryoptographyProviderTests.cs (83%) rename src/Robware.Auth.Tests/{ => Users}/TestUser.cs (68%) create mode 100644 src/Robware.Auth/API/ApiKey.cs create mode 100644 src/Robware.Auth/API/ApiKeyNotFoundException.cs create mode 100644 src/Robware.Auth/API/ApiKeyValidator.cs create mode 100644 src/Robware.Auth/API/IApiKeyValidator.cs create mode 100644 src/Robware.Auth/API/IApiKeys.cs rename src/Robware.Auth/{ => Users}/Authenticator.cs (91%) rename src/Robware.Auth/{ => Users}/CryptographyProvider.cs (93%) rename src/Robware.Auth/{ => Users}/IAuthenticator.cs (84%) rename src/Robware.Auth/{ => Users}/ICryptographyProvider.cs (69%) rename src/Robware.Auth/{ => Users}/IUsers.cs (77%) rename src/Robware.Auth/{ => Users}/User.cs (78%) rename src/Robware.Auth/{ => Users}/UserNotFoundException.cs (84%) create mode 100644 src/Robware.Data/API/ApiKeyRepository.cs rename src/Robware.Data/{ => Users}/DatabaseUser.cs (62%) rename src/Robware.Data/{ => Users}/IDatabaseProvider.cs (75%) rename src/Robware.Data/{ => Users}/MySQLDatabaseProvider.cs (91%) rename src/Robware.Data/{ => Users}/States/UserState.cs (87%) rename src/Robware.Data/{ => Users}/UserRepository.cs (88%) diff --git a/src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs b/src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs new file mode 100644 index 0000000..3a497e7 --- /dev/null +++ b/src/Robware.Api.Auth.Tests/Controllers/ApiControllerTests.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Robware.Api.Auth.Controllers; +using Robware.Auth.API; +using Xunit; + +namespace Robware.Api.Auth.Tests.Controllers { + public class ApiControllerTests { + [Fact] + public async Task Validate_WithValidKey_ReturnsOk() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + apiKeyValidator.Validate("key").Returns(true); + var controller = new ApiController(logger, apiKeyValidator); + (await controller.Validate("key")).Should().BeOfType(); + } + + [Fact] + public async Task Validate_WithInvalidKey_ReturnsUnauthorised() { + var logger = Substitute.For>(); + var apiKeyValidator = Substitute.For(); + apiKeyValidator.Validate("key").Returns(false); + var controller = new ApiController(logger, apiKeyValidator); + (await controller.Validate("key")).Should().BeOfType(); + } + } +} \ No newline at end of file diff --git a/src/Robware.Api.Auth.Tests/AuthControllerTests.cs b/src/Robware.Api.Auth.Tests/Controllers/AuthControllerTests.cs similarity index 80% rename from src/Robware.Api.Auth.Tests/AuthControllerTests.cs rename to src/Robware.Api.Auth.Tests/Controllers/AuthControllerTests.cs index e906a0c..b00d79e 100644 --- a/src/Robware.Api.Auth.Tests/AuthControllerTests.cs +++ b/src/Robware.Api.Auth.Tests/Controllers/AuthControllerTests.cs @@ -5,10 +5,10 @@ using Microsoft.Extensions.Logging; using NSubstitute; using Robware.Api.Auth.Controllers; using Robware.Api.Auth.Models; -using Robware.Auth; +using Robware.Auth.Users; using Xunit; -namespace Robware.Api.Auth.Tests { +namespace Robware.Api.Auth.Tests.Controllers { public class AuthControllerTests { private class TestUser : User { public TestUser(string username, string password) { @@ -19,7 +19,7 @@ namespace Robware.Api.Auth.Tests { [Fact] public async Task Authenticate_WithSuccessfulLoginRequest_ReturnsUser() { - var logger = Substitute.For>(); + var logger = Substitute.For>(); var authenticator = Substitute.For(); authenticator.Authenticate("username", "password").Returns((AuthenticationResult.Success, new TestUser("username", "password"))); @@ -30,13 +30,13 @@ namespace Robware.Api.Auth.Tests { var expectation = new TestUser("username", "password"); - var controller = new AuthController(logger, authenticator); + var controller = new UserController(logger, authenticator); (await controller.Authenticate(request)).Value.Should().BeEquivalentTo(expectation); } [Fact] public async Task Authenticate_WithIncorrectPassword_Returns401() { - var logger = Substitute.For>(); + var logger = Substitute.For>(); var authenticator = Substitute.For(); authenticator.Authenticate("username", "password").Returns((AuthenticationResult.IncorrectPassword, null)); @@ -45,13 +45,13 @@ namespace Robware.Api.Auth.Tests { Password = "password" }; - var controller = new AuthController(logger, authenticator); + var controller = new UserController(logger, authenticator); (await controller.Authenticate(request)).Result.Should().BeOfType(); } [Fact] public async Task Authenticate_WithIncorrectPassword_Returns404() { - var logger = Substitute.For>(); + var logger = Substitute.For>(); var authenticator = Substitute.For(); authenticator.Authenticate("username", "password").Returns((AuthenticationResult.NotFound, null)); @@ -60,7 +60,7 @@ namespace Robware.Api.Auth.Tests { Password = "password" }; - var controller = new AuthController(logger, authenticator); + var controller = new UserController(logger, authenticator); (await controller.Authenticate(request)).Result.Should().BeOfType(); } } diff --git a/src/Robware.Api.Auth/Controllers/ApiController.cs b/src/Robware.Api.Auth/Controllers/ApiController.cs new file mode 100644 index 0000000..db528d2 --- /dev/null +++ b/src/Robware.Api.Auth/Controllers/ApiController.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Robware.Auth.API; + +namespace Robware.Api.Auth.Controllers { + [ApiController] + [Route("[controller]")] + public class ApiController : ControllerBase { + private readonly ILogger _logger; + private readonly IApiKeyValidator _apiKeyValidator; + + public ApiController(ILogger logger, IApiKeyValidator apiKeyValidator) { + _logger = logger; + _apiKeyValidator = apiKeyValidator; + } + + [HttpGet(nameof(Validate))] + public async Task Validate(string key) => await _apiKeyValidator.Validate(key) ? (ActionResult) Ok() : Unauthorized(); + } +} diff --git a/src/Robware.Api.Auth/Controllers/AuthController.cs b/src/Robware.Api.Auth/Controllers/UserController.cs similarity index 80% rename from src/Robware.Api.Auth/Controllers/AuthController.cs rename to src/Robware.Api.Auth/Controllers/UserController.cs index 4ec655b..ba5a51f 100644 --- a/src/Robware.Api.Auth/Controllers/AuthController.cs +++ b/src/Robware.Api.Auth/Controllers/UserController.cs @@ -4,14 +4,16 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Robware.Api.Auth.Models; using Robware.Auth; +using Robware.Auth.Users; namespace Robware.Api.Auth.Controllers { [ApiController] - public class AuthController : ControllerBase { - private readonly ILogger _logger; + [Route("[controller]")] + public class UserController : ControllerBase { + private readonly ILogger _logger; private readonly IAuthenticator _authenticator; - public AuthController(ILogger logger, IAuthenticator authenticator) { + public UserController(ILogger logger, IAuthenticator authenticator) { _logger = logger; _authenticator = authenticator; } diff --git a/src/Robware.Api.Auth/Startup.cs b/src/Robware.Api.Auth/Startup.cs index 3787933..2c47bfa 100644 --- a/src/Robware.Api.Auth/Startup.cs +++ b/src/Robware.Api.Auth/Startup.cs @@ -3,8 +3,10 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Robware.Auth; -using Robware.Data; +using Robware.Auth.API; +using Robware.Auth.Users; +using Robware.Data.API; +using Robware.Data.Users; namespace Robware.Api.Auth { public class Startup { @@ -21,7 +23,9 @@ namespace Robware.Api.Auth { services.AddSingleton() .AddSingleton() .AddSingleton(new MySQLDatabaseProvider(Configuration.GetConnectionString("database"))) - .AddSingleton(); + .AddSingleton() + .AddSingleton() + .AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/Robware.Auth.Tests/API/ApiKeyValidatorTests.cs b/src/Robware.Auth.Tests/API/ApiKeyValidatorTests.cs new file mode 100644 index 0000000..2807f29 --- /dev/null +++ b/src/Robware.Auth.Tests/API/ApiKeyValidatorTests.cs @@ -0,0 +1,52 @@ +using System; +using System.Threading.Tasks; +using FluentAssertions; +using NSubstitute; +using NSubstitute.ExceptionExtensions; +using Robware.Auth.API; +using Xunit; + +namespace Robware.Auth.Tests.API { + public class ApiKeyValidatorTests { + [Fact] + public async Task Validate_WithKeyThatExistsAndIsEnabled_ReturnsTrue() { + var apiKey = new ApiKey { + Name = "Test Key", + IssueTimestamp = new DateTime(2020, 4, 19), + Key = "3c6e0b8a9c15224a8228b9a98ca1531d", + Enabled = true + }; + + var keys = Substitute.For(); + keys.Get("3c6e0b8a9c15224a8228b9a98ca1531d").Returns(apiKey); + + var validator = new ApiKeyValidator(keys); + (await validator.Validate("3c6e0b8a9c15224a8228b9a98ca1531d")).Should().BeTrue(); + } + + [Fact] + public async Task Validate_WithKeyThatExistsAndIsDisabled_ReturnsFalse() { + var apiKey = new ApiKey { + Name = "Test Key", + IssueTimestamp = new DateTime(2020, 4, 19), + Key = "3c6e0b8a9c15224a8228b9a98ca1531d", + Enabled = false + }; + + var keys = Substitute.For(); + keys.Get("3c6e0b8a9c15224a8228b9a98ca1531d").Returns(apiKey); + + var validator = new ApiKeyValidator(keys); + (await validator.Validate("3c6e0b8a9c15224a8228b9a98ca1531d")).Should().BeFalse(); + } + + [Fact] + public async Task Validate_WithKeyThatDoesntExist_ReturnsFalse() { + var keys = Substitute.For(); + keys.Get("3c6e0b8a9c15224a8228b9a98ca1531d").Throws(new ApiKeyNotFoundException("")); + + var validator = new ApiKeyValidator(keys); + (await validator.Validate("3c6e0b8a9c15224a8228b9a98ca1531d")).Should().BeFalse(); + } + } +} \ No newline at end of file diff --git a/src/Robware.Auth.Tests/AuthenticatorTests.cs b/src/Robware.Auth.Tests/Users/AuthenticatorTests.cs similarity index 96% rename from src/Robware.Auth.Tests/AuthenticatorTests.cs rename to src/Robware.Auth.Tests/Users/AuthenticatorTests.cs index 1fa4677..4e8c05f 100644 --- a/src/Robware.Auth.Tests/AuthenticatorTests.cs +++ b/src/Robware.Auth.Tests/Users/AuthenticatorTests.cs @@ -2,10 +2,10 @@ using FluentAssertions; using NSubstitute; using NSubstitute.ExceptionExtensions; -using Robware.Data; +using Robware.Auth.Users; using Xunit; -namespace Robware.Auth.Tests { +namespace Robware.Auth.Tests.Users { public class AuthenticatorTests { [Fact] public async Task Authenticate_ForUserThatExistsWithCorrectPassword_ReturnsOkResultWithUser() { diff --git a/src/Robware.Auth.Tests/CryoptographyProviderTests.cs b/src/Robware.Auth.Tests/Users/CryoptographyProviderTests.cs similarity index 83% rename from src/Robware.Auth.Tests/CryoptographyProviderTests.cs rename to src/Robware.Auth.Tests/Users/CryoptographyProviderTests.cs index e25941c..5dd261b 100644 --- a/src/Robware.Auth.Tests/CryoptographyProviderTests.cs +++ b/src/Robware.Auth.Tests/Users/CryoptographyProviderTests.cs @@ -1,7 +1,8 @@ using FluentAssertions; +using Robware.Auth.Users; using Xunit; -namespace Robware.Auth.Tests { +namespace Robware.Auth.Tests.Users { public class CryoptographyProviderTests { [Fact] public void Encrypt_WithInput_ReturnsHash() { diff --git a/src/Robware.Auth.Tests/TestUser.cs b/src/Robware.Auth.Tests/Users/TestUser.cs similarity index 68% rename from src/Robware.Auth.Tests/TestUser.cs rename to src/Robware.Auth.Tests/Users/TestUser.cs index 691e2a2..6535aee 100644 --- a/src/Robware.Auth.Tests/TestUser.cs +++ b/src/Robware.Auth.Tests/Users/TestUser.cs @@ -1,4 +1,6 @@ -namespace Robware.Auth.Tests { +using Robware.Auth.Users; + +namespace Robware.Auth.Tests.Users { internal class TestUser : User { public TestUser(string username, string password) { Username = username; diff --git a/src/Robware.Auth/API/ApiKey.cs b/src/Robware.Auth/API/ApiKey.cs new file mode 100644 index 0000000..c112453 --- /dev/null +++ b/src/Robware.Auth/API/ApiKey.cs @@ -0,0 +1,10 @@ +using System; + +namespace Robware.Auth.API { + public class ApiKey { + public string Name { get; set; } + public DateTime IssueTimestamp { get; set; } + public string Key { get; set; } + public bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/src/Robware.Auth/API/ApiKeyNotFoundException.cs b/src/Robware.Auth/API/ApiKeyNotFoundException.cs new file mode 100644 index 0000000..0bc8219 --- /dev/null +++ b/src/Robware.Auth/API/ApiKeyNotFoundException.cs @@ -0,0 +1,9 @@ +using System; + +namespace Robware.Auth.API { + public class ApiKeyNotFoundException :Exception { + public ApiKeyNotFoundException(string key) : base("Could not find API key " + key) { + + } + } +} \ No newline at end of file diff --git a/src/Robware.Auth/API/ApiKeyValidator.cs b/src/Robware.Auth/API/ApiKeyValidator.cs new file mode 100644 index 0000000..6da92a0 --- /dev/null +++ b/src/Robware.Auth/API/ApiKeyValidator.cs @@ -0,0 +1,22 @@ +using System; +using System.Threading.Tasks; + +namespace Robware.Auth.API { + public class ApiKeyValidator : IApiKeyValidator { + private readonly IApiKeys _apiKeys; + + public ApiKeyValidator(IApiKeys apiKeys) { + _apiKeys = apiKeys; + } + + public async Task Validate(string key) { + try { + var apiKey = await _apiKeys.Get(key); + return apiKey.Enabled; + } + catch (ApiKeyNotFoundException) { + return false; + } + } + } +} \ No newline at end of file diff --git a/src/Robware.Auth/API/IApiKeyValidator.cs b/src/Robware.Auth/API/IApiKeyValidator.cs new file mode 100644 index 0000000..a8b2c31 --- /dev/null +++ b/src/Robware.Auth/API/IApiKeyValidator.cs @@ -0,0 +1,7 @@ +using System.Threading.Tasks; + +namespace Robware.Auth.API { + public interface IApiKeyValidator { + Task Validate(string key); + } +} \ No newline at end of file diff --git a/src/Robware.Auth/API/IApiKeys.cs b/src/Robware.Auth/API/IApiKeys.cs new file mode 100644 index 0000000..a4a962d --- /dev/null +++ b/src/Robware.Auth/API/IApiKeys.cs @@ -0,0 +1,7 @@ +using System.Threading.Tasks; + +namespace Robware.Auth.API { + public interface IApiKeys { + Task Get(string key); + } +} \ No newline at end of file diff --git a/src/Robware.Auth/Authenticator.cs b/src/Robware.Auth/Users/Authenticator.cs similarity index 91% rename from src/Robware.Auth/Authenticator.cs rename to src/Robware.Auth/Users/Authenticator.cs index 7ee0475..52f22d0 100644 --- a/src/Robware.Auth/Authenticator.cs +++ b/src/Robware.Auth/Users/Authenticator.cs @@ -1,7 +1,6 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; -namespace Robware.Auth { +namespace Robware.Auth.Users { public class Authenticator : IAuthenticator { private readonly IUsers _users; private readonly ICryptographyProvider _crypto; diff --git a/src/Robware.Auth/CryptographyProvider.cs b/src/Robware.Auth/Users/CryptographyProvider.cs similarity index 93% rename from src/Robware.Auth/CryptographyProvider.cs rename to src/Robware.Auth/Users/CryptographyProvider.cs index 57f61a1..2a344aa 100644 --- a/src/Robware.Auth/CryptographyProvider.cs +++ b/src/Robware.Auth/Users/CryptographyProvider.cs @@ -1,7 +1,7 @@ using System.Security.Cryptography; using System.Text; -namespace Robware.Auth { +namespace Robware.Auth.Users { public class CryptographyProvider : ICryptographyProvider { public string Encrypt(string input) { using (var sha256 = SHA256.Create()) { diff --git a/src/Robware.Auth/IAuthenticator.cs b/src/Robware.Auth/Users/IAuthenticator.cs similarity index 84% rename from src/Robware.Auth/IAuthenticator.cs rename to src/Robware.Auth/Users/IAuthenticator.cs index 4718d67..1913957 100644 --- a/src/Robware.Auth/IAuthenticator.cs +++ b/src/Robware.Auth/Users/IAuthenticator.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace Robware.Auth { +namespace Robware.Auth.Users { public interface IAuthenticator { Task<(AuthenticationResult Result, User User)> Authenticate(string username, string password); } diff --git a/src/Robware.Auth/ICryptographyProvider.cs b/src/Robware.Auth/Users/ICryptographyProvider.cs similarity index 69% rename from src/Robware.Auth/ICryptographyProvider.cs rename to src/Robware.Auth/Users/ICryptographyProvider.cs index bb1c3f9..9ddcdc6 100644 --- a/src/Robware.Auth/ICryptographyProvider.cs +++ b/src/Robware.Auth/Users/ICryptographyProvider.cs @@ -1,4 +1,4 @@ -namespace Robware.Auth { +namespace Robware.Auth.Users { public interface ICryptographyProvider { string Encrypt(string input); } diff --git a/src/Robware.Auth/IUsers.cs b/src/Robware.Auth/Users/IUsers.cs similarity index 77% rename from src/Robware.Auth/IUsers.cs rename to src/Robware.Auth/Users/IUsers.cs index b7f8f5a..e2d7ae5 100644 --- a/src/Robware.Auth/IUsers.cs +++ b/src/Robware.Auth/Users/IUsers.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace Robware.Auth { +namespace Robware.Auth.Users { public interface IUsers { Task GetByEmail(string email); } diff --git a/src/Robware.Auth/User.cs b/src/Robware.Auth/Users/User.cs similarity index 78% rename from src/Robware.Auth/User.cs rename to src/Robware.Auth/Users/User.cs index cfb8a65..dd8b7e0 100644 --- a/src/Robware.Auth/User.cs +++ b/src/Robware.Auth/Users/User.cs @@ -1,4 +1,4 @@ -namespace Robware.Auth { +namespace Robware.Auth.Users { public class User { public string Username { get; protected set; } public string Password { get; protected set; } diff --git a/src/Robware.Auth/UserNotFoundException.cs b/src/Robware.Auth/Users/UserNotFoundException.cs similarity index 84% rename from src/Robware.Auth/UserNotFoundException.cs rename to src/Robware.Auth/Users/UserNotFoundException.cs index dde2acb..9a0d981 100644 --- a/src/Robware.Auth/UserNotFoundException.cs +++ b/src/Robware.Auth/Users/UserNotFoundException.cs @@ -1,6 +1,6 @@ using System; -namespace Robware.Auth { +namespace Robware.Auth.Users { public class UserNotFoundException : Exception { public UserNotFoundException(string username) : base("Could not find user " + username) { diff --git a/src/Robware.Data/API/ApiKeyRepository.cs b/src/Robware.Data/API/ApiKeyRepository.cs new file mode 100644 index 0000000..cb03368 --- /dev/null +++ b/src/Robware.Data/API/ApiKeyRepository.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using System.Linq; +using Dapper; +using Robware.Auth.API; +using Robware.Data.Users; + +namespace Robware.Data.API { + public class ApiKeyRepository : IApiKeys { + private readonly IDatabaseProvider _dbProvider; + + public ApiKeyRepository(IDatabaseProvider dbProvider) { + _dbProvider = dbProvider; + } + + public async Task Get(string key) { + const string query = "SELECT * FROM api_keys WHERE api_key=@key"; + + using (var connection = _dbProvider.NewConnection()) { + connection.Open(); + var result = await connection.QueryAsync(query, new {key}); + + if (!result.Any()) + throw new ApiKeyNotFoundException(key); + + var dbKey = result.Single(); + return new ApiKey { + Key = dbKey.Api_Key, + Enabled = dbKey.Enabled, + IssueTimestamp = dbKey.IssueTimestamp, + Name = dbKey.Name + }; + } + } + } + + public class ApiKeyState { + public string Name { get; set; } + public DateTime IssueTimestamp { get; set; } + public string Api_Key { get; set; } + public bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/src/Robware.Data/DatabaseUser.cs b/src/Robware.Data/Users/DatabaseUser.cs similarity index 62% rename from src/Robware.Data/DatabaseUser.cs rename to src/Robware.Data/Users/DatabaseUser.cs index be76924..8a14c0d 100644 --- a/src/Robware.Data/DatabaseUser.cs +++ b/src/Robware.Data/Users/DatabaseUser.cs @@ -1,7 +1,7 @@ -using Robware.Auth; -using Robware.Data.States; +using Robware.Auth.Users; +using Robware.Data.Users.States; -namespace Robware.Data { +namespace Robware.Data.Users { public class DatabaseUser : User { public DatabaseUser(UserState state) { Username = state.User_Email; diff --git a/src/Robware.Data/IDatabaseProvider.cs b/src/Robware.Data/Users/IDatabaseProvider.cs similarity index 75% rename from src/Robware.Data/IDatabaseProvider.cs rename to src/Robware.Data/Users/IDatabaseProvider.cs index a4493e2..7304a7c 100644 --- a/src/Robware.Data/IDatabaseProvider.cs +++ b/src/Robware.Data/Users/IDatabaseProvider.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Robware.Data { +namespace Robware.Data.Users { public interface IDatabaseProvider { IDbConnection NewConnection(); } diff --git a/src/Robware.Data/MySQLDatabaseProvider.cs b/src/Robware.Data/Users/MySQLDatabaseProvider.cs similarity index 91% rename from src/Robware.Data/MySQLDatabaseProvider.cs rename to src/Robware.Data/Users/MySQLDatabaseProvider.cs index 57fdc43..ec6e07d 100644 --- a/src/Robware.Data/MySQLDatabaseProvider.cs +++ b/src/Robware.Data/Users/MySQLDatabaseProvider.cs @@ -1,7 +1,7 @@ using System.Data; using MySql.Data.MySqlClient; -namespace Robware.Data { +namespace Robware.Data.Users { public class MySQLDatabaseProvider : IDatabaseProvider { private readonly string _connectionString; diff --git a/src/Robware.Data/States/UserState.cs b/src/Robware.Data/Users/States/UserState.cs similarity index 87% rename from src/Robware.Data/States/UserState.cs rename to src/Robware.Data/Users/States/UserState.cs index 2dfec41..aa0cbc8 100644 --- a/src/Robware.Data/States/UserState.cs +++ b/src/Robware.Data/Users/States/UserState.cs @@ -1,4 +1,4 @@ -namespace Robware.Data.States { +namespace Robware.Data.Users.States { public class UserState { public string User_Id { get; set; } public string User_Email { get; set; } diff --git a/src/Robware.Data/UserRepository.cs b/src/Robware.Data/Users/UserRepository.cs similarity index 88% rename from src/Robware.Data/UserRepository.cs rename to src/Robware.Data/Users/UserRepository.cs index 4bc391d..b3d41ee 100644 --- a/src/Robware.Data/UserRepository.cs +++ b/src/Robware.Data/Users/UserRepository.cs @@ -1,10 +1,10 @@ using System.Linq; using System.Threading.Tasks; using Dapper; -using Robware.Auth; -using Robware.Data.States; +using Robware.Auth.Users; +using Robware.Data.Users.States; -namespace Robware.Data { +namespace Robware.Data.Users { public class UserRepository : IUsers { private readonly IDatabaseProvider _dbProvider;