X-Git-Url: https://gitweb.ps.run/chirp/blobdiff_plain/4440a97c5a3bc8dca03198dbe0d9474978aa8904..HEAD:/src/main.zig
diff --git a/src/main.zig b/src/main.zig
index 7fe3b63..259f3da 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -29,8 +29,11 @@ const User = struct {
id: UserId,
name: Username,
display_name: DisplayName,
+ description: UserDescription,
password_hash: PasswordHash,
+
posts: PostList,
+
following: UserList,
followers: UserList,
@@ -82,6 +85,7 @@ const PostId = enum(u64) { _ };
const Timestamp = i64;
const Username = std.BoundedArray(u8, 32);
const DisplayName = std.BoundedArray(u8, 64);
+const UserDescription = std.BoundedArray(u8, 1024);
const PasswordHash = std.BoundedArray(u8, 128);
const SessionToken = u64;
const CookieValue = std.BoundedArray(u8, 128);
@@ -93,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
@@ -107,28 +111,19 @@ fn reencode(comptime T: type, text: []const u8) !T {
const c = text[idx];
if (c == '+') {
try result.append(' ');
- } else if (c == '%') {
- // special case of ...
- // assume only , no
- if (idx + 6 < text.len and std.mem.eql(u8, text[idx .. idx + 6], "%26%23")) {
- const num_start = idx + 6;
- var num_end = num_start;
- while (num_end < text.len and std.ascii.isDigit(text[num_end])) {
- num_end += 1;
- }
+ } else if (c == '%' and idx + 2 < text.len) {
+ const allow = &[_]u8{ 0x26, 0x23, 0x3b, 0x0a };
- if (num_end + 2 < text.len and
- text[num_end] == '%' and
- text[num_end + 1] == '3' and
- std.ascii.toLower(text[num_end + 2]) == 'b')
- {
- try std.fmt.format(result.writer(), "{s};", .{text[num_start..num_end]});
- idx = num_end + 2;
- continue;
- }
+ const escaped_value = std.fmt.parseUnsigned(u8, text[idx + 1 .. idx + 3], 16) catch continue;
+
+ if (escaped_value == 0x0d) {
+ try std.fmt.format(result.writer(), "
", .{});
+ } else if (std.mem.indexOfScalar(u8, allow, escaped_value) != null) {
+ try std.fmt.format(result.writer(), "{c}", .{escaped_value});
+ } else {
+ try std.fmt.format(result.writer(), "{x};", .{escaped_value});
}
- try std.fmt.format(result.writer(), "{s};", .{text[idx + 1 .. idx + 3]});
idx += 2;
} else {
try result.append(c);
@@ -168,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);
@@ -189,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(),
@@ -223,6 +216,7 @@ const Chirp = struct {
.id = user_id,
.name = username_array,
.display_name = display_name,
+ .description = try UserDescription.init(0),
.password_hash = try hash_password(password),
.posts = try PostList.init(txn),
.following = try UserList.init(txn),
@@ -463,19 +457,15 @@ pub fn Paginate(comptime T: type) type {
it.idx = try parse_enum(T.Base.Key, starting_at_str, 16);
}
- if (it.idx == null) {
- return error.InvalidIterator;
- }
-
return .{
.res = res,
.view = view,
.per_page = per_page,
.it = it,
- .starting_idx = it.idx.?,
+ .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;
@@ -517,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(">{s}>", .{input[0]});
+ } else {
+ try res.write("", .{});
+ }
},
else => {
try res.write("
\\
\\