X-Git-Url: https://gitweb.ps.run/chirp/blobdiff_plain/b30a60adbaae5f6af46d32b3a45195fd8664662c..d20342bd4fd63a9d098678c4a954c40fe48b7af7:/src/main.zig diff --git a/src/main.zig b/src/main.zig index 9411261..d35221e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -97,7 +97,7 @@ const PostListList = db.List(SavedPostList); const UserListList = db.List(SavedUserList); fn parse_enum(comptime E: type, buf: []const u8, base: u8) !E { - return @enumFromInt(try std.fmt.parseUnsigned(@typeInfo(E).Enum.tag_type, buf, base)); + return @enumFromInt(try std.fmt.parseUnsigned(@typeInfo(E).@"enum".tag_type, buf, base)); } // https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding @@ -163,19 +163,18 @@ fn decode(text: []const u8) !std.BoundedArray(u8, 1024) { const Chirp = struct { const PostsPerPage = 10; const UsersPerPage = 10; + var HashBuffer = std.mem.zeroes([1024 * 1024 * 50]u8); pub fn hash_password(password: []const u8) !PasswordHash { var hash_buffer = try PasswordHash.init(128); // TODO: choose buffer size - // TODO: dont allocate on stack, maybe zero memory? - var buffer: [1024 * 10]u8 = undefined; - var alloc = std.heap.FixedBufferAllocator.init(&buffer); + var alloc = std.heap.FixedBufferAllocator.init(&HashBuffer); // TODO: choose limits const result = try std.crypto.pwhash.argon2.strHash(password, .{ .allocator = alloc.allocator(), - .params = std.crypto.pwhash.argon2.Params.fromLimits(1000, 1024), + .params = std.crypto.pwhash.argon2.Params.owasp_2id, }, hash_buffer.slice()); try hash_buffer.resize(result.len); @@ -184,8 +183,7 @@ const Chirp = struct { } pub fn verify_password(password: []const u8, hash: PasswordHash) bool { - var buffer: [1024 * 10]u8 = undefined; - var alloc = std.heap.FixedBufferAllocator.init(&buffer); + var alloc = std.heap.FixedBufferAllocator.init(&HashBuffer); if (std.crypto.pwhash.argon2.strVerify(hash.constSlice(), password, .{ .allocator = alloc.allocator(), @@ -467,7 +465,7 @@ pub fn Paginate(comptime T: type) type { .starting_idx = it.idx, }; } - pub fn next(self: *Self) IterateResult { + pub fn next(self: *Self) ?IterateResult { if (self.it.next()) |kv| { if (self.count < self.per_page) { self.count += 1; @@ -509,10 +507,16 @@ fn html_form(res: *http.Response, action: []const u8, inputs: anytype) !void { inline for (inputs) |input| { switch (@typeInfo(@TypeOf(input))) { - .Struct => { - try res.write("", .{}); + .@"struct" => |s| { + if (s.fields.len == 3) { + try res.write("<{s} ", .{input[0]}); + try res.write(input[1], input[2]); + try res.write(">", .{input[0]}); + } else { + try res.write("", .{}); + } }, else => { try res.write("{s}{s}", .{ id, name.constSlice(), if (list_view.has(post_id) catch false) " *" else "" }); } try res.write("", .{}); - try res.write("", .{@intFromEnum(post_id)}); - try res.write("", .{}); + try res.write("", .{@intFromEnum(post_id)}); + try res.write("", .{}); try res.write("", .{}); } @@ -780,8 +784,8 @@ fn write_profile(res: *http.Response, txn: lmdb.Txn, logged_in: ?Login, user: Us try res.write("", .{ id, name.constSlice(), if (list_view.has(user.id) catch false) " *" else "" }); } try res.write("", .{}); - try res.write("", .{@intFromEnum(user.id)}); - try res.write("", .{}); + try res.write("", .{@intFromEnum(user.id)}); + try res.write("", .{}); try res.write("", .{}); } try res.write( @@ -963,20 +967,20 @@ const GET = struct { fn handle(self: Self) !bool { const ti = @typeInfo(Self); - inline for (ti.Struct.decls) |f_decl| { + inline for (ti.@"struct".decls) |f_decl| { const has_arg = f_decl.name.len > 1 and f_decl.name[f_decl.name.len - 1] == '/'; const match = if (has_arg) std.mem.startsWith(u8, self.req.target, f_decl.name) else std.mem.eql(u8, self.req.target, f_decl.name); if (match) { const f = @field(Self, f_decl.name); const fi = @typeInfo(@TypeOf(f)); - if (fi.Fn.params.len == 1) { + if (fi.@"fn".params.len == 1) { try @call(.auto, f, .{self}); } else { - const arg_type = fi.Fn.params[1].type.?; + const arg_type = fi.@"fn".params[1].type.?; const arg_info = @typeInfo(arg_type); var arg: arg_type = undefined; - const field = arg_info.Struct.fields[0]; + const field = arg_info.@"struct".fields[0]; if (self.req.target.len <= f_decl.name.len) { return error.NoArgProvided; } @@ -984,10 +988,10 @@ const GET = struct { const field_ti = @typeInfo(field.type); switch (field_ti) { // TODO: maybe handle BoundedArray? - .Int => { + .int => { @field(arg, field.name) = try std.fmt.parseUnsigned(field.type, str, 16); }, - .Enum => { + .@"enum" => { @field(arg, field.name) = try parse_enum(field.type, str, 16); }, else => { @@ -1265,7 +1269,7 @@ const GET = struct { }); try self.res.write("
Description: ", .{}); try html_form(self.res, "/set_description", .{ - .{ "type=\"text\" name=\"description\" placeholder=\"{s}\"", .{login.user.description.constSlice()} }, + .{ "textarea", "type=\"text\" name=\"description\" placeholder=\"{s}\"", .{login.user.description.constSlice()} }, "type=\"submit\" value=\"Change\"", }); try self.res.write("
Password: ", .{}); @@ -1299,24 +1303,24 @@ const POST = struct { pub fn handle(self: Self) !bool { const ti = @typeInfo(Self); - inline for (ti.Struct.decls) |f_decl| { + inline for (ti.@"struct".decls) |f_decl| { if (std.mem.eql(u8, f_decl.name, self.req.target)) { const f = @field(Self, f_decl.name); const fi = @typeInfo(@TypeOf(f)); - if (fi.Fn.params.len == 1) { + if (fi.@"fn".params.len == 1) { _ = try @call(.auto, f, .{self}); } else { - const args_type = fi.Fn.params[fi.Fn.params.len - 1].type.?; + const args_type = fi.@"fn".params[fi.@"fn".params.len - 1].type.?; const argsi = @typeInfo(args_type); var args: args_type = undefined; - inline for (argsi.Struct.fields) |field| { + inline for (argsi.@"struct".fields) |field| { const str = self.req.get_value(field.name) orelse return error.ArgNotFound; const field_ti = @typeInfo(field.type); switch (field_ti) { - .Int => { + .int => { @field(args, field.name) = try std.fmt.parseUnsigned(field.type, str, 16); }, - .Enum => { + .@"enum" => { @field(args, field.name) = try parse_enum(field.type, str, 16); }, else => {