╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────╮ │src/event/Grant.zig│ ╰───────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │26 pub const target_to_grant_id_set_key = "target->grant-id-set"; │ │27 │ │28 // the id of the one grant a user can hold on a target │ │29 -pub fn idOf(target_id: []const u8, user_id: []const u8) [evt.event_id_size]u8 { │ │29 +pub fn idOf(target_id: *const [evt.event_id_size]u8, user_id: *const [evt.event_id_size]u8) [evt.event_id_size]u8 {│ │30 var hasher = std.crypto.hash.sha2.Sha256.init(.{}); │ │31 hasher.update(target_id); │ │32 hasher.update(user_id); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │38 // only what the event says about itself is checked. a grant naming a missing │ │39 // target or user is inert. │ │40 fn validate(event_id: *const [evt.event_id_size]u8, record: Record) !void { │ │41 - if (record.event.target_id.len != evt.event_id_size) return error.InvalidTargetId; │ │42 - if (record.event.user_id.len != evt.event_id_size) return error.InvalidUserId; │ │43 - if (!std.mem.eql(u8, event_id, &idOf(record.event.target_id, record.event.user_id))) return error.InvalidGrantId;│ │41 + const target_id = try evt.parseEventId(&record.event.target_id); │ │42 + const user_id = try evt.parseEventId(&record.event.user_id); │ │43 + if (!std.mem.eql(u8, event_id, &idOf(&target_id, &user_id))) return error.InvalidGrantId; │ │44 } │ │45 │ │46 pub fn consume( │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │84 } │ │85 │ │86 // the id fixes the target, so a grant never moves between sets │ │87 - const target_grants = try DB.SortedSet(.read_write).init(try by_target.putCursor(hash.hashInt(hash_kind, record.event.target_id)));│ │87 + const target_id = try evt.parseEventId(&record.event.target_id); │ │88 + const target_grants = try DB.SortedSet(.read_write).init(try by_target.putCursor(hash.hashInt(hash_kind, &target_id))); │ │89 if (record.removed) { │ │90 _ = try target_grants.remove(&order_key); │ │91 } else { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 99 comptime hash_kind: hash.HashKind, │ │100 haxy_moment: DB.HashMap(.read_only), │ │101 arena: *std.heap.ArenaAllocator, │ │101 - target_id: []const u8, │ │102 - user_id: []const u8, │ │102 + target_id: *const [evt.event_id_size]u8, │ │103 + user_id: *const [evt.event_id_size]u8, │ │104 ) !?evt.Repo.Role { │ │105 const Granted = struct { event: struct { role: evt.Repo.Role }, removed: bool }; │ │106 const grant = (try evt.readRecordSubset(Self, Granted, DB, hash_kind, haxy_moment, arena, &idOf(target_id, user_id))) orelse return null;│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │113 comptime hash_kind: hash.HashKind, │ │114 haxy_moment: DB.HashMap(.read_only), │ │115 arena: *std.heap.ArenaAllocator, │ │115 - target_id: []const u8, │ │116 + target_id: *const [evt.event_id_size]u8, │ │117 ) ![]const Self { │ │118 var grants: std.ArrayList(Self) = .empty; │ │119 const by_target_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, target_to_grant_id_set_key)) orelse return grants.items;│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────╮ │src/event/Notify.zig│ ╰────────────────────╯ ╭───────────────────────────────────────────────────────────────────╮ │ 4 const hash = xit.hash; │ │ 5 │ │ 6 // the repo's owner, whose user repo holds the subscriber index│ │ 7 -owner_id: []const u8, │ │ 7 +owner_id: [evt.event_id_size * 2]u8, │ │ 8 // the thread and its repo │ │ 9 -repo_id: []const u8, │ │ 9 +repo_id: [evt.event_id_size * 2]u8, │ │10 thread_id: [evt.event_id_size * 2]u8, │ │11 mode: Mode, │ │12 │ ╰───────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │33 pub const all_id_set_key = "notify-id-set"; │ │34 │ │35 // the id of the one record a user can hold on a thread │ │36 -pub fn idOf(repo_id: []const u8, thread_id: *const [evt.event_id_size]u8) [evt.event_id_size]u8 { │ │36 +pub fn idOf(repo_id: *const [evt.event_id_size]u8, thread_id: *const [evt.event_id_size]u8) [evt.event_id_size]u8 {│ │37 var hasher = std.crypto.hash.sha2.Sha256.init(.{}); │ │38 // the kind name keeps the id apart from the notif id the same pair hashes to │ │39 hasher.update(@tagName(evt.EventKind.notify)); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │47 // only what the event says about itself is checked. a record naming a missing │ │48 // repo or thread is inert. │ │49 fn validate(event_id: *const [evt.event_id_size]u8, record: Record) !void { │ │50 - if (record.event.owner_id.len != evt.event_id_size) return error.InvalidOwnerId; │ │51 - if (record.event.repo_id.len != evt.event_id_size) return error.InvalidRepoId; │ │50 + _ = try evt.parseEventId(&record.event.owner_id); │ │51 + const repo_id = try evt.parseEventId(&record.event.repo_id); │ │52 const thread_id = try evt.parseEventId(&record.event.thread_id); │ │53 - if (!std.mem.eql(u8, event_id, &idOf(record.event.repo_id, &thread_id))) return error.InvalidNotifyId;│ │53 + if (!std.mem.eql(u8, event_id, &idOf(&repo_id, &thread_id))) return error.InvalidNotifyId; │ │54 } │ │55 │ │56 pub fn consume( │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/event/Repo.zig│ ╰──────────────────╯ ╭──────────────────────────────────────╮ │3 const xit = @import("xit"); │ │4 const hash = xit.hash; │ │5 │ │6 -user_id: []const u8, │ │6 +user_id: [evt.event_id_size * 2]u8,│ │7 name: []const u8, │ │8 description: []const u8, │ │9 read_access: Access = .private, │ ╰──────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │77 // what the access fields give everyone, logged in or not │ │78 const base_maybe: ?Role = if (record.event.write_access == .public) .write else if (record.event.read_access == .public) .read else null;│ │79 const user_id = user_id_maybe orelse return base_maybe; │ │80 - if (std.mem.eql(u8, record.event.user_id, &user_id)) return .owner; │ │80 + if (std.mem.eql(u8, &record.event.user_id, &std.fmt.bytesToHex(user_id, .lower))) return .owner; │ │81 │ │82 const granted = (try evt.Grant.readRole(DB, hash_kind, user_moment, arena, repo_id, &user_id)) orelse return base_maybe; │ │83 const base = base_maybe orelse return granted; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯