╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────╮ │src/event/Repo.zig│ ╰──────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │127 │ │128 var record_to_write = record_maybe orelse try evt.removedRecord(Record, DB, hash_kind, haxy_moment.readOnly(), existing_record_maybe);│ │129 │ │130 - if (!record_to_write.removed) try validateName(record_to_write.event.name); │ │130 + if (!record_to_write.removed) { │ │131 + _ = try evt.parseEventId(&record_to_write.event.user_id); │ │132 + try validateName(record_to_write.event.name); │ │133 + } │ │134 │ │135 if (existing_record_maybe) |existing_record| { │ │136 // updates preserve the original creation metadata │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───╮ │src/fork.zig│ ╰────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │239 .timestamp = input.timestamp, │ │240 .author = input.author, │ │241 .event = .{ .fork = .{ │ │242 - .repo_id = &input.repo_id, │ │243 - .repo_user_id = &input.repo_user_id, │ │242 + .repo_id = std.fmt.bytesToHex(input.repo_id, .lower), │ │243 + .repo_user_id = std.fmt.bytesToHex(input.repo_user_id, .lower),│ │244 } }, │ │245 }}); │ │246 } │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────╮ │src/notify.zig│ ╰──────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │274 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()),│ │275 .author = author, │ │276 .event = .{ .notify = .{ │ │277 - .owner_id = &location.owner_id, │ │278 - .repo_id = &location.repo_id, │ │277 + .owner_id = std.fmt.bytesToHex(location.owner_id, .lower), │ │278 + .repo_id = std.fmt.bytesToHex(location.repo_id, .lower), │ │279 .thread_id = std.fmt.bytesToHex(thread_id.*, .lower), │ │280 .mode = mode, │ │281 } }, │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────╮ │src/patch.zig│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │900 const admin_moment = try evt.currentMoment(evt.admin_repo_opts, admin_repo); │ │901 const user_moment = (try evt.userMoment(&user_repo)) orelse return error.InvalidPatchDraft; │ │902 const fork_record = (try evt.Fork.readById(evt.UserDB, evt.user_repo_opts.hash, user_moment, &arena, &patch_id)) orelse return error.InvalidPatchDraft; │ │903 - if (fork_record.removed or !std.mem.eql(u8, fork_record.event.repo_id, &input.repo_id)) return error.InvalidPatchDraft; │ │903 + if (fork_record.removed or !std.mem.eql(u8, &fork_record.event.repo_id, &std.fmt.bytesToHex(input.repo_id, .lower))) return error.InvalidPatchDraft; │ │904 const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &arena, &input.user_id)) orelse return error.InvalidPatchDraft;│ │905 if (user.removed or │ │906 !std.mem.eql(u8, user.event.name, input.author.name) or │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1045 const user_moment = (try evt.userMoment(&user_repo)) orelse return false; │ │1046 const fork_record = (try evt.Fork.readById(evt.UserDB, evt.user_repo_opts.hash, user_moment, &arena, &patch_id)) orelse return false; │ │1047 if (fork_record.event.stage != .draft) return false; │ │1048 - if (fork_record.removed or !std.mem.eql(u8, fork_record.event.repo_id, &input.repo_id)) return error.InvalidPatchDraft; │ │1048 + if (fork_record.removed or !std.mem.eql(u8, &fork_record.event.repo_id, &std.fmt.bytesToHex(input.repo_id, .lower))) return error.InvalidPatchDraft; │ │1049 const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &arena, &input.user_id)) orelse return error.InvalidPatchDraft;│ │1050 if (user.removed or │ │1051 !std.mem.eql(u8, user.event.name, input.author.name) or │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/serve_http.zig│ ╰──────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │140 try writeSimpleResponse(http_server, 403, "Forbidden", "text/plain", "private repos cannot be fetched over HTTP");│ │141 return; │ │142 } │ │143 - break :blk try evt.repoPath(allocator, users_dir, repo.repo.event.user_id, &repo.event_id); │ │143 + break :blk try evt.repoPath(allocator, users_dir, &try evt.parseEventId(&repo.repo.event.user_id), &repo.event_id); │ │144 }; │ │145 defer allocator.free(repo_path); │ │146 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │489 if (service == .receive_pack and !isKeyInAuthorizedKeys(user.event.ssh_keys, &sess.fingerprint)) │ │490 return writeError(sess, "unauthorized: this SSH key is not registered to the patch author"); │ │491 │ │492 - const target = (try evt.readRepoById(io, allocator, &admin_arena, handler.server.users_dir, fork_record.event.repo_user_id[0..evt.event_id_size], fork_record.event.repo_id[0..evt.event_id_size], forker_id)) orelse│ │492 + const target_owner_id = try evt.parseEventId(&fork_record.event.repo_user_id); │ │493 + const target_id = try evt.parseEventId(&fork_record.event.repo_id); │ │494 + const target = (try evt.readRepoById(io, allocator, &admin_arena, handler.server.users_dir, &target_owner_id, &target_id, forker_id)) orelse │ │495 return writeError(sess, "repo not found"); │ │496 // patches that are off take their drafts with them │ │497 const patch_role = target.repo.event.patch_role orelse return writeError(sess, "patch draft not found"); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │512 } │ │513 } else { │ │514 if (!std.mem.eql(u8, target.repo.event.name, forker_repo.name)) return writeError(sess, "patch draft belongs to another repo"); │ │513 - const target_path = try evt.repoPath(allocator, handler.server.users_dir, fork_record.event.repo_user_id, fork_record.event.repo_id);│ │515 + const target_path = try evt.repoPath(allocator, handler.server.users_dir, &target_owner_id, &target_id); │ │516 defer allocator.free(target_path); │ │517 const author: evt.CommitAuthor = .{ .name = user.event.name, .email = user.event.email }; │ │518 const timestamp: u64 = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │592 } │ │593 │ │594 // the creator owns the repo │ │593 - const owner_id = repo.repo.event.user_id[0..evt.event_id_size]; │ │594 - if (try authorWithKey(moment, arena, owner_id, fingerprint)) |author| return .{ .allowed = author }; │ │595 + const owner_id = try evt.parseEventId(&repo.repo.event.user_id); │ │596 + if (try authorWithKey(moment, arena, &owner_id, fingerprint)) |author| return .{ .allowed = author };│ │597 │ │598 // anyone else holding the key needs a grant with the role. a key can be │ │599 // shared, so a grant that falls short doesn't end the search. │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │598 - for (try evt.readRepoGrants(io, allocator, arena, users_dir, owner_id, &repo.event_id)) |grant| { │ │600 + for (try evt.readRepoGrants(io, allocator, arena, users_dir, &owner_id, &repo.event_id)) |grant| { │ │601 if (!grant.role.atLeast(min_role)) continue; │ │600 - if (try authorWithKey(moment, arena, grant.user_id, fingerprint)) |author| return .{ .allowed = author }; │ │602 + if (try authorWithKey(moment, arena, &try evt.parseEventId(&grant.user_id), fingerprint)) |author| return .{ .allowed = author };│ │603 } │ │604 return .denied; │ │605 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯