More fixes and linting

This commit is contained in:
Jakub Trávník 2026-01-03 12:03:04 +01:00
parent b120071762
commit ff48b7c464
6 changed files with 1071 additions and 1101 deletions

View file

@ -116,10 +116,7 @@ export default function LoginPage() {
// Show 2FA verification form // Show 2FA verification form
if (pendingSessionId) { if (pendingSessionId) {
return ( return (
<AuthLayout <AuthLayout title="Two-Factor Authentication" description="Enter the 6-digit code from your authenticator app">
title="Two-Factor Authentication"
description="Enter the 6-digit code from your authenticator app"
>
<form onSubmit={handleTwoFactorSubmit} className="space-y-4"> <form onSubmit={handleTwoFactorSubmit} className="space-y-4">
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="2fa-code">Authentication Code</Label> <Label htmlFor="2fa-code">Authentication Code</Label>

View file

@ -150,10 +150,14 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
}, 1500); }, 1500);
} else { } else {
toast.error("Failed to enable 2FA", { description: data.message }); toast.error("Failed to enable 2FA", { description: data.message });
setEnable2faDialogOpen(false);
resetEnable2faDialog();
} }
}, },
onError: (error) => { onError: (error) => {
toast.error("Failed to enable 2FA", { description: error.message }); toast.error("Failed to enable 2FA", { description: error.message });
setEnable2faDialogOpen(false);
resetEnable2faDialog();
}, },
}); });
@ -169,10 +173,14 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
}, 1500); }, 1500);
} else { } else {
toast.error("Failed to disable 2FA", { description: data.message }); toast.error("Failed to disable 2FA", { description: data.message });
setDisable2faDialogOpen(false);
resetDisable2faDialog();
} }
}, },
onError: (error) => { onError: (error) => {
toast.error("Failed to disable 2FA", { description: error.message }); toast.error("Failed to disable 2FA", { description: error.message });
setDisable2faDialogOpen(false);
resetDisable2faDialog();
}, },
}); });
@ -350,10 +358,20 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
<Shield className="size-5" /> <Shield className="size-5" />
Two-Factor Authentication Two-Factor Authentication
{twoFactorStatus.data && ( {twoFactorStatus.isLoading ? (
<Badge variant="secondary" className="ml-2">
Loading...
</Badge>
) : twoFactorStatus.isError ? (
<Badge variant="secondary" className="ml-2">
Status unavailable
</Badge>
) : (
twoFactorStatus.data && (
<Badge variant={twoFactorStatus.data.enabled ? "success" : "secondary"} className="ml-2"> <Badge variant={twoFactorStatus.data.enabled ? "success" : "secondary"} className="ml-2">
{twoFactorStatus.data.enabled ? "Enabled" : "Disabled"} {twoFactorStatus.data.enabled ? "Enabled" : "Disabled"}
</Badge> </Badge>
)
)} )}
</CardTitle> </CardTitle>
<CardDescription className="mt-1.5">Add an extra layer of security to your account</CardDescription> <CardDescription className="mt-1.5">Add an extra layer of security to your account</CardDescription>
@ -364,7 +382,12 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
authenticator app when logging in. authenticator app when logging in.
</p> </p>
{twoFactorStatus.data?.enabled ? ( {twoFactorStatus.isLoading || twoFactorStatus.isError ? (
<Button variant="outline" disabled>
<Shield size={16} className="mr-2" />
{twoFactorStatus.isLoading ? "Loading..." : "Status unavailable"}
</Button>
) : twoFactorStatus.data?.enabled ? (
<Dialog <Dialog
open={disable2faDialogOpen} open={disable2faDialogOpen}
onOpenChange={(open) => { onOpenChange={(open) => {

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -212,12 +201,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -225,22 +210,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -395,16 +373,12 @@
"indexes": { "indexes": {
"backup_schedules_table_short_id_unique": { "backup_schedules_table_short_id_unique": {
"name": "backup_schedules_table_short_id_unique", "name": "backup_schedules_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -413,12 +387,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -426,12 +396,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -499,9 +465,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -598,9 +562,7 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -648,12 +610,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -729,9 +687,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -829,16 +785,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -34,9 +34,7 @@ const disableTwoFactor = async (username: string): Promise<void> => {
console.log(" All existing sessions have been invalidated."); console.log(" All existing sessions have been invalidated.");
}; };
export const twoFactorCommand = new Command("2fa") export const twoFactorCommand = new Command("2fa").description("Two-factor authentication recovery").addCommand(
.description("Two-factor authentication recovery")
.addCommand(
new Command("disable") new Command("disable")
.description("Disable 2FA for a user (recovery method when authenticator access is lost)") .description("Disable 2FA for a user (recovery method when authenticator access is lost)")
.requiredOption("-u, --username <username>", "Username of the account") .requiredOption("-u, --username <username>", "Username of the account")
@ -52,4 +50,4 @@ export const twoFactorCommand = new Command("2fa")
process.exit(0); process.exit(0);
}), }),
); );

View file

@ -3,7 +3,7 @@ import { authService } from "../modules/auth/auth.service";
export class CleanupSessionsJob extends Job { export class CleanupSessionsJob extends Job {
async run() { async run() {
authService.cleanupExpiredSessions(); await authService.cleanupExpiredSessions();
authService.cleanupExpiredPending2faSessions(); authService.cleanupExpiredPending2faSessions();
return { done: true, timestamp: new Date() }; return { done: true, timestamp: new Date() };