diff --git a/demo/src/app/views/anti_csrf/index.zmpl b/demo/src/app/views/anti_csrf/index.zmpl index 4b914a7..c1442c1 100644 --- a/demo/src/app/views/anti_csrf/index.zmpl +++ b/demo/src/app/views/anti_csrf/index.zmpl @@ -7,4 +7,4 @@ -
Try clearing `_jetzig_session` cookie before clicking "Submit Spam"
+
Try clearing `_jetzig-session` cookie before clicking "Submit Spam"
diff --git a/src/jetzig/http/Request.zig b/src/jetzig/http/Request.zig index d6517fc..4e31d3e 100644 --- a/src/jetzig/http/Request.zig +++ b/src/jetzig/http/Request.zig @@ -497,12 +497,14 @@ pub fn cookies(self: *Request) !*jetzig.http.Cookies { /// `jetzig.http.Session`. pub fn session(self: *Request) !*jetzig.http.Session { if (self._session) |capture| return capture; - + const cookie_name = self.server.env.vars.get("JETZIG_SESSION_COOKIE") orelse + jetzig.http.Session.default_cookie_name; const local_session = try self.allocator.create(jetzig.http.Session); local_session.* = jetzig.http.Session.init( self.allocator, try self.cookies(), self.server.env.secret, + .{ .cookie_name = cookie_name }, ); local_session.parse() catch |err| { switch (err) { diff --git a/src/jetzig/http/Session.zig b/src/jetzig/http/Session.zig index 1c96a60..384745b 100644 --- a/src/jetzig/http/Session.zig +++ b/src/jetzig/http/Session.zig @@ -2,12 +2,12 @@ const std = @import("std"); const jetzig = @import("../../jetzig.zig"); -pub const cookie_name = "_jetzig-session"; pub const Cipher = std.crypto.aead.chacha_poly.XChaCha20Poly1305; allocator: std.mem.Allocator, encryption_key: []const u8, cookies: *jetzig.http.Cookies, +cookie_name: []const u8, initialized: bool = false, data: jetzig.data.Data, @@ -15,22 +15,30 @@ state: enum { parsed, pending } = .pending, const Self = @This(); +pub const default_cookie_name = "_jetzig-session"; + +pub const Options = struct { + cookie_name: []const u8 = default_cookie_name, +}; + pub fn init( allocator: std.mem.Allocator, cookies: *jetzig.http.Cookies, encryption_key: []const u8, + options: Options, ) Self { return .{ .allocator = allocator, .data = jetzig.data.Data.init(allocator), .cookies = cookies, + .cookie_name = options.cookie_name, .encryption_key = encryption_key, }; } /// Parse session cookie. pub fn parse(self: *Self) !void { - if (self.cookies.get(cookie_name)) |cookie| { + if (self.cookies.get(self.cookie_name)) |cookie| { try self.parseSessionCookie(cookie.value); } else { try self.reset(); @@ -111,7 +119,7 @@ fn save(self: *Self) !void { defer self.allocator.free(encrypted); const encoded = try jetzig.util.base64Encode(self.allocator, encrypted); defer self.allocator.free(encoded); - try self.cookies.put(.{ .name = cookie_name, .value = encoded }); + try self.cookies.put(.{ .name = self.cookie_name, .value = encoded }); } fn parseSessionCookie(self: *Self, cookie_value: []const u8) !void { @@ -180,7 +188,7 @@ test "put and get session key/value" { try cookies.parse(); const secret: [Cipher.key_length]u8 = [_]u8{0x69} ** Cipher.key_length; - var session = Self.init(allocator, &cookies, &secret); + var session = Self.init(allocator, &cookies, &secret, .{}); defer session.deinit(); var data = jetzig.data.Data.init(allocator); @@ -199,7 +207,7 @@ test "remove session key/value" { try cookies.parse(); const secret: [Cipher.key_length]u8 = [_]u8{0x69} ** Cipher.key_length; - var session = Self.init(allocator, &cookies, &secret); + var session = Self.init(allocator, &cookies, &secret, .{}); defer session.deinit(); var data = jetzig.data.Data.init(allocator); @@ -224,7 +232,7 @@ test "get value from parsed/decrypted cookie" { try cookies.parse(); const secret: [Cipher.key_length]u8 = [_]u8{0x69} ** Cipher.key_length; - var session = Self.init(allocator, &cookies, &secret); + var session = Self.init(allocator, &cookies, &secret, .{}); defer session.deinit(); try session.parse(); @@ -233,17 +241,32 @@ test "get value from parsed/decrypted cookie" { } test "invalid cookie value - too short" { + const allocator = std.testing.allocator; + var cookies = jetzig.http.Cookies.init(allocator, "_jetzig-session=abc"); + defer cookies.deinit(); + try cookies.parse(); + + const secret: [Cipher.key_length]u8 = [_]u8{0x69} ** Cipher.key_length; + var session = Self.init(allocator, &cookies, &secret, .{}); + defer session.deinit(); + + try std.testing.expectError(error.JetzigInvalidSessionCookie, session.parse()); +} + +test "custom session cookie name" { const allocator = std.testing.allocator; var cookies = jetzig.http.Cookies.init( allocator, - "_jetzig-session=abc", + "custom-cookie-name=fPCFwZHvPDT-XCVcsQUSspDLchS3tRuJDqPpB2v3127VXpRP_bPcPLgpHK6RiVkfcP1bMtU", ); defer cookies.deinit(); try cookies.parse(); const secret: [Cipher.key_length]u8 = [_]u8{0x69} ** Cipher.key_length; - var session = Self.init(allocator, &cookies, &secret); + var session = Self.init(allocator, &cookies, &secret, .{ .cookie_name = "custom-cookie-name" }); defer session.deinit(); - try std.testing.expectError(error.JetzigInvalidSessionCookie, session.parse()); + try session.parse(); + var value = (session.get("foo")).?; + try std.testing.expectEqualStrings("bar", try value.toString()); } diff --git a/src/jetzig/testing/App.zig b/src/jetzig/testing/App.zig index f3c2a4f..ddc2060 100644 --- a/src/jetzig/testing/App.zig +++ b/src/jetzig/testing/App.zig @@ -55,7 +55,7 @@ pub fn init(allocator: std.mem.Allocator, routes_module: type) !App { try cookies.parse(); const session = try alloc.create(jetzig.http.Session); - session.* = jetzig.http.Session.init(alloc, cookies, jetzig.testing.secret); + session.* = jetzig.http.Session.init(alloc, cookies, jetzig.testing.secret, .{}); app.* = App{ .arena = arena, @@ -237,7 +237,7 @@ pub fn initSession(self: *App) !void { const allocator = self.arena.allocator(); var local_session = try allocator.create(jetzig.http.Session); - local_session.* = jetzig.http.Session.init(allocator, self.cookies, jetzig.testing.secret); + local_session.* = jetzig.http.Session.init(allocator, self.cookies, jetzig.testing.secret, .{}); try local_session.parse(); self.session = local_session;