style changes, and password login fix
This commit is contained in:
@@ -331,12 +331,12 @@ export default function LoginPage() {
|
|||||||
<Show when={error()}>
|
<Show when={error()}>
|
||||||
<div class="border-maroon bg-red mb-4 w-full max-w-md rounded-lg border px-4 py-3 text-center">
|
<div class="border-maroon bg-red mb-4 w-full max-w-md rounded-lg border px-4 py-3 text-center">
|
||||||
<Show when={error() === "passwordMismatch"}>
|
<Show when={error() === "passwordMismatch"}>
|
||||||
<div class="text-red text-lg font-semibold">
|
<div class="text-base text-lg font-semibold">
|
||||||
Passwords did not match!
|
Passwords did not match!
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={error() === "duplicate"}>
|
<Show when={error() === "duplicate"}>
|
||||||
<div class="text-red text-lg font-semibold">
|
<div class="text-base text-lg font-semibold">
|
||||||
Email Already Exists!
|
Email Already Exists!
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
@@ -347,7 +347,7 @@ export default function LoginPage() {
|
|||||||
error() !== "duplicate"
|
error() !== "duplicate"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div class="text-red text-sm">{error()}</div>
|
<div class="text-base text-sm">{error()}</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|||||||
@@ -851,19 +851,25 @@ export const authRouter = createTRPCRouter({
|
|||||||
|
|
||||||
// Check all conditions after password verification
|
// Check all conditions after password verification
|
||||||
if (!user || !passwordHash || !passwordMatch) {
|
if (!user || !passwordHash || !passwordMatch) {
|
||||||
// Log failed login attempt
|
// Log failed login attempt (wrap in try-catch to ensure it never blocks auth flow)
|
||||||
const { ipAddress, userAgent } = getAuditContext(ctx.event.nativeEvent);
|
try {
|
||||||
await logAuditEvent({
|
const { ipAddress, userAgent } = getAuditContext(
|
||||||
eventType: "auth.login.failed",
|
ctx.event.nativeEvent
|
||||||
eventData: {
|
);
|
||||||
email,
|
await logAuditEvent({
|
||||||
method: "password",
|
eventType: "auth.login.failed",
|
||||||
reason: "invalid_credentials"
|
eventData: {
|
||||||
},
|
email,
|
||||||
ipAddress,
|
method: "password",
|
||||||
userAgent,
|
reason: "invalid_credentials"
|
||||||
success: false
|
},
|
||||||
});
|
ipAddress,
|
||||||
|
userAgent,
|
||||||
|
success: false
|
||||||
|
});
|
||||||
|
} catch (auditError) {
|
||||||
|
console.error("Audit logging failed:", auditError);
|
||||||
|
}
|
||||||
|
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
@@ -911,15 +917,19 @@ export const authRouter = createTRPCRouter({
|
|||||||
// Set CSRF token for authenticated session
|
// Set CSRF token for authenticated session
|
||||||
setCSRFToken(ctx.event.nativeEvent);
|
setCSRFToken(ctx.event.nativeEvent);
|
||||||
|
|
||||||
// Log successful login
|
// Log successful login (wrap in try-catch to ensure it never blocks auth flow)
|
||||||
await logAuditEvent({
|
try {
|
||||||
userId: user.id,
|
await logAuditEvent({
|
||||||
eventType: "auth.login.success",
|
userId: user.id,
|
||||||
eventData: { method: "password", rememberMe: rememberMe || false },
|
eventType: "auth.login.success",
|
||||||
ipAddress: clientIP,
|
eventData: { method: "password", rememberMe: rememberMe || false },
|
||||||
userAgent,
|
ipAddress: clientIP,
|
||||||
success: true
|
userAgent,
|
||||||
});
|
success: true
|
||||||
|
});
|
||||||
|
} catch (auditError) {
|
||||||
|
console.error("Audit logging failed:", auditError);
|
||||||
|
}
|
||||||
|
|
||||||
return { success: true, message: "success" };
|
return { success: true, message: "success" };
|
||||||
}),
|
}),
|
||||||
|
|||||||
95
src/server/init-audit-table.ts
Normal file
95
src/server/init-audit-table.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Database Initialization for Audit Logging
|
||||||
|
* Run this script to create the AuditLog table in your database
|
||||||
|
*
|
||||||
|
* Usage: bun run src/server/init-audit-table.ts
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ConnectionFactory } from "./database";
|
||||||
|
|
||||||
|
async function initAuditTable() {
|
||||||
|
console.log("🔧 Initializing AuditLog table...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const conn = ConnectionFactory();
|
||||||
|
|
||||||
|
// Create AuditLog table
|
||||||
|
await conn.execute({
|
||||||
|
sql: `CREATE TABLE IF NOT EXISTS AuditLog (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
user_id TEXT,
|
||||||
|
event_type TEXT NOT NULL,
|
||||||
|
event_data TEXT,
|
||||||
|
ip_address TEXT,
|
||||||
|
user_agent TEXT,
|
||||||
|
success INTEGER NOT NULL,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
|
FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE SET NULL
|
||||||
|
)`
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("✅ AuditLog table created (or already exists)");
|
||||||
|
|
||||||
|
// Create indexes for performance
|
||||||
|
console.log("🔧 Creating indexes...");
|
||||||
|
|
||||||
|
await conn.execute({
|
||||||
|
sql: `CREATE INDEX IF NOT EXISTS idx_audit_user_id ON AuditLog(user_id)`
|
||||||
|
});
|
||||||
|
|
||||||
|
await conn.execute({
|
||||||
|
sql: `CREATE INDEX IF NOT EXISTS idx_audit_event_type ON AuditLog(event_type)`
|
||||||
|
});
|
||||||
|
|
||||||
|
await conn.execute({
|
||||||
|
sql: `CREATE INDEX IF NOT EXISTS idx_audit_created_at ON AuditLog(created_at)`
|
||||||
|
});
|
||||||
|
|
||||||
|
await conn.execute({
|
||||||
|
sql: `CREATE INDEX IF NOT EXISTS idx_audit_ip_address ON AuditLog(ip_address)`
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("✅ Indexes created");
|
||||||
|
|
||||||
|
// Verify table exists
|
||||||
|
const result = await conn.execute({
|
||||||
|
sql: `SELECT name FROM sqlite_master WHERE type='table' AND name='AuditLog'`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.rows.length > 0) {
|
||||||
|
console.log("✅ AuditLog table verified - ready for use!");
|
||||||
|
|
||||||
|
// Check row count
|
||||||
|
const countResult = await conn.execute({
|
||||||
|
sql: `SELECT COUNT(*) as count FROM AuditLog`
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`📊 Current audit log entries: ${countResult.rows[0]?.count || 0}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error("❌ AuditLog table was not created properly");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\n✅ Audit logging system is ready!");
|
||||||
|
console.log("💡 You can now use the audit logging features");
|
||||||
|
console.log("📖 See docs/AUDIT_LOGGING.md for usage examples\n");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Failed to initialize AuditLog table:");
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run if executed directly
|
||||||
|
if (import.meta.main) {
|
||||||
|
initAuditTable()
|
||||||
|
.then(() => process.exit(0))
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { initAuditTable };
|
||||||
Reference in New Issue
Block a user