Remove unused auth middleware and utils

- Delete src/middleware/auth.ts (createAuthMiddleware, createSuperuserMiddleware)
- Delete src/utils/auth.ts (authenticateRequest)

These files were never imported or used anywhere in the codebase.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
igm
2026-01-12 17:39:07 +08:00
parent ce5a27d014
commit bd4053f952
2 changed files with 0 additions and 256 deletions

View File

@@ -1,181 +0,0 @@
/**
* Authentication middleware for oRPC server
*
* Handles authentication via:
* - Session cookie (rev.session_token) - for browser clients
* - API key header (x-api-key) - for CLI and programmatic access
*/
import type {
APIContext,
AuthenticatedContext,
AuthInfo,
Session,
SessionUser,
} from "../context.js";
import { ORPCError } from "@orpc/server";
import { COOKIE_NAMES, getCookie } from "../utils/cookies.js";
import { hashToken } from "../utils/crypto.js";
/**
* Create the auth middleware function
* This returns a middleware handler that can be used with oRPC procedures
*/
export const createAuthMiddleware = () => {
return async ({
context,
next,
}: {
context: APIContext;
next: (opts: {
context: Omit<AuthenticatedContext, keyof APIContext>;
}) => Promise<unknown>;
}) => {
const { db, reqHeaders } = context;
// Try session cookie first
let tokenHash: string | undefined;
const sessionToken = getCookie(reqHeaders, COOKIE_NAMES.SESSION_TOKEN);
if (sessionToken) {
tokenHash = await hashToken(sessionToken);
}
// Fall back to API key header (for CLI)
const apiKey = reqHeaders.get("x-api-key");
if (!tokenHash && apiKey) {
tokenHash = await hashToken(apiKey);
}
if (!tokenHash) {
throw new ORPCError("UNAUTHORIZED", { message: "No session or API key" });
}
// Look up session (check not expired and not revoked)
const session = await db
.selectFrom("sessions")
.where("token_hash", "=", tokenHash)
.where("expires_at", ">", new Date())
.where("revoked_at", "is", null)
.selectAll()
.executeTakeFirst();
// Fall back to API token if no session found
const apiToken = !session
? await db
.selectFrom("api_tokens")
.where("token_hash", "=", tokenHash)
.where("expires_at", ">", new Date())
.selectAll()
.executeTakeFirst()
: undefined;
const userId = session?.user_id ?? apiToken?.user_id;
if (!userId) {
throw new ORPCError("UNAUTHORIZED", {
message: "Invalid or expired token",
});
}
// Update last_used_at for API tokens
if (apiToken) {
await db
.updateTable("api_tokens")
.set({ last_used_at: new Date() })
.where("id", "=", apiToken.id)
.execute();
}
// Fetch user details
const user = await db
.selectFrom("users")
.where("id", "=", userId)
.select([
"id",
"email",
"display_name",
"email_verified_at",
"is_superuser",
])
.executeTakeFirst();
if (!user) {
throw new ORPCError("UNAUTHORIZED", {
message: "User not found",
});
}
const sessionUser: SessionUser = {
id: user.id,
email: user.email,
displayName: user.display_name,
emailVerifiedAt: user.email_verified_at,
isSuperuser: user.is_superuser,
};
// Build session and auth info based on authentication method
let sessionInfo: Session;
let authInfo: AuthInfo;
if (session) {
sessionInfo = {
id: session.id,
trustedMode: session.trusted_mode,
createdAt: session.created_at,
};
authInfo = {
method: "session",
sessionId: session.id,
expiresAt: session.expires_at,
createdAt: session.created_at,
};
} else if (apiToken) {
sessionInfo = {
// For API token auth, create a synthetic session object
id: "0",
trustedMode: true,
createdAt: apiToken.created_at,
};
authInfo = {
method: "api_token",
tokenId: apiToken.id,
tokenName: apiToken.name,
expiresAt: apiToken.expires_at,
lastUsedAt: apiToken.last_used_at,
createdAt: apiToken.created_at,
};
} else {
// This should never happen since we checked userId above
throw new ORPCError("UNAUTHORIZED", {
message: "Invalid authentication state",
});
}
return next({
context: {
user: sessionUser,
session: sessionInfo,
auth: authInfo,
},
});
};
};
/**
* Middleware to require superuser access
*/
export const createSuperuserMiddleware = () => {
return async ({
context,
next,
}: {
context: AuthenticatedContext;
next: () => Promise<unknown>;
}) => {
if (!context.user.isSuperuser) {
throw new ORPCError("FORBIDDEN", {
message: "Superuser access required",
});
}
return next();
};
};

View File

@@ -1,75 +0,0 @@
/**
* Authentication utilities for token handling
*/
import type { Database } from "@reviq/db-schema";
import type { Kysely } from "kysely";
import { hashToken } from "./crypto.js";
export interface AuthenticatedUser {
id: number;
email: string;
isSuperuser: boolean;
}
/**
* Authenticate a request using session token or API key
* Returns the authenticated user or null if not authenticated
*/
export const authenticateRequest = async (
db: Kysely<Database>,
sessionToken?: string,
apiKey?: string,
): Promise<AuthenticatedUser | null> => {
// Try session cookie first, then API key
const token = sessionToken ?? apiKey;
if (!token) {
return null;
}
const tokenHash = await hashToken(token);
// Check sessions table
const session = await db
.selectFrom("sessions")
.innerJoin("users", "users.id", "sessions.user_id")
.where("sessions.token_hash", "=", tokenHash)
.where("sessions.expires_at", ">", new Date())
.where("sessions.revoked_at", "is", null)
.select(["users.id", "users.email", "users.is_superuser"])
.executeTakeFirst();
if (session) {
return {
id: session.id,
email: session.email,
isSuperuser: session.is_superuser,
};
}
// Check API tokens table
const apiToken = await db
.selectFrom("api_tokens")
.innerJoin("users", "users.id", "api_tokens.user_id")
.where("api_tokens.token_hash", "=", tokenHash)
.where("api_tokens.expires_at", ">", new Date())
.select(["users.id", "users.email", "users.is_superuser"])
.executeTakeFirst();
if (apiToken) {
// Update last_used_at
await db
.updateTable("api_tokens")
.set({ last_used_at: new Date() })
.where("token_hash", "=", tokenHash)
.execute();
return {
id: apiToken.id,
email: apiToken.email,
isSuperuser: apiToken.is_superuser,
};
}
return null;
};