╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │170 .@"repo/new" => handleRepoNew(io, request, allocator, path, server.admin_repo_path, server.users_dir, server.session_store), │ │171 .@"user/new" => handleUserNew(io, request, allocator, path, server.admin_repo_path, server.users_dir, server.session_store), │ │172 .user => handleUserSettings(io, request, allocator, base, server.admin_repo_path, server.users_dir, server.session_store), │ │173 - .addkey => handleUserKey(io, request, allocator, base, server.admin_repo_path, server.users_dir, server.session_store, .add), │ │174 - .removekey => handleUserKey(io, request, allocator, base, server.admin_repo_path, server.users_dir, server.session_store, .remove),│ │173 + .addkey => handleUserKeyAdd(io, request, allocator, base, server.admin_repo_path, server.users_dir, server.session_store), │ │174 + .removekey => handleUserKeyRemove(io, request, allocator, base, server.admin_repo_path, server.users_dir, server.session_store), │ │175 .settings => handleRepoSettings(io, request, allocator, path, host), │ │176 .grant => handleRoles(io, request, allocator, base, host, .grant), │ │177 .revoke => handleRoles(io, request, allocator, base, host, .revoke), │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │897 }); │ │898 } │ │899 │ │900 -// add or remove one of the logged-in user's ssh keys, then return to the ssh│ │901 -// keys tab that posted the form, which a failure also goes back to. │ │902 -fn handleUserKey( │ │900 +// add one of the logged-in user's ssh keys, then return to the ssh keys tab │ │901 +// that posted the form, which a failure also goes back to. │ │902 +fn handleUserKeyAdd( │ │903 io: std.Io, │ │904 request: *std.http.Server.Request, │ │905 allocator: std.mem.Allocator, │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │907 admin_repo_path: []const u8, │ │908 users_dir: []const u8, │ │909 session_store: SessionStore, │ │910 - action: evt.KeyAction, │ │910 ) !void { │ │911 const user_id = requestUserId(request, session_store) orelse return respondLoginRequired(request);│ │912 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │918 { │ │919 var admin_repo = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = admin_repo_path });│ │920 defer admin_repo.deinit(io, allocator); │ │922 - evt.changeUserKey(io, allocator, users_dir, &admin_repo, &user_id, action, key) catch |err| switch (err) {│ │921 + evt.addUserKey(io, allocator, users_dir, &admin_repo, &user_id, key) catch |err| switch (err) { │ │922 error.NotFound => return respondLoginRequired(request), │ │923 else => { │ │924 const failure = ui.Session.FormFeedback.KeyFailure.fromError(err) orelse return err; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │930 try request.respond("", .{ │ │931 .status = .see_other, │ │932 .extra_headers = &.{.{ .name = "location", .value = form_location }}, │ │933 + }); │ │934 +} │ │935 + │ │936 +// remove the logged-in user's ssh key the confirmation url names, then return │ │937 +// to the ssh keys tab │ │938 +fn handleUserKeyRemove( │ │939 + io: std.Io, │ │940 + request: *std.http.Server.Request, │ │941 + allocator: std.mem.Allocator, │ │942 + base: []const u8, │ │943 + admin_repo_path: []const u8, │ │944 + users_dir: []const u8, │ │945 + session_store: SessionStore, │ │946 +) !void { │ │947 + const user_id = requestUserId(request, session_store) orelse return respondLoginRequired(request); │ │948 + const route = ui.RoutablePage.fromUrl(base) orelse return respondKeyNotFound(request); │ │949 + const tab = route.userTab(); │ │950 + if (tab.view != .keys or tab.key.len != evt.User.fingerprint_len) return respondKeyNotFound(request); │ │951 + │ │952 + { │ │953 + var admin_repo = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = admin_repo_path }); │ │954 + defer admin_repo.deinit(io, allocator); │ │955 + evt.removeUserKey(io, allocator, users_dir, &admin_repo, &user_id, &tab.key.bytes) catch |err| switch (err) {│ │956 + error.NotFound => return respondLoginRequired(request), │ │957 + else => return err, │ │958 + }; │ │959 + } │ │960 + │ │961 + var arena = std.heap.ArenaAllocator.init(allocator); │ │962 + defer arena.deinit(); │ │963 + const location = try route.withUserTab(.{ .view = .keys }).toUrl(&arena); │ │964 + try request.respond("", .{ │ │965 + .status = .see_other, │ │966 + .extra_headers = &.{.{ .name = "location", .value = location }}, │ │967 }); │ │968 } │ │969 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │970 +fn respondKeyNotFound(request: *std.http.Server.Request) !void { │ │971 + try request.respond("ssh key not found", .{ │ │972 + .status = .not_found, │ │973 + .extra_headers = &.{.{ .name = "content-type", .value = "text/plain" }},│ │974 + }); │ │975 +} │ │976 + │ │977 // create a thread in the repo the form's page names and redirect to it. │ │978 fn handleThreadNew( │ │979 io: std.Io, │ ╰─────────────────────────────────────────────────────────────────────────────────────╯