1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
const std = @import("std");
const httpz = @import("httpz");
const userModel = @import("Models/User.zig");
const tokens = @import("Authentication/Tokens.zig");
pub const authError = error {
Unauthorized,
Forbidden,
};
pub const RequestData = struct {
User: ?userModel.User,
pub fn Init(req: *httpz.Request) !RequestData {
return .{
.User = try getUser(req),
};
}
fn getUser(req: *httpz.Request) !?userModel.User {
const header = req.header("authorization") orelse return null;
const stripped = stripBearerPrefix(header);
const parsed = tokens.GetUserFromToken(req.arena, stripped) catch |err| {
if (err == tokens.errors.NotFound) {
return null;
}
std.debug.print("Failed to parse a user: {any}\n", .{ err });
return err;
} orelse {
return null;
};
return parsed.value;
}
pub fn CanUserAccess(self: RequestData, minimalRole: userModel.Role) bool {
if (self.User == null) return false;
return self.User.?.Role >= minimalRole;
}
/// This function returns an error that is caught by a handler. Add this to
/// the start of the handler to add an auth
pub fn CheckAccess(self: RequestData, minimalRole: userModel.Role) authError!void {
if (self.User == null) return authError.Unauthorized;
if (@intFromEnum(self.User.?.Role) < @intFromEnum(minimalRole))
return authError.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 });
action(&data, req, res) catch |err| {
switch (err) {
authError.Forbidden => {
res.setStatus(.forbidden);
},
authError.Unauthorized => {
res.setStatus(.unauthorized);
},
else => {
return err;
}
}
};
std.debug.print("{any} {s}: {d}\n", .{req.method, req.url.raw, res.status});
}
};
const headerPrefix = "Bearer ";
fn stripBearerPrefix(header: []const u8) []const u8 {
if (std.mem.startsWith(u8, header, headerPrefix)) {
return header[headerPrefix.len..];
}
return header;
}
|