From 98e916ddd159f7181a5030c005269d2b94b3b215 Mon Sep 17 00:00:00 2001 From: jas20202 <99250573+jas20202@users.noreply.github.com> Date: Sat, 24 Feb 2024 14:38:03 +0100 Subject: [PATCH 1/7] implemented login service --- .../Context/IApplicationEnvironment.cs | 4 +- .../Services/Interfaces/ILoginService.cs | 5 +++ PWManager.CLI/Abstractions/CliEnvironment.cs | 6 +-- PWManager.Data/Repositories/UserRepository.cs | 7 +++- PWManager.Data/Services/LoginService.cs | 39 +++++++++++++++++++ PWManager.Domain/Exceptions/LoginException.cs | 10 +++++ .../Repositories/IUserRepository.cs | 2 +- 7 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 PWManager.Application/Services/Interfaces/ILoginService.cs create mode 100644 PWManager.Data/Services/LoginService.cs create mode 100644 PWManager.Domain/Exceptions/LoginException.cs diff --git a/PWManager.Application/Context/IApplicationEnvironment.cs b/PWManager.Application/Context/IApplicationEnvironment.cs index 36ba374..85a6647 100644 --- a/PWManager.Application/Context/IApplicationEnvironment.cs +++ b/PWManager.Application/Context/IApplicationEnvironment.cs @@ -10,7 +10,7 @@ public interface IApplicationEnvironment { public User? CurrentUser { get; set; } - public string? CurrentGroup { get; set; } + public Group? CurrentGroup { get; set; } - public string? EncryptionKey { get; init; } + public string? EncryptionKey { get; set; } } \ No newline at end of file diff --git a/PWManager.Application/Services/Interfaces/ILoginService.cs b/PWManager.Application/Services/Interfaces/ILoginService.cs new file mode 100644 index 0000000..d547fc9 --- /dev/null +++ b/PWManager.Application/Services/Interfaces/ILoginService.cs @@ -0,0 +1,5 @@ +namespace PWManager.Application.Services.Interfaces { + public interface ILoginService { + public void Login(string username, string password, string dbPath); + } +} diff --git a/PWManager.CLI/Abstractions/CliEnvironment.cs b/PWManager.CLI/Abstractions/CliEnvironment.cs index 63d51dc..9a75426 100644 --- a/PWManager.CLI/Abstractions/CliEnvironment.cs +++ b/PWManager.CLI/Abstractions/CliEnvironment.cs @@ -8,11 +8,11 @@ public class CliEnvironment : IApplicationEnvironment { public bool IsDevelopmentMode { get; init; } = true; public bool RunningSession { get; set; } = false; - public string Prompt => $"{CurrentUser.UserName} ({CurrentGroup}) $"; + public string Prompt => $"{CurrentUser.UserName} ({CurrentGroup.Identifier}) $"; public User? CurrentUser { get; set; } - public string? CurrentGroup { get; set; } + public Group? CurrentGroup { get; set; } - public string? EncryptionKey { get; init; } + public string? EncryptionKey { get; set; } } \ No newline at end of file diff --git a/PWManager.Data/Repositories/UserRepository.cs b/PWManager.Data/Repositories/UserRepository.cs index 2480b3d..e67f84c 100644 --- a/PWManager.Data/Repositories/UserRepository.cs +++ b/PWManager.Data/Repositories/UserRepository.cs @@ -34,11 +34,14 @@ public User AddUser(string username, string password) { return UserModelToEntity(userModel); } - public bool CheckPasswordAttempt(string username, string password) { + public User CheckPasswordAttempt(string username, string password) { var user = _dbContext.Users.First(e => e.UserName == username); var hash = _cryptService.Hash(password, user.Salt); - return hash == user.MasterHash; + if(hash == user.MasterHash) { + return UserModelToEntity(user); + } + return null; } private User UserModelToEntity(UserModel e) { diff --git a/PWManager.Data/Services/LoginService.cs b/PWManager.Data/Services/LoginService.cs new file mode 100644 index 0000000..6c46e30 --- /dev/null +++ b/PWManager.Data/Services/LoginService.cs @@ -0,0 +1,39 @@ +using PWManager.Application.Context; +using PWManager.Application.Services.Interfaces; +using PWManager.Domain.Exceptions; +using PWManager.Domain.Repositories; +using PWManager.Domain.Services.Interfaces; + +namespace PWManager.Data.Services { + public class LoginService : ILoginService { + + private readonly IUserRepository _userRepository; + private readonly IGroupRepository _groupRepository; + private readonly ISettingsRepository _settingsRepository; + private readonly ICryptService _cryptService; + private readonly IApplicationEnvironment _env; + + public LoginService(IUserRepository userRepository, IGroupRepository groupRepository, ICryptService cryptService, ISettingsRepository settingsRepository, IApplicationEnvironment env) { + _userRepository = userRepository; + _groupRepository = groupRepository; + _settingsRepository = settingsRepository; + _cryptService = cryptService; + _env = env; + } + public void Login(string username, string password, string dbPath) { + // TODO: Check if DB exists + DataContext.InitDataContext(dbPath); + + var user = _userRepository.CheckPasswordAttempt(username, password); + if(user is null) { + throw new LoginException("No such user found."); + } + + _env.CurrentUser = user; + _env.EncryptionKey = _cryptService.DeriveKeyFrom(password, username); + + var mainGroup = _settingsRepository.GetSettings().MainGroup; + _env.CurrentGroup = _groupRepository.GetGroup(mainGroup.MainGroupIdentifier); + } + } +} diff --git a/PWManager.Domain/Exceptions/LoginException.cs b/PWManager.Domain/Exceptions/LoginException.cs new file mode 100644 index 0000000..49a5fa1 --- /dev/null +++ b/PWManager.Domain/Exceptions/LoginException.cs @@ -0,0 +1,10 @@ +using System.Runtime.Serialization; + +namespace PWManager.Domain.Exceptions { + public class LoginException : Exception { + public LoginException() { } + protected LoginException(SerializationInfo info, StreamingContext context) : base(info, context) { } + public LoginException(string? message) : base(message) { } + public LoginException(string? message, Exception? innerException) : base(message, innerException) { } + } +} diff --git a/PWManager.Domain/Repositories/IUserRepository.cs b/PWManager.Domain/Repositories/IUserRepository.cs index 671cd9d..1c57398 100644 --- a/PWManager.Domain/Repositories/IUserRepository.cs +++ b/PWManager.Domain/Repositories/IUserRepository.cs @@ -3,6 +3,6 @@ namespace PWManager.Domain.Repositories { public interface IUserRepository { public User AddUser(string username, string password); - public bool CheckPasswordAttempt(string username, string password); + public User CheckPasswordAttempt(string username, string password); } } \ No newline at end of file From 7daa8a67fb1798fe91d3ac20d36b20470e167b2c Mon Sep 17 00:00:00 2001 From: jas20202 <99250573+jas20202@users.noreply.github.com> Date: Sat, 24 Feb 2024 16:32:27 +0100 Subject: [PATCH 2/7] created controller --- PWManager.CLI/Controllers/LoginController.cs | 85 +++++++++++++++++++ .../ExtensionMethods/RunnerExtensions.cs | 2 + PWManager.Data/DependencyInjection.cs | 3 + PWManager.Data/Services/LoginService.cs | 2 +- 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 PWManager.CLI/Controllers/LoginController.cs diff --git a/PWManager.CLI/Controllers/LoginController.cs b/PWManager.CLI/Controllers/LoginController.cs new file mode 100644 index 0000000..10c3142 --- /dev/null +++ b/PWManager.CLI/Controllers/LoginController.cs @@ -0,0 +1,85 @@ +using PWManager.Application.Context; +using PWManager.Application.Services.Interfaces; +using PWManager.CLI.Abstractions; +using PWManager.CLI.Enums; +using PWManager.CLI.Interfaces; +using Sharprompt; + +namespace PWManager.CLI.Controllers { + public class LoginController : IController { + private readonly IApplicationEnvironment _env; + private readonly ILoginService _loginService; + public LoginController(IApplicationEnvironment env, ILoginService loginService) { + _env = env; + _loginService = loginService; + } + public ExitCondition Handle(string[] args) { + if (_env.RunningSession) { + throw new Exception("Command not available in a session!"); + // TODO: change to UserFeedbackException + } + + string username = ""; + string path = ""; + + int basepointer = 0; + while(basepointer < args.Length) { + if ((args[basepointer].Equals("-u") || args[basepointer].Equals("--username"))) { + if ((args.Length - basepointer <= 1) || args[basepointer + 1].StartsWith('-')) { + username = Prompt.Input("Please enter your username"); + } else { + username = args[basepointer + 1]; + basepointer++; + } + } + else if ((args[basepointer].Equals("-d") || args[basepointer].Equals("--directory"))) { + if ((args.Length - basepointer <= 1) || args[basepointer + 1].StartsWith('-')) { + path = Prompt.Input("Please enter the location of your databasefile"); + } else { + path = args[basepointer + 1]; + basepointer++; + } + } + basepointer++; + } + + var lastUser = ReadDefaultFile(); + if (String.IsNullOrWhiteSpace(username)) { + username = lastUser.Split('\n')[0]; + } + if (String.IsNullOrWhiteSpace(path)) { + path = lastUser.Split('\n')[1]; + } + + var pass = Prompt.Password("Enter your password"); + _loginService.Login(username, pass, path); + + WriteDefaultFile(username, path); + + Console.WriteLine($"Welcome {username} :)"); + return ExitCondition.CONTINUE; + } + + private string ReadDefaultFile() { + var defaultFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); + + try { + return File.ReadAllText(Path.Combine(defaultFilePath, "last.txt")); + } catch (IOException e) { + throw new Exception("The file could not be read"); + // TODO: throw new UserFeedbackException + } + } + private void WriteDefaultFile(string username, string path) { + var defaultFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); + + try { + File.WriteAllText(Path.Combine(defaultFilePath, "last.txt"), username + '\n' + path); + } catch (IOException e) { + throw new Exception("The file could not be written"); + // TODO: change to UserFeedbackException + } + } + + } +} diff --git a/PWManager.CLI/ExtensionMethods/RunnerExtensions.cs b/PWManager.CLI/ExtensionMethods/RunnerExtensions.cs index 28c2c80..c7a1ee8 100644 --- a/PWManager.CLI/ExtensionMethods/RunnerExtensions.cs +++ b/PWManager.CLI/ExtensionMethods/RunnerExtensions.cs @@ -9,9 +9,11 @@ internal static class RunnerExtensions { public static void AddControllers(this IServiceCollection services) { services.AddTransient(); + services.AddTransient(); } public static void MapControllers(this ConsoleRunner runner) { runner.MapCommand(AvailableCommands.HELP); + runner.MapCommand(AvailableCommands.LOGIN); } } \ No newline at end of file diff --git a/PWManager.Data/DependencyInjection.cs b/PWManager.Data/DependencyInjection.cs index b006b31..d3bdf5f 100644 --- a/PWManager.Data/DependencyInjection.cs +++ b/PWManager.Data/DependencyInjection.cs @@ -1,5 +1,7 @@ using Microsoft.Extensions.DependencyInjection; +using PWManager.Application.Services.Interfaces; using PWManager.Data.Repositories; +using PWManager.Data.Services; using PWManager.Domain.Repositories; namespace PWManager.Data; @@ -11,6 +13,7 @@ public static IServiceCollection AddDataServices(this IServiceCollection service services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); return services; } } \ No newline at end of file diff --git a/PWManager.Data/Services/LoginService.cs b/PWManager.Data/Services/LoginService.cs index 6c46e30..0bc383f 100644 --- a/PWManager.Data/Services/LoginService.cs +++ b/PWManager.Data/Services/LoginService.cs @@ -26,7 +26,7 @@ public void Login(string username, string password, string dbPath) { var user = _userRepository.CheckPasswordAttempt(username, password); if(user is null) { - throw new LoginException("No such user found."); + throw new LoginException("No such user found."); // TODO: Change with UserFeedbackException } _env.CurrentUser = user; From ac5c51f0353b62b498d6bbf4e51a4fd962e0bc26 Mon Sep 17 00:00:00 2001 From: jas20202 <99250573+jas20202@users.noreply.github.com> Date: Sat, 24 Feb 2024 16:38:00 +0100 Subject: [PATCH 3/7] fixed exceptions --- PWManager.CLI/Controllers/LoginController.cs | 10 ++++------ PWManager.Data/Services/LoginService.cs | 8 ++++++-- PWManager.Domain/Exceptions/LoginException.cs | 10 ---------- 3 files changed, 10 insertions(+), 18 deletions(-) delete mode 100644 PWManager.Domain/Exceptions/LoginException.cs diff --git a/PWManager.CLI/Controllers/LoginController.cs b/PWManager.CLI/Controllers/LoginController.cs index 10c3142..30ed074 100644 --- a/PWManager.CLI/Controllers/LoginController.cs +++ b/PWManager.CLI/Controllers/LoginController.cs @@ -1,4 +1,5 @@ using PWManager.Application.Context; +using PWManager.Application.Exceptions; using PWManager.Application.Services.Interfaces; using PWManager.CLI.Abstractions; using PWManager.CLI.Enums; @@ -15,8 +16,7 @@ public LoginController(IApplicationEnvironment env, ILoginService loginService) } public ExitCondition Handle(string[] args) { if (_env.RunningSession) { - throw new Exception("Command not available in a session!"); - // TODO: change to UserFeedbackException + throw new UserFeedbackException("Command not available in a session!"); } string username = ""; @@ -66,8 +66,7 @@ private string ReadDefaultFile() { try { return File.ReadAllText(Path.Combine(defaultFilePath, "last.txt")); } catch (IOException e) { - throw new Exception("The file could not be read"); - // TODO: throw new UserFeedbackException + throw new UserFeedbackException("The file could not be read"); } } private void WriteDefaultFile(string username, string path) { @@ -76,8 +75,7 @@ private void WriteDefaultFile(string username, string path) { try { File.WriteAllText(Path.Combine(defaultFilePath, "last.txt"), username + '\n' + path); } catch (IOException e) { - throw new Exception("The file could not be written"); - // TODO: change to UserFeedbackException + throw new UserFeedbackException("The file could not be written"); } } diff --git a/PWManager.Data/Services/LoginService.cs b/PWManager.Data/Services/LoginService.cs index 0bc383f..6e37e95 100644 --- a/PWManager.Data/Services/LoginService.cs +++ b/PWManager.Data/Services/LoginService.cs @@ -1,4 +1,5 @@ using PWManager.Application.Context; +using PWManager.Application.Exceptions; using PWManager.Application.Services.Interfaces; using PWManager.Domain.Exceptions; using PWManager.Domain.Repositories; @@ -21,12 +22,15 @@ public LoginService(IUserRepository userRepository, IGroupRepository groupReposi _env = env; } public void Login(string username, string password, string dbPath) { - // TODO: Check if DB exists + if(!DataContext.DatabaseExists(dbPath)) { + throw new UserFeedbackException("Database not found."); + } + DataContext.InitDataContext(dbPath); var user = _userRepository.CheckPasswordAttempt(username, password); if(user is null) { - throw new LoginException("No such user found."); // TODO: Change with UserFeedbackException + throw new UserFeedbackException("No such user found."); } _env.CurrentUser = user; diff --git a/PWManager.Domain/Exceptions/LoginException.cs b/PWManager.Domain/Exceptions/LoginException.cs deleted file mode 100644 index 49a5fa1..0000000 --- a/PWManager.Domain/Exceptions/LoginException.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Runtime.Serialization; - -namespace PWManager.Domain.Exceptions { - public class LoginException : Exception { - public LoginException() { } - protected LoginException(SerializationInfo info, StreamingContext context) : base(info, context) { } - public LoginException(string? message) : base(message) { } - public LoginException(string? message, Exception? innerException) : base(message, innerException) { } - } -} From bdd472c9638b16011b13d70817d2ee9a28979373 Mon Sep 17 00:00:00 2001 From: jas20202 <99250573+jas20202@users.noreply.github.com> Date: Sat, 24 Feb 2024 16:45:22 +0100 Subject: [PATCH 4/7] filehandling ausgelagert --- .../Abstractions/ConfigFileHandler.cs | 24 +++++++++++++++++ PWManager.CLI/Controllers/InitController.cs | 2 ++ PWManager.CLI/Controllers/LoginController.cs | 27 +++---------------- 3 files changed, 30 insertions(+), 23 deletions(-) create mode 100644 PWManager.CLI/Abstractions/ConfigFileHandler.cs diff --git a/PWManager.CLI/Abstractions/ConfigFileHandler.cs b/PWManager.CLI/Abstractions/ConfigFileHandler.cs new file mode 100644 index 0000000..95308ce --- /dev/null +++ b/PWManager.CLI/Abstractions/ConfigFileHandler.cs @@ -0,0 +1,24 @@ +using PWManager.Application.Exceptions; + +namespace PWManager.CLI.Abstractions { + public class ConfigFileHandler { + public static string ReadDefaultFile() { + var defaultFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); + + try { + return File.ReadAllText(Path.Combine(defaultFilePath, "last.txt")); + } catch (IOException e) { + throw new UserFeedbackException("The file could not be read"); + } + } + public static void WriteDefaultFile(string username, string path) { + var defaultFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); + + try { + File.WriteAllText(Path.Combine(defaultFilePath, "last.txt"), username + '\n' + path); + } catch (IOException e) { + throw new UserFeedbackException("The file could not be written"); + } + } + } +} diff --git a/PWManager.CLI/Controllers/InitController.cs b/PWManager.CLI/Controllers/InitController.cs index 51ca77f..587e775 100644 --- a/PWManager.CLI/Controllers/InitController.cs +++ b/PWManager.CLI/Controllers/InitController.cs @@ -3,6 +3,7 @@ using PWManager.Application.Context; using PWManager.Application.Exceptions; using PWManager.Application.Services.Interfaces; +using PWManager.CLI.Abstractions; using PWManager.CLI.Enums; using PWManager.CLI.Interfaces; using Sharprompt; @@ -39,6 +40,7 @@ public ExitCondition Handle(string[] args) { } _dbInit.InitDatabase(path, name, password); + ConfigFileHandler.WriteDefaultFile(name, path); Console.WriteLine("Created your database! Enjoy"); return ExitCondition.EXIT; diff --git a/PWManager.CLI/Controllers/LoginController.cs b/PWManager.CLI/Controllers/LoginController.cs index 30ed074..a3a28dd 100644 --- a/PWManager.CLI/Controllers/LoginController.cs +++ b/PWManager.CLI/Controllers/LoginController.cs @@ -43,7 +43,7 @@ public ExitCondition Handle(string[] args) { basepointer++; } - var lastUser = ReadDefaultFile(); + var lastUser = ConfigFileHandler.ReadDefaultFile(); if (String.IsNullOrWhiteSpace(username)) { username = lastUser.Split('\n')[0]; } @@ -54,30 +54,11 @@ public ExitCondition Handle(string[] args) { var pass = Prompt.Password("Enter your password"); _loginService.Login(username, pass, path); - WriteDefaultFile(username, path); - + ConfigFileHandler.WriteDefaultFile(username, path); Console.WriteLine($"Welcome {username} :)"); - return ExitCondition.CONTINUE; - } - - private string ReadDefaultFile() { - var defaultFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); - - try { - return File.ReadAllText(Path.Combine(defaultFilePath, "last.txt")); - } catch (IOException e) { - throw new UserFeedbackException("The file could not be read"); - } - } - private void WriteDefaultFile(string username, string path) { - var defaultFilePath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); - try { - File.WriteAllText(Path.Combine(defaultFilePath, "last.txt"), username + '\n' + path); - } catch (IOException e) { - throw new UserFeedbackException("The file could not be written"); - } + _env.RunningSession = true; + return ExitCondition.CONTINUE; } - } } From 2f32b82f81c30c9f137a643f6d6c99739083ee2a Mon Sep 17 00:00:00 2001 From: jas20202 <99250573+jas20202@users.noreply.github.com> Date: Sat, 24 Feb 2024 17:02:35 +0100 Subject: [PATCH 5/7] hot fixed --- PWManager.Application/PWManager.Application.csproj | 6 ++++++ PWManager.Data/Repositories/SettingsRepository.cs | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/PWManager.Application/PWManager.Application.csproj b/PWManager.Application/PWManager.Application.csproj index 55fcd04..190d3ad 100644 --- a/PWManager.Application/PWManager.Application.csproj +++ b/PWManager.Application/PWManager.Application.csproj @@ -6,6 +6,12 @@ enable + + + + + + diff --git a/PWManager.Data/Repositories/SettingsRepository.cs b/PWManager.Data/Repositories/SettingsRepository.cs index 98839a9..3498170 100644 --- a/PWManager.Data/Repositories/SettingsRepository.cs +++ b/PWManager.Data/Repositories/SettingsRepository.cs @@ -5,6 +5,7 @@ using PWManager.Domain.Repositories; using PWManager.Domain.Services.Interfaces; using PWManager.Domain.ValueObjects; +using System; namespace PWManager.Data.Repositories; @@ -20,14 +21,17 @@ public SettingsRepository(IApplicationEnvironment env, ICryptService cryptServic } public Settings GetSettings() { - var settingsModel = _dbContext.Settings.First(e => e.UserId == _environment.CurrentUser.Id); + var userId = _environment.CurrentUser.Id; + var settingsList = _dbContext.Settings.Where(e => e.UserId == userId).ToList(); + var settingsModel = settingsList.Any() ? settingsList.First() : null; if (settingsModel is null) { settingsModel = new SettingsModel { UserId = _environment.CurrentUser.Id, Id = Guid.NewGuid().ToString(), MainGroupIdentifier = _cryptService.Encrypt("main") }; - UpdateSettings(settingsModel); + _dbContext.Settings.Add(settingsModel); + _dbContext.SaveChanges(); } return SettingsModelToEntity(settingsModel); From def6b82a248e27e81fa8115361f266756aec284a Mon Sep 17 00:00:00 2001 From: jas20202 <99250573+jas20202@users.noreply.github.com> Date: Sat, 24 Feb 2024 18:03:52 +0100 Subject: [PATCH 6/7] created and run unit Tests - all green --- PWManager.CLI/Controllers/LoginController.cs | 50 ++++++----- PWManager.Data/Services/LoginService.cs | 12 ++- .../Cli/LoginControllerTest.cs | 88 +++++++++++++++++++ .../Services/LoginServiceTest.cs | 69 +++++++++++++++ 4 files changed, 197 insertions(+), 22 deletions(-) create mode 100644 PWManager.UnitTests/Cli/LoginControllerTest.cs create mode 100644 PWManager.UnitTests/Services/LoginServiceTest.cs diff --git a/PWManager.CLI/Controllers/LoginController.cs b/PWManager.CLI/Controllers/LoginController.cs index a3a28dd..f23fa9b 100644 --- a/PWManager.CLI/Controllers/LoginController.cs +++ b/PWManager.CLI/Controllers/LoginController.cs @@ -5,6 +5,7 @@ using PWManager.CLI.Enums; using PWManager.CLI.Interfaces; using Sharprompt; +using System.IO; namespace PWManager.CLI.Controllers { public class LoginController : IController { @@ -19,22 +20,42 @@ public ExitCondition Handle(string[] args) { throw new UserFeedbackException("Command not available in a session!"); } + (var username, var path) = ParseArgs(args); + + var lastUser = ConfigFileHandler.ReadDefaultFile(); + if (String.IsNullOrWhiteSpace(username)) { + username = lastUser.Split('\n')[0]; + } + if (String.IsNullOrWhiteSpace(path)) { + path = lastUser.Split('\n')[1]; + } + + var pass = Prompt.Password("Enter your password"); + _loginService.Login(username, pass, path); + + ConfigFileHandler.WriteDefaultFile(username, path); + Console.WriteLine($"Welcome {username} :)"); + + _env.RunningSession = true; + return ExitCondition.CONTINUE; + } + + public (string, string) ParseArgs(string[] args) { string username = ""; string path = ""; int basepointer = 0; - while(basepointer < args.Length) { + while (basepointer < args.Length) { if ((args[basepointer].Equals("-u") || args[basepointer].Equals("--username"))) { if ((args.Length - basepointer <= 1) || args[basepointer + 1].StartsWith('-')) { - username = Prompt.Input("Please enter your username"); + username = AskForInput("Please enter your username"); } else { username = args[basepointer + 1]; basepointer++; } - } - else if ((args[basepointer].Equals("-d") || args[basepointer].Equals("--directory"))) { + } else if ((args[basepointer].Equals("-d") || args[basepointer].Equals("--directory"))) { if ((args.Length - basepointer <= 1) || args[basepointer + 1].StartsWith('-')) { - path = Prompt.Input("Please enter the location of your databasefile"); + path = AskForInput("Please enter the location of your databasefile"); } else { path = args[basepointer + 1]; basepointer++; @@ -43,22 +64,11 @@ public ExitCondition Handle(string[] args) { basepointer++; } - var lastUser = ConfigFileHandler.ReadDefaultFile(); - if (String.IsNullOrWhiteSpace(username)) { - username = lastUser.Split('\n')[0]; - } - if (String.IsNullOrWhiteSpace(path)) { - path = lastUser.Split('\n')[1]; - } - - var pass = Prompt.Password("Enter your password"); - _loginService.Login(username, pass, path); - - ConfigFileHandler.WriteDefaultFile(username, path); - Console.WriteLine($"Welcome {username} :)"); + return (username, path); + } - _env.RunningSession = true; - return ExitCondition.CONTINUE; + public virtual string AskForInput(string prompt) { + return Prompt.Input(prompt); } } } diff --git a/PWManager.Data/Services/LoginService.cs b/PWManager.Data/Services/LoginService.cs index 6e37e95..85798c9 100644 --- a/PWManager.Data/Services/LoginService.cs +++ b/PWManager.Data/Services/LoginService.cs @@ -1,6 +1,7 @@ using PWManager.Application.Context; using PWManager.Application.Exceptions; using PWManager.Application.Services.Interfaces; +using PWManager.Data.Abstraction; using PWManager.Domain.Exceptions; using PWManager.Domain.Repositories; using PWManager.Domain.Services.Interfaces; @@ -14,19 +15,26 @@ public class LoginService : ILoginService { private readonly ICryptService _cryptService; private readonly IApplicationEnvironment _env; + private readonly DataContextWrapper _dataContext; + + internal LoginService(DataContextWrapper wrapper, IUserRepository userRepository, IGroupRepository groupRepository, ICryptService cryptService, ISettingsRepository settingsRepository, IApplicationEnvironment env) : this( + userRepository, groupRepository, cryptService, settingsRepository, env) { + _dataContext = wrapper; + } public LoginService(IUserRepository userRepository, IGroupRepository groupRepository, ICryptService cryptService, ISettingsRepository settingsRepository, IApplicationEnvironment env) { _userRepository = userRepository; _groupRepository = groupRepository; _settingsRepository = settingsRepository; _cryptService = cryptService; _env = env; + _dataContext = new DataContextWrapper(); } public void Login(string username, string password, string dbPath) { - if(!DataContext.DatabaseExists(dbPath)) { + if(!_dataContext.DatabaseExists(dbPath)) { throw new UserFeedbackException("Database not found."); } - DataContext.InitDataContext(dbPath); + _dataContext.InitDataContext(dbPath); var user = _userRepository.CheckPasswordAttempt(username, password); if(user is null) { diff --git a/PWManager.UnitTests/Cli/LoginControllerTest.cs b/PWManager.UnitTests/Cli/LoginControllerTest.cs new file mode 100644 index 0000000..f3ec4d3 --- /dev/null +++ b/PWManager.UnitTests/Cli/LoginControllerTest.cs @@ -0,0 +1,88 @@ +using NSubstitute; +using PWManager.Application.Context; +using PWManager.Application.Services.Interfaces; +using PWManager.CLI.Controllers; +using PWManager.Data.Repositories; +using PWManager.Data.Services; +using PWManager.Domain.Entities; +using PWManager.Domain.Repositories; +using PWManager.Domain.ValueObjects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PWManager.UnitTests.Cli { + public class LoginControllerTest { + + private LoginController _sut; + + public LoginControllerTest() + { + _sut = Substitute.ForPartsOf(null, null); + _sut.AskForInput(Arg.Any()).Returns("Test"); + } + + [Fact] + public void Arguments_ShouldBe_Empty_WithoutArgs() { + string[] args = { }; + + (var username, var path) = _sut.ParseArgs(args); + + Assert.Equal(0, username.Length); + Assert.Equal(0, path.Length); + } + + [Fact] + public void Arguments_Should_Return_Path() { + string[] args = { "-d", "TestPath" }; + + (var username, var path) = _sut.ParseArgs(args); + + Assert.Equal(0, username.Length); + Assert.Equal("TestPath", path); + } + + [Fact] + public void Arguments_Should_Return_Username() { + string[] args = { "-u", "TestUserName" }; + + (var username, var path) = _sut.ParseArgs(args); + + Assert.Equal("TestUserName", username); + Assert.Equal(0, path.Length); + } + + + [Fact] + public void Arguments_Should_Return_Path_And_PromptName() { + string[] args = { "-d", "TestPath", "-u" }; + + (var username, var path) = _sut.ParseArgs(args); + + Assert.Equal("Test", username); + Assert.Equal("TestPath", path); + } + + [Fact] + public void Arguments_Should_Return_Username_And_PromptPath() { + string[] args = { "-d", "-u", "TestUserName" }; + + (var username, var path) = _sut.ParseArgs(args); + + Assert.Equal("TestUserName", username); + Assert.Equal("Test", path); + } + + [Fact] + public void Arguments_Should_Return_From_Prompts() { + string[] args = { "-d", "-u" }; + + (var username, var path) = _sut.ParseArgs(args); + + Assert.Equal("Test", username); + Assert.Equal("Test", path); + } + } +} diff --git a/PWManager.UnitTests/Services/LoginServiceTest.cs b/PWManager.UnitTests/Services/LoginServiceTest.cs new file mode 100644 index 0000000..e238825 --- /dev/null +++ b/PWManager.UnitTests/Services/LoginServiceTest.cs @@ -0,0 +1,69 @@ +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using PWManager.Application.Context; +using PWManager.Application.Exceptions; +using PWManager.Data.Abstraction; +using PWManager.Data.Services; +using PWManager.Domain.Entities; +using PWManager.Domain.Repositories; +using PWManager.Domain.Services.Interfaces; +using PWManager.Domain.ValueObjects; + +namespace PWManager.UnitTests.Services { + public class LoginServiceTest { + + private LoginService _sut; + private IGroupRepository _groupRepo = Substitute.For(); + private ICryptService _cryptService = Substitute.For(); + private ISettingsRepository _settingsRepository = Substitute.For(); + private DataContextWrapper _wrapper = Substitute.For(); + private IApplicationEnvironment _env = Substitute.For(); + private IUserRepository _userRepo = Substitute.For(); + + [Fact] + public void Login_Should_SetEnviroment() { + _wrapper.DatabaseExists(Arg.Any()).Returns(true); + var user = new User(Guid.NewGuid().ToString(), DateTimeOffset.Now, DateTimeOffset.Now, "TestUserName"); + _userRepo.CheckPasswordAttempt(Arg.Any(), Arg.Any()).Returns(user); + var group = new Group("TestGroup", user.Id); + _settingsRepository.GetSettings().Returns( + new Settings(user.Id, null, null, new MainGroupSetting(group.Identifier)) + ); + _groupRepo.GetGroup(Arg.Any()).Returns(group); + + _sut = new LoginService(_wrapper, _userRepo, _groupRepo, _cryptService, _settingsRepository, _env); + _sut.Login("TestUserName", "WhatAPasswort", "."); + + Assert.Equal(user, _env.CurrentUser); + Assert.NotNull(_env.EncryptionKey); + Assert.NotNull(_env.CurrentGroup); + } + + [Fact] + public void Login_ShouldNot_IfDatabaseDoesntExists() { + _wrapper.DatabaseExists(Arg.Any()).Returns(false); + var user = new User(Guid.NewGuid().ToString(), DateTimeOffset.Now, DateTimeOffset.Now, "TestUserName"); + _userRepo.CheckPasswordAttempt(Arg.Any(), Arg.Any()).Returns(user); + + + _sut = new LoginService(_wrapper, _userRepo, _groupRepo, _cryptService, _settingsRepository, _env); + + var ex = Assert.Throws(() => _sut.Login("TestUserName", "WhatAPassword", ".")); + Assert.Equal("Database not found.", ex.Message); + } + + [Fact] + public void Login_ShouldNot_IfUserNotFound() { + _wrapper.DatabaseExists(Arg.Any()).Returns(true); + var user = new User(Guid.NewGuid().ToString(), DateTimeOffset.Now, DateTimeOffset.Now, "TestUserName"); + _userRepo.CheckPasswordAttempt(Arg.Any(), Arg.Any()).ReturnsNull(); + + + _sut = new LoginService(_wrapper, _userRepo, _groupRepo, _cryptService, _settingsRepository, _env); + + var ex = Assert.Throws(() => _sut.Login("TestUserName", "WhatAPassword", ".")); + Assert.Equal("No such user found.", ex.Message); + } + + } +} From 2abc361c5b069f58b3122be80e2234e110d410aa Mon Sep 17 00:00:00 2001 From: jas20202 <99250573+jas20202@users.noreply.github.com> Date: Sat, 24 Feb 2024 18:19:24 +0100 Subject: [PATCH 7/7] fixes --- PWManager.Application/PWManager.Application.csproj | 6 ------ PWManager.Data/Repositories/UserRepository.cs | 4 ++-- PWManager.Domain/Repositories/IUserRepository.cs | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/PWManager.Application/PWManager.Application.csproj b/PWManager.Application/PWManager.Application.csproj index 190d3ad..55fcd04 100644 --- a/PWManager.Application/PWManager.Application.csproj +++ b/PWManager.Application/PWManager.Application.csproj @@ -6,12 +6,6 @@ enable - - - - - - diff --git a/PWManager.Data/Repositories/UserRepository.cs b/PWManager.Data/Repositories/UserRepository.cs index 56143a3..e1b64d4 100644 --- a/PWManager.Data/Repositories/UserRepository.cs +++ b/PWManager.Data/Repositories/UserRepository.cs @@ -37,11 +37,11 @@ public User AddUser(string username, string password) { return UserModelToEntity(userModel); } - public User CheckPasswordAttempt(string username, string password) { + public User? CheckPasswordAttempt(string username, string password) { var user = _dbContext.Users.First(e => e.UserName == username); var hash = _cryptService.Hash(password, user.Salt); - if(hash == user.MasterHash) { + if(hash.Equals(user.MasterHash)) { return UserModelToEntity(user); } return null; diff --git a/PWManager.Domain/Repositories/IUserRepository.cs b/PWManager.Domain/Repositories/IUserRepository.cs index 1c57398..311e94a 100644 --- a/PWManager.Domain/Repositories/IUserRepository.cs +++ b/PWManager.Domain/Repositories/IUserRepository.cs @@ -3,6 +3,6 @@ namespace PWManager.Domain.Repositories { public interface IUserRepository { public User AddUser(string username, string password); - public User CheckPasswordAttempt(string username, string password); + public User? CheckPasswordAttempt(string username, string password); } } \ No newline at end of file