diff --git a/backend/ApplicationState.cs b/backend/ApplicationState.cs index 1fb72ae..447607d 100644 --- a/backend/ApplicationState.cs +++ b/backend/ApplicationState.cs @@ -1,11 +1,10 @@ using MQTTnet.Client; using Microsoft.EntityFrameworkCore; -namespace backend.Application +namespace backend.Application; + +public static class ApplicationState { - public static class ApplicationState - { - public static IMqttClient? MqttClient { get; set; } - public static DispenserContext? DbContext { get; set; } - } + public static IMqttClient? MqttClient { get; set; } + public static DispenserContext? DbContext { get; set; } } diff --git a/backend/Controllers/UserController.cs b/backend/Controllers/UserController.cs index c6a6f14..55caee1 100644 --- a/backend/Controllers/UserController.cs +++ b/backend/Controllers/UserController.cs @@ -4,6 +4,7 @@ using backend.Models; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Identity; using System.Web; +using backend.Middleware; namespace backend.Controllers; @@ -37,6 +38,7 @@ public class UserController : ControllerBase Username = input["username"]!.ToString(), Password = hashedPassword, TouchCode = touchCode, + IsParent = false, }; // Save user @@ -87,13 +89,9 @@ public class UserController : ControllerBase } [HttpPost("Logout")] + [MiddlewareFilter(typeof(AuthenticationMiddlewareBuilder))] public IActionResult LogOut() { - // Validate - if (Request.Cookies["session"] == null) { - return BadRequest("You are not logged in"); - } - // Get user var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.SessionToken == Request.Cookies["session"]!.ToString()); if (user == null) { @@ -110,13 +108,9 @@ public class UserController : ControllerBase } [HttpGet("UserInfo")] + [MiddlewareFilter(typeof(AuthenticationMiddlewareBuilder))] public IActionResult UserInfo() { - // Validate - if (Request.Cookies["session"] == null) { - return BadRequest("You are not logged in"); - } - // Get user var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.SessionToken == Request.Cookies["session"]!.ToString()); if (user == null) { @@ -126,6 +120,7 @@ public class UserController : ControllerBase var data = new { username = user.Username, touchCode = user.TouchCode, + isParent = user.IsParent, }; return new JsonResult(data); diff --git a/backend/Middleware/AuthenticationMiddleware.cs b/backend/Middleware/AuthenticationMiddleware.cs new file mode 100644 index 0000000..0b69289 --- /dev/null +++ b/backend/Middleware/AuthenticationMiddleware.cs @@ -0,0 +1,42 @@ +using backend.Application; + +namespace backend.Middleware; + +public class AuthenticationMiddleware +{ + private readonly RequestDelegate _next; + + public AuthenticationMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + if (context.Request.Cookies["session"] == null) { + context.Response.Clear(); + context.Response.StatusCode = 401; + await context.Response.WriteAsync("You are not logged in"); + return; + } + + var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.SessionToken == context.Request.Cookies["session"]!.ToString()); + if (user == null) { + context.Response.Clear(); + context.Response.StatusCode = 401; + await context.Response.WriteAsync("Invalid session token"); + return; + } + + await _next(context); + } +} + +public class AuthenticationMiddlewareBuilder +{ + public void Configure(IApplicationBuilder app) + { + app.UseMiddleware(); + } +} + diff --git a/backend/Migrations/20231218184746_AddIsParentToUser.Designer.cs b/backend/Migrations/20231218184746_AddIsParentToUser.Designer.cs new file mode 100644 index 0000000..787ad99 --- /dev/null +++ b/backend/Migrations/20231218184746_AddIsParentToUser.Designer.cs @@ -0,0 +1,67 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace backend.Migrations +{ + [DbContext(typeof(DispenserContext))] + [Migration("20231218184746_AddIsParentToUser")] + partial class AddIsParentToUser + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.0"); + + modelBuilder.Entity("backend.Models.DispenserLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("DispenserLogs"); + }); + + modelBuilder.Entity("backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("IsParent") + .HasColumnType("INTEGER"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SessionToken") + .HasColumnType("TEXT"); + + b.Property("TouchCode") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/Migrations/20231218184746_AddIsParentToUser.cs b/backend/Migrations/20231218184746_AddIsParentToUser.cs new file mode 100644 index 0000000..7d1f662 --- /dev/null +++ b/backend/Migrations/20231218184746_AddIsParentToUser.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace backend.Migrations +{ + /// + public partial class AddIsParentToUser : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsParent", + table: "Users", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsParent", + table: "Users"); + } + } +} diff --git a/backend/Migrations/DispenserContextModelSnapshot.cs b/backend/Migrations/DispenserContextModelSnapshot.cs index 5b0fb43..a260f48 100644 --- a/backend/Migrations/DispenserContextModelSnapshot.cs +++ b/backend/Migrations/DispenserContextModelSnapshot.cs @@ -36,6 +36,9 @@ namespace backend.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("IsParent") + .HasColumnType("INTEGER"); + b.Property("Password") .IsRequired() .HasColumnType("TEXT"); diff --git a/backend/Models/User.cs b/backend/Models/User.cs index 9b29242..1d6cef9 100644 --- a/backend/Models/User.cs +++ b/backend/Models/User.cs @@ -13,4 +13,5 @@ public class User public string Password { get; set; } public string TouchCode { get; set; } public string? SessionToken { get; set; } + public bool IsParent { get; set; } } diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 6826d73..34866b9 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -15,6 +15,9 @@ async function dispense() {

Welcome back, {{ userStore.state.userInfo.username }}


+

+

Your touch code is: {{ userStore.state.userInfo.touchCode }}

+

Use this code to login on the dispenser