Security: - Disable SSL verification only in development (lib/req.js) - Wrap all JSON.parse(cookie) calls in try-catch via safeJsonParse utility - Sanitize dangerouslySetInnerHTML in blog/clinic with sanitizeHtml utility - Fix open redirect in payment page — validate URL origin before redirect - Fix cookie cleanup on 401 — use js-cookie with correct domain scope Performance: - Wrap ItemDoctor with React.memo to prevent unnecessary re-renders - Replace <img> with Next.js <Image> in blog Caption component Functionality: - Fix memory leak in Recode.js — store intervals in refs, cleanup on unmount - Add null guard on retryIcon.current before classList manipulation - Fix getParsedUserInfo in helper to handle malformed cookie gracefully Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
49 lines
1.4 KiB
JavaScript
49 lines
1.4 KiB
JavaScript
import Content from "@/components/panel/Content";
|
|
import { defineAbilitiesFor } from "@/lib/ability";
|
|
import { getUser } from "@/lib/auth";
|
|
import { redirect } from "next/navigation";
|
|
import { cookies } from "next/headers";
|
|
import { fetchReq } from "@/lib/req";
|
|
import { safeJsonParse } from "@/lib/sanitize";
|
|
|
|
async function LayoutPanel({ children }) {
|
|
const user = await getUser();
|
|
const ability = defineAbilitiesFor(user);
|
|
|
|
if (!ability.can("access", "Panel")) {
|
|
return redirect("/");
|
|
}
|
|
|
|
let representationInfo = null;
|
|
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
|
|
|
try {
|
|
const cookieStore = await cookies();
|
|
const userInfo = cookieStore.get("userInfo");
|
|
const accessToken = cookieStore.get("access_token");
|
|
|
|
if (userInfo && accessToken) {
|
|
const parsedUserInfo = safeJsonParse(userInfo.value);
|
|
if (!parsedUserInfo) return;
|
|
const representationUuid = parsedUserInfo?.representation_uuid;
|
|
|
|
if (representationUuid) {
|
|
representationInfo = await fetchReq(
|
|
`${API_URL}/api/v1/representation/${representationUuid}`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${accessToken.value}`,
|
|
},
|
|
}
|
|
);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Error fetching representation info:", error);
|
|
}
|
|
|
|
return <Content children={children} representationInfo={representationInfo} />;
|
|
}
|
|
|
|
export default LayoutPanel;
|