diff --git a/Controllers/FilesController.cs b/Controllers/FilesController.cs index d004943..bcf6ea8 100644 --- a/Controllers/FilesController.cs +++ b/Controllers/FilesController.cs @@ -8,9 +8,11 @@ using System.Drawing; using System.Linq.Expressions; using Microsoft.Extensions.Logging; using CarCareTracker.Helper; +using Microsoft.AspNetCore.Authorization; namespace CarCareTracker.Controllers { + [Authorize] public class FilesController : Controller { private readonly ILogger _logger; diff --git a/Controllers/HomeController.cs b/Controllers/HomeController.cs index 029ea5c..b04364f 100644 --- a/Controllers/HomeController.cs +++ b/Controllers/HomeController.cs @@ -8,31 +8,74 @@ using System.Drawing; using System.Linq.Expressions; using Microsoft.Extensions.Logging; using CarCareTracker.Helper; +using Microsoft.AspNetCore.Authorization; namespace CarCareTracker.Controllers { + [Authorize] public class HomeController : Controller { private readonly ILogger _logger; private readonly IVehicleDataAccess _dataAccess; private readonly IFileHelper _fileHelper; + private readonly IConfiguration _config; - public HomeController(ILogger logger, IVehicleDataAccess dataAccess, IFileHelper fileHelper) + public HomeController(ILogger logger, IVehicleDataAccess dataAccess, IFileHelper fileHelper, IConfiguration configuration) { _logger = logger; _dataAccess = dataAccess; _fileHelper = fileHelper; + _config = configuration; } - public IActionResult Index() + public IActionResult Index(string tab = "garage") { - return View(); + return View(model: tab); } public IActionResult Garage() { var vehiclesStored = _dataAccess.GetVehicles(); return PartialView("_GarageDisplay", vehiclesStored); } + public IActionResult Settings() + { + var userConfig = new UserConfig + { + EnableCsvImports = bool.Parse(_config[nameof(UserConfig.EnableCsvImports)]), + UseDarkMode = bool.Parse(_config[nameof(UserConfig.UseDarkMode)]), + UseMPG = bool.Parse(_config[nameof(UserConfig.UseMPG)]), + UseDescending = bool.Parse(_config[nameof(UserConfig.UseDescending)]), + EnableAuth = bool.Parse(_config[nameof(UserConfig.EnableAuth)]) + }; + return PartialView("_Settings", userConfig); + } + [HttpPost] + public IActionResult WriteToSettings(UserConfig userConfig) + { + try + { + var configFileContents = System.IO.File.ReadAllText("userConfig.json"); + var existingUserConfig = System.Text.Json.JsonSerializer.Deserialize(configFileContents); + if (existingUserConfig is not null) + { + //copy over settings that are off limits on the settings page. + userConfig.EnableAuth = existingUserConfig.EnableAuth; + userConfig.UserNameHash = existingUserConfig.UserNameHash; + userConfig.UserPasswordHash = existingUserConfig.UserPasswordHash; + } else + { + userConfig.EnableAuth = false; + userConfig.UserNameHash = string.Empty; + userConfig.UserPasswordHash = string.Empty; + } + System.IO.File.WriteAllText("userConfig.json", System.Text.Json.JsonSerializer.Serialize(userConfig)); + return Json(true); + } catch (Exception ex) + { + _logger.LogError(ex, "Error on saving config file."); + } + return Json(false); + } public IActionResult Privacy() { return View(); diff --git a/Controllers/VehicleController.cs b/Controllers/VehicleController.cs index 2fcfff4..429e8d2 100644 --- a/Controllers/VehicleController.cs +++ b/Controllers/VehicleController.cs @@ -5,9 +5,11 @@ using Microsoft.AspNetCore.Mvc; using CarCareTracker.Helper; using CsvHelper; using System.Globalization; +using Microsoft.AspNetCore.Authorization; namespace CarCareTracker.Controllers { + [Authorize] public class VehicleController : Controller { private readonly ILogger _logger; diff --git a/Middleware/Authen.cs b/Middleware/Authen.cs new file mode 100644 index 0000000..eb9d10d --- /dev/null +++ b/Middleware/Authen.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using System.Security.Claims; +using System.Text.Encodings.Web; + +namespace CarCareTracker.Middleware +{ + public class Authen : AuthenticationHandler + { + private IHttpContextAccessor _httpContext; + private bool enableAuth; + public Authen( + IOptionsMonitor options, + UrlEncoder encoder, + ILoggerFactory logger, + IConfiguration configuration, + IHttpContextAccessor httpContext): base(options, logger, encoder) + { + _httpContext = httpContext; + enableAuth = bool.Parse(configuration["EnableAuth"]); + } + protected override async Task HandleAuthenticateAsync() + { + if (!enableAuth) + { + //generate a fake user ticket to go with it lol. + var appIdentity = new ClaimsIdentity("Custom"); + var userIdentity = new List + { + new(ClaimTypes.Name, "admin") + }; + appIdentity.AddClaims(userIdentity); + AuthenticationTicket ticket = new AuthenticationTicket(new ClaimsPrincipal(appIdentity), this.Scheme.Name); + return AuthenticateResult.Success(ticket); + } else + { + return AuthenticateResult.Fail("Invalid credentials"); + } + } + } +} diff --git a/Models/UserConfig.cs b/Models/UserConfig.cs new file mode 100644 index 0000000..b3cd48c --- /dev/null +++ b/Models/UserConfig.cs @@ -0,0 +1,13 @@ +namespace CarCareTracker.Models +{ + public class UserConfig + { + public bool UseDarkMode { get; set; } + public bool EnableCsvImports { get; set; } + public bool UseMPG { get; set; } + public bool UseDescending { get; set; } + public bool EnableAuth { get; set; } + public string UserNameHash { get; set; } + public string UserPasswordHash { get; set;} + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index a132ec4..d98e43d 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,9 @@ using CarCareTracker.External.Implementations; using CarCareTracker.External.Interfaces; using CarCareTracker.Helper; +using CarCareTracker.Middleware; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; var builder = WebApplication.CreateBuilder(args); @@ -14,13 +17,21 @@ builder.Services.AddSingleton(); builder.Services.AddSingleton(); +//Additional JsonFile +builder.Configuration.AddJsonFile("userConfig.json", optional: true, reloadOnChange: true); + +//Configure Auth +builder.Services.AddHttpContextAccessor(); +builder.Services.AddAuthentication("AuthN").AddScheme("AuthN", opts => { }); +builder.Services.AddAuthorization(options => +{ + options.DefaultPolicy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes("AuthN").RequireAuthenticatedUser().Build(); +}); + var app = builder.Build(); // Configure the HTTP request pipeline. -if (!app.Environment.IsDevelopment()) -{ - app.UseExceptionHandler("/Home/Error"); -} +app.UseExceptionHandler("/Home/Error"); app.UseStaticFiles(); app.UseRouting(); diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index e699de7..03a65eb 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -7,7 +7,7 @@ "ASPNETCORE_ENVIRONMENT": "Development" }, "dotnetRunMessages": true, - "applicationUrl": "http://10.10.2.61:5011" + "applicationUrl": "http://10.10.2.60:5011" }, "IIS Express": { "commandName": "IISExpress", diff --git a/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index b928607..2338393 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -1,4 +1,5 @@ -@{ +@model string +@{ ViewData["Title"] = "LubeLogger"; } @section Scripts { @@ -13,20 +14,20 @@
-
+
-
+
@@ -38,4 +39,8 @@
- \ No newline at end of file + + \ No newline at end of file diff --git a/Views/Home/_Settings.cshtml b/Views/Home/_Settings.cshtml new file mode 100644 index 0000000..e065e74 --- /dev/null +++ b/Views/Home/_Settings.cshtml @@ -0,0 +1,89 @@ +@model UserConfig + +
+
+
Settings
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+
+
About
+
+
+
+
+ +
+

+ Proudly developed in the rural town of Price, Utah by Hargata Softworks. +

+

If you enjoyed using this app, please consider spreading the good word.

+
+
Hometown Shoutout
+
+

+ Do you work remotely and are looking for a new place to call home? Consider looking into the rural Eastern Utah town of Price. Price and Carbon County + has experienced pronounced decline in both population and economic activity within the past decade whereas the rest of the state experienced exponential growth. + It is conveniently located in between Salt Lake City and Moab Utah. Amenities are relatively complete in terms of big box stores and high speed fiber Internet. + Price and its surrounding towns as a whole could really benefit from in-migration. Thank you! +

+
+
+
+
Open Source Dependencies
+
+

+ LubeLogger utilizes open-source dependencies to serve you the best possible user experience, those dependencies are: +

+
    +
  • Bootstrap
  • +
  • Bootstrap-DatePicker
  • +
  • LiteDB
  • +
  • SweetAlert2
  • +
  • CsvHelper
  • +
  • Chart.js
  • +
+
+
+ \ No newline at end of file diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index a14d3c5..e7fdc7c 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -1,7 +1,8 @@  @inject IConfiguration Configuration @{ - var useDarkMode = bool.Parse(Configuration["DarkMode"]); + var useDarkMode = bool.Parse(Configuration["UseDarkMode"]); + var enableCsvImports = bool.Parse(Configuration["EnableCsvImports"]); } @@ -20,6 +21,14 @@ + @await RenderSectionAsync("Scripts", required: false) diff --git a/Views/Vehicle/Index.cshtml b/Views/Vehicle/Index.cshtml index 13dbcaa..6fdd067 100644 --- a/Views/Vehicle/Index.cshtml +++ b/Views/Vehicle/Index.cshtml @@ -14,7 +14,7 @@
-

@($"{Model.Year} {Model.Make} {Model.Model}(License # {Model.LicensePlate})")

+

@($"{Model.Year} {Model.Make} {Model.Model}")@($"(#{Model.LicensePlate})")

diff --git a/Views/Vehicle/_CostMakeUpReport.cshtml b/Views/Vehicle/_CostMakeUpReport.cshtml index 518dfc2..ca66f96 100644 --- a/Views/Vehicle/_CostMakeUpReport.cshtml +++ b/Views/Vehicle/_CostMakeUpReport.cshtml @@ -3,6 +3,7 @@