From 9a43fa05ade031c91d515d1254e05fd33cc7a482 Mon Sep 17 00:00:00 2001 From: physcik Date: Mon, 27 Apr 2026 16:52:45 +0500 Subject: Auth middleware + origin check --- backend/src/API/WeaponsAPI.zig | 16 +++++++++++---- backend/src/Database/RangedWeaponsAccessLayer.zig | 9 +++++--- backend/src/Handler.zig | 25 ++++++++++++++++++++++- backend/src/Models/RangedWeapon.zig | 11 +++++++++- 4 files changed, 52 insertions(+), 9 deletions(-) (limited to 'backend') diff --git a/backend/src/API/WeaponsAPI.zig b/backend/src/API/WeaponsAPI.zig index 7c8d72a..101c436 100644 --- a/backend/src/API/WeaponsAPI.zig +++ b/backend/src/API/WeaponsAPI.zig @@ -42,7 +42,9 @@ fn getRangedWeaponById(_: *Handler.RequestData, req: *httpz.Request, res: *httpz try res.json(found, .{}); } -fn newRangedWeapon(_: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { +fn newRangedWeapon(data: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { + try data.CheckAccess(.editor); + var body = try req.json(model.RequestBody) orelse { res.setStatus(.bad_request); return; @@ -63,7 +65,9 @@ fn newRangedWeapon(_: *Handler.RequestData, req: *httpz.Request, res: *httpz.Res res.setStatus(.created); } -fn updateRangedWeapon(_: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { +fn updateRangedWeapon(data: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { + try data.CheckAccess(.editor); + const id = req.param("id") orelse { res.setStatus(.bad_request); return; @@ -85,7 +89,9 @@ fn updateRangedWeapon(_: *Handler.RequestData, req: *httpz.Request, res: *httpz. }; } -fn deleteRangedWeapon(_: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { +fn deleteRangedWeapon(data: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { + try data.CheckAccess(.editor); + const id = req.param("id") orelse { res.setStatus(.bad_request); return; @@ -118,7 +124,9 @@ fn getRangedWeaponDescription(_: *Handler.RequestData, req: *httpz.Request, res: try res.json(desc, .{}); } -fn setRangedWeaponDescription(_: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { +fn setRangedWeaponDescription(data: *Handler.RequestData, req: *httpz.Request, res: *httpz.Response) !void { + try data.CheckAccess(.editor); + const id = req.param("id") orelse { res.setStatus(.bad_request); return; diff --git a/backend/src/Database/RangedWeaponsAccessLayer.zig b/backend/src/Database/RangedWeaponsAccessLayer.zig index 6857581..6170a60 100644 --- a/backend/src/Database/RangedWeaponsAccessLayer.zig +++ b/backend/src/Database/RangedWeaponsAccessLayer.zig @@ -46,8 +46,9 @@ pub fn Update(displayName: []const u8, updatedModel: *model.RangedWeaponType) !v \\ number_of_shots = $9, \\ rate_of_fire = $10, \\ reliability = $11, + \\ origin = $12, \\ updated_at = CURRENT_TIMESTAMP - \\ WHERE id = $12 + \\ WHERE id = $13 ; _ = try conn.pool.exec(query, .{ @@ -62,6 +63,7 @@ pub fn Update(displayName: []const u8, updatedModel: *model.RangedWeaponType) !v updatedModel.NumberOfShots, updatedModel.RateOfFire, updatedModel.Reliability, + updatedModel.Origin, displayName, }); } @@ -70,9 +72,9 @@ pub fn Create(NewWeapon: *model.RangedWeaponType) !void { if (try Exists(NewWeapon.Id)) return conn.ResultErrors.AlreadyExists; const query = \\ INSERT INTO RangedWeapons - \\ (id, name, weapon_type, accuracy, concealability, availability, damage, ammunition, number_of_shots, rate_of_fire, reliability) + \\ (id, name, weapon_type, accuracy, concealability, availability, damage, ammunition, number_of_shots, rate_of_fire, reliability, origin) \\ VALUES - \\ ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) + \\ ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) ; _ = try conn.pool.exec(query, .{ @@ -87,6 +89,7 @@ pub fn Create(NewWeapon: *model.RangedWeaponType) !void { NewWeapon.NumberOfShots, NewWeapon.RateOfFire, NewWeapon.Reliability, + NewWeapon.Origin, }); } diff --git a/backend/src/Handler.zig b/backend/src/Handler.zig index 3e40cf8..2f3389e 100644 --- a/backend/src/Handler.zig +++ b/backend/src/Handler.zig @@ -3,6 +3,11 @@ const httpz = @import("httpz"); const userModel = @import("Models/User.zig"); const tokens = @import("Authentication/Tokens.zig"); +pub const errors = error { + Unauthorized, + Forbidden, +}; + pub const RequestData = struct { User: ?userModel.User, @@ -32,13 +37,31 @@ pub const RequestData = struct { if (self.User == null) return false; return self.User.?.Role >= minimalRole; } + + pub fn CheckAccess(self: RequestData, minimalRole: userModel.Role) !void { + if (self.User == null) return errors.Unauthorized; + if (@intFromEnum(self.User.?.Role) < @intFromEnum(minimalRole)) + return errors.Forbidden; + } }; pub const Handler = struct { pub fn dispatch(_: *Handler, action: httpz.Action(*RequestData), req: *httpz.Request, res: *httpz.Response) !void { var data = try RequestData.Init(req); // std.debug.print("Data: {any}\n", .{ data }); - try action(&data, req, res); + action(&data, req, res) catch |err| { + switch (err) { + errors.Forbidden => { + res.setStatus(.forbidden); + }, + errors.Unauthorized => { + res.setStatus(.unauthorized); + }, + else => { + return err; + } + } + }; std.debug.print("{any} {s}: {d}\n", .{req.method, req.url.raw, res.status}); } }; diff --git a/backend/src/Models/RangedWeapon.zig b/backend/src/Models/RangedWeapon.zig index 36e750e..9b65409 100644 --- a/backend/src/Models/RangedWeapon.zig +++ b/backend/src/Models/RangedWeapon.zig @@ -18,6 +18,9 @@ pub const RangedWeaponType = struct { CreatedAt: i64, UpdatedAt: i64, + // The source of the weapom. For example, corebook or an adventure + Origin: []const u8, + pub fn GetCompactNotation(self: *RangedWeaponType, separator: u8) ![]const u8 { var b: [64]u8 = undefined; return try std.fmt.bufPrint(&b, @@ -52,6 +55,7 @@ pub const RangedWeaponType = struct { .Reliability = try row.get([]const u8, 10), .CreatedAt = try row.get(i64, 11), .UpdatedAt = try row.get(i64, 12), + .Origin = try row.get([]const u8, 13), }; } @@ -72,6 +76,7 @@ pub const RangedWeaponType = struct { .Reliability = try allocator.dupe(u8, try row.get([]const u8, 10)), .CreatedAt = try row.get(i64, 11), .UpdatedAt = try row.get(i64, 12), + .Origin = try allocator.dupe(u8, try row.get([]const u8, 13)), }; } @@ -92,6 +97,7 @@ pub const RequestBody = struct { NumberOfShots: u31, RateOfFire: u32, Reliability: []const u8, + Origin: []const u8, pub fn ToModel(this: RequestBody) RangedWeaponType { return RangedWeaponType { @@ -107,7 +113,8 @@ pub const RequestBody = struct { .RateOfFire = this.RateOfFire, .Reliability = this.Reliability, .CreatedAt = 0, - .UpdatedAt = 0 + .UpdatedAt = 0, + .Origin = this.Origin, }; } }; @@ -129,6 +136,7 @@ fn getTestType() RangedWeaponType { .Reliability = "ST", .CreatedAt = 0, .UpdatedAt = 0, + .Origin = "corebook", }; } @@ -153,6 +161,7 @@ test "Request to model" { .NumberOfShots = 8, .RateOfFire = 2, .Reliability = "ST", + .Origin = "corebook" }; const expected = getTestType(); -- cgit v1.3