mirror of
https://github.com/JetSprow/J-Board-Lite.git
synced 2026-05-01 01:14:10 +05:30
fix: harden secrets and session checks
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "./auth";
|
||||
import { jsonError } from "./api-response";
|
||||
import { getActiveSession } from "./require-auth";
|
||||
|
||||
export async function requireAdminApiSession() {
|
||||
const session = await getServerSession(authOptions);
|
||||
const session = await getActiveSession();
|
||||
if (!session || session.user.role !== "ADMIN") {
|
||||
return {
|
||||
session: null,
|
||||
|
||||
@@ -3,6 +3,7 @@ import CredentialsProvider from "next-auth/providers/credentials";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { prisma } from "./prisma";
|
||||
import { verifyTurnstile } from "./turnstile";
|
||||
import { decryptIfEncrypted } from "./crypto";
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
providers: [
|
||||
@@ -17,9 +18,12 @@ export const authOptions: NextAuthOptions = {
|
||||
if (!credentials?.email || !credentials?.password) return null;
|
||||
|
||||
const config = await prisma.appConfig.findUnique({ where: { id: "default" } });
|
||||
if (config?.turnstileSecretKey) {
|
||||
const turnstileSecretKey = config?.turnstileSecretKey
|
||||
? decryptIfEncrypted(config.turnstileSecretKey)
|
||||
: "";
|
||||
if (turnstileSecretKey) {
|
||||
const token = credentials.turnstileToken;
|
||||
if (!token || !(await verifyTurnstile(token, config.turnstileSecretKey))) {
|
||||
if (!token || !(await verifyTurnstile(token, turnstileSecretKey))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,22 @@ export function encrypt(text: string): string {
|
||||
return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted.toString("hex")}`;
|
||||
}
|
||||
|
||||
function isHexBytes(value: string) {
|
||||
return value.length > 0 && value.length % 2 === 0 && /^[0-9a-f]+$/i.test(value);
|
||||
}
|
||||
|
||||
export function isEncryptedValue(data: string): boolean {
|
||||
const parts = data.split(":");
|
||||
if (parts.length !== 3) return false;
|
||||
|
||||
const [ivHex, authTagHex, encryptedHex] = parts;
|
||||
return ivHex.length === 32
|
||||
&& authTagHex.length === 32
|
||||
&& isHexBytes(ivHex)
|
||||
&& isHexBytes(authTagHex)
|
||||
&& isHexBytes(encryptedHex);
|
||||
}
|
||||
|
||||
export function decrypt(data: string): string {
|
||||
const parts = data.split(":");
|
||||
if (parts.length !== 3) {
|
||||
@@ -28,3 +44,7 @@ export function decrypt(data: string): string {
|
||||
decipher.setAuthTag(Buffer.from(authTagHex, "hex"));
|
||||
return decipher.update(Buffer.from(encryptedHex, "hex")) + decipher.final("utf8");
|
||||
}
|
||||
|
||||
export function decryptIfEncrypted(data: string): string {
|
||||
return isEncryptedValue(data) ? decrypt(data) : data;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "./auth";
|
||||
import { prisma } from "./prisma";
|
||||
import { getActiveSubscriptionRiskRestriction } from "@/services/subscription-risk-review";
|
||||
|
||||
export async function requireAdmin() {
|
||||
export async function getActiveSession() {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) return null;
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: session.user.id },
|
||||
select: { id: true, email: true, name: true, role: true, status: true },
|
||||
});
|
||||
|
||||
if (!user || user.status !== "ACTIVE") return null;
|
||||
|
||||
session.user.id = user.id;
|
||||
session.user.email = user.email;
|
||||
session.user.name = user.name;
|
||||
session.user.role = user.role;
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
export async function requireAdmin() {
|
||||
const session = await getActiveSession();
|
||||
if (!session || session.user.role !== "ADMIN") {
|
||||
throw new Error("无权限");
|
||||
}
|
||||
@@ -11,7 +31,7 @@ export async function requireAdmin() {
|
||||
}
|
||||
|
||||
export async function requireAuth(options: { allowDuringRiskRestriction?: boolean } = {}) {
|
||||
const session = await getServerSession(authOptions);
|
||||
const session = await getActiveSession();
|
||||
if (!session) {
|
||||
throw new Error("未登录");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user