╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────╮ │1 const std = @import("std"); │ │2 -const builtin = @import("builtin");│ │2 const xit = @import("xit"); │ │3 const rp = xit.repo; │ │4 const obj = xit.object; │ ╰──────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │220 // whoever seeded the store may have left a session to claim │ │221 if (user_id == null) { │ │222 var token: [SessionStore.token_hex_len]u8 = undefined; │ │224 - if (remote.session_store.claimAutoLogin(&token) and remote.session_store.lookup(&token, &user_id_buf)) {│ │223 + if (remote.session_store.autoLogin(&token) and remote.session_store.lookup(&token, &user_id_buf)) { │ │224 session_cookie = try std.fmt.bufPrint(&cookie_buf, session_cookie_fmt, .{token}); │ │225 user_id = user_id_buf[0..evt.event_id_size]; │ │226 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────╮ │1916 pub const SessionStore = struct { │ │1917 io: std.Io, │ │1918 dir: std.Io.Dir, │ │1919 + auto_login: ?[token_hex_len]u8, │ │1920 │ │1921 pub const token_hex_len = evt.event_id_size * 2;│ │1922 │ ╰──────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1923 pub fn init(io: std.Io, data_dir: std.Io.Dir) !SessionStore { │ │1924 try data_dir.createDirPath(io, "sessions"); │ │1925 const dir = try data_dir.openDir(io, "sessions", .{}); │ │1926 - return .{ .io = io, .dir = dir }; │ │1926 + const auto_login = blk: { │ │1927 + const file = dir.openFile(io, auto_login_name, .{ .mode = .read_only }) catch break :blk null;│ │1928 + defer file.close(io); │ │1929 + var token: [token_hex_len]u8 = undefined; │ │1930 + var storage: [token_hex_len]u8 = undefined; │ │1931 + var reader = file.reader(io, &storage); │ │1932 + reader.interface.readSliceAll(&token) catch break :blk null; │ │1933 + break :blk token; │ │1934 + }; │ │1935 + return .{ .io = io, .dir = dir, .auto_login = auto_login }; │ │1936 } │ │1937 │ │1938 pub fn deinit(self: SessionStore) void { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │1969 self.dir.deleteFile(self.io, token_hex) catch {}; │ │1970 } │ │1971 │ │1963 - // leave `token_hex`'s session for the next visitor arriving without one. │ │1964 - // only the `try` fixture writes one, and only a debug build honors it. the │ │1965 - // name isn't token-shaped, so it can't collide with a session file. │ │1972 + // leave `token_hex`'s session for visitors arriving without one. only the │ │1973 + // `try` fixture writes one. the name can't collide with a session token. │ │1974 pub fn offerAutoLogin(self: SessionStore, token_hex: *const [token_hex_len]u8) !void {│ │1975 const file = try self.dir.createFile(self.io, auto_login_name, .{}); │ │1976 defer file.close(self.io); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1977 try file.writeStreamingAll(self.io, token_hex); │ │1978 } │ │1979 │ │1972 - // claim the offered session, if one is there. the delete picks the winner │ │1973 - // of a race, so the offer is only ever taken once. a release build never │ │1974 - // looks, because that would be an extra syscall for every GET request. │ │1975 - pub fn claimAutoLogin(self: SessionStore, out: *[token_hex_len]u8) bool { │ │1976 - if (builtin.mode != .Debug) return false; │ │1977 - { │ │1978 - const file = self.dir.openFile(self.io, auto_login_name, .{ .mode = .read_only }) catch return false;│ │1979 - defer file.close(self.io); │ │1980 - var storage: [token_hex_len]u8 = undefined; │ │1981 - var file_reader = file.reader(self.io, &storage); │ │1982 - file_reader.interface.readSliceAll(out) catch return false; │ │1983 - } │ │1984 - self.dir.deleteFile(self.io, auto_login_name) catch return false; │ │1980 + pub fn autoLogin(self: SessionStore, out: *[token_hex_len]u8) bool { │ │1981 + out.* = self.auto_login orelse return false; │ │1982 return true; │ │1983 } │ │1984 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯