From 988cd9c3d8e9f04e52add99cd61351aaaf93843c Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Wed, 14 May 2025 18:59:26 +0100 Subject: [PATCH] Extend auth + demo to show sign out Add Jetzig module to migrations/seeders to make it available for import. --- build.zig | 6 ++++ build.zig.zon | 4 +-- cli/build.zig.zon | 4 +-- .../2025-03-10_01-36-58_create_users.zig | 1 + .../2025-03-10_01-36-58_create_users.zig | 6 ++-- demo/src/app/views/login.zig | 34 +++++++++++-------- demo/src/app/views/login/index.zmpl | 23 +++++++++---- demo/src/main.zig | 10 +++--- src/jetzig/auth.zig | 5 +++ 9 files changed, 61 insertions(+), 32 deletions(-) diff --git a/build.zig b/build.zig index afaf39d..7c199a9 100644 --- a/build.zig +++ b/build.zig @@ -82,6 +82,9 @@ pub fn build(b: *std.Build) !void { b.modules.put("jetquery_migrate", jetquery_dep.module("jetquery_migrate")) catch @panic("Out of memory"); b.modules.put("jetquery_seeder", jetquery_dep.module("jetquery_seeder")) catch @panic("Out of memory"); + jetquery_dep.module("jetquery_seeder").addImport("jetzig", jetzig_module); + jetquery_dep.module("jetquery_migrate").addImport("jetzig", jetzig_module); + const smtp_client_dep = b.dependency("smtp_client", .{ .target = target, .optimize = optimize, @@ -192,6 +195,9 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn const jetquery_seeder_module = jetzig_dep.module("jetquery_seeder"); const jetquery_reflect_module = jetquery_dep.module("jetquery_reflect"); + jetquery_dep.module("jetquery_seeders").addImport("jetzig", jetzig_module); + jetquery_dep.module("jetquery_migrations").addImport("jetzig", jetzig_module); + const build_options = b.addOptions(); build_options.addOption(Environment, "environment", environment); build_options.addOption(bool, "build_static", build_static); diff --git a/build.zig.zon b/build.zig.zon index 38daeea..4d92cfa 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -33,8 +33,8 @@ .hash = "httpz-0.0.0-PNVzrEK4BgBpHQGA2m0RPqPGEjnTdDXHodBwzjYDrmps", }, .jetquery = .{ - .url = "https://github.com/jetzig-framework/jetquery/archive/ed6b42e196573365057d8e5d17ff85b456b11e68.tar.gz", - .hash = "jetquery-0.0.0-TNf3zs24BgCYXZZvMKUbEMb6hRfrMmYHJgHTNGWZM5B1", + .url = "https://github.com/jetzig-framework/jetquery/archive/8d3dd2ae107767d9c72161a1e4adbb602a16e619.tar.gz", + .hash = "jetquery-0.0.0-TNf3ziK5BgBGDf4BI6tNfTTQ3TpHIGjuonWrlvs8meVg", }, }, diff --git a/cli/build.zig.zon b/cli/build.zig.zon index dd5a413..b8a3f9e 100644 --- a/cli/build.zig.zon +++ b/cli/build.zig.zon @@ -10,8 +10,8 @@ .hash = "zig_args-0.0.0-jqtN6P_NAAC97fGpk9hS2K681jkiqPsWP6w3ucb_ctGH", }, .jetquery = .{ - .url = "https://github.com/jetzig-framework/jetquery/archive/ed6b42e196573365057d8e5d17ff85b456b11e68.tar.gz", - .hash = "jetquery-0.0.0-TNf3zs24BgCYXZZvMKUbEMb6hRfrMmYHJgHTNGWZM5B1", + .url = "https://github.com/jetzig-framework/jetquery/archive/8d3dd2ae107767d9c72161a1e4adbb602a16e619.tar.gz", + .hash = "jetquery-0.0.0-TNf3ziK5BgBGDf4BI6tNfTTQ3TpHIGjuonWrlvs8meVg", }, }, .paths = .{ diff --git a/demo/src/app/database/migrations/2025-03-10_01-36-58_create_users.zig b/demo/src/app/database/migrations/2025-03-10_01-36-58_create_users.zig index da76936..6ac23c3 100644 --- a/demo/src/app/database/migrations/2025-03-10_01-36-58_create_users.zig +++ b/demo/src/app/database/migrations/2025-03-10_01-36-58_create_users.zig @@ -1,6 +1,7 @@ const std = @import("std"); const jetquery = @import("jetquery"); const t = jetquery.schema.table; +const jetzig = @import("jetzig"); pub fn up(repo: anytype) !void { try repo.createTable( diff --git a/demo/src/app/database/seeders/2025-03-10_01-36-58_create_users.zig b/demo/src/app/database/seeders/2025-03-10_01-36-58_create_users.zig index e8baa85..13ccb9e 100644 --- a/demo/src/app/database/seeders/2025-03-10_01-36-58_create_users.zig +++ b/demo/src/app/database/seeders/2025-03-10_01-36-58_create_users.zig @@ -1,11 +1,13 @@ const std = @import("std"); +const jetzig = @import("jetzig"); + pub fn run(repo: anytype) !void { try repo.insert( .User, .{ .email = "iguana@jetzig.dev", - .password_hash = "not_secure", + .password_hash = try jetzig.auth.hashPassword(repo.allocator, "password"), }, ); @@ -13,7 +15,7 @@ pub fn run(repo: anytype) !void { .User, .{ .email = "admin@jetzig.dev", - .password_hash = "do_not_use", + .password_hash = try jetzig.auth.hashPassword(repo.allocator, "admin"), }, ); } diff --git a/demo/src/app/views/login.zig b/demo/src/app/views/login.zig index 0736dd2..5304cb6 100644 --- a/demo/src/app/views/login.zig +++ b/demo/src/app/views/login.zig @@ -3,38 +3,44 @@ const jetzig = @import("jetzig"); const auth = @import("jetzig").auth; pub fn index(request: *jetzig.Request) !jetzig.View { + var root = try request.data(.object); + + if (request.middleware(.auth).user) |user| { + try root.put("user", .{ .email = user.email }); + } + return request.render(.ok); } pub fn post(request: *jetzig.Request) !jetzig.View { - const Login = struct { - email: []const u8, - password: []const u8, - }; + const Logout = struct { logout: []const u8 }; + const Login = struct { email: []const u8, password: []const u8 }; + + if (try request.expectParams(Logout)) |_| { + try auth.signOut(request); + return request.redirect("/login", .found); + } const params = try request.expectParams(Login) orelse { return request.fail(.forbidden); }; // Lookup the user by email - const query = jetzig.database.Query(.User).findBy( + const user = try jetzig.database.Query(.User).findBy( .{ .email = params.email }, - ); - - const user = try request.repo.execute(query) orelse { + ).execute(request.repo) orelse { return request.fail(.forbidden); }; // Check that the password matches - if (try auth.verifyPassword( + if (!try auth.verifyPassword( request.allocator, user.password_hash, params.password, - )) { - try auth.signIn(request, user.id); - return request.redirect("/", .found); - } - return request.fail(.forbidden); + )) return request.fail(.forbidden); + + try auth.signIn(request, user.id); + return request.redirect("/login", .found); } test "post" { diff --git a/demo/src/app/views/login/index.zmpl b/demo/src/app/views/login/index.zmpl index 605b051..2fb4638 100644 --- a/demo/src/app/views/login/index.zmpl +++ b/demo/src/app/views/login/index.zmpl @@ -1,7 +1,16 @@ -
- - - - - -
+@if ($.user) |user| +
Logged in as {{user.email}}
+ +
+ + +
+@else +
+ + + + + +
+@end diff --git a/demo/src/main.zig b/demo/src/main.zig index 454a95a..99a75d3 100644 --- a/demo/src/main.zig +++ b/demo/src/main.zig @@ -12,11 +12,11 @@ pub const jetzig_options = struct { /// Middleware chain. Add any custom middleware here, or use middleware provided in /// `jetzig.middleware` (e.g. `jetzig.middleware.HtmxMiddleware`). pub const middleware: []const type = &.{ - // jetzig.middleware.AuthMiddleware, - // jetzig.middleware.AntiCsrfMiddleware, - // jetzig.middleware.HtmxMiddleware, - // jetzig.middleware.CompressionMiddleware, - // @import("app/middleware/DemoMiddleware.zig"), + jetzig.middleware.AuthMiddleware, + // jetzig.middleware.AntiCsrfMiddleware, + // jetzig.middleware.HtmxMiddleware, + // jetzig.middleware.CompressionMiddleware, + // @import("app/middleware/DemoMiddleware.zig"), }; // Maximum bytes to allow in request body. diff --git a/src/jetzig/auth.zig b/src/jetzig/auth.zig index 15b401a..f55e073 100644 --- a/src/jetzig/auth.zig +++ b/src/jetzig/auth.zig @@ -22,6 +22,11 @@ pub fn signIn(request: *jetzig.Request, user_id: anytype) !void { try session.put("_jetzig_user_id", user_id); } +pub fn signOut(request: *jetzig.Request) !void { + var session = try request.session(); + _ = try session.remove("_jetzig_user_id"); +} + pub fn verifyPassword( allocator: std.mem.Allocator, hash: []const u8,