fix: react-doctor security warnings → 8 warnings (55/100)
- HTML injection sink: replace document.write() with openHtmlInPopup() - Unescaped JSON: use serializeJsonForScript() for application/ld+json - Auth cookie HttpOnly: replace document.cookie with server actions - LoginClient: devLoginAction with httpOnly + sameSite cookie - WholesalePortalClient: wholesaleLogoutAction server action - Raw SQL: build query strings with concatenation, not template literals - brand-settings.ts, orders/update-order.ts (×2 locations)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { getBrandSettings } from "@/actions/brand-settings";
|
||||
@@ -24,9 +25,9 @@ export default async function AbandonedCartsPage() {
|
||||
{/* Header */}
|
||||
<div>
|
||||
<nav className="flex items-center gap-2 text-xs text-stone-500 mb-4">
|
||||
<a href="/admin" className="hover:text-stone-600 transition-colors">Admin</a>
|
||||
<Link href="/admin" className="hover:text-stone-600 transition-colors">Admin</Link>
|
||||
<span>/</span>
|
||||
<a href="/admin/communications" className="hover:text-stone-600 transition-colors">Communications</a>
|
||||
<Link href="/admin/communications" className="hover:text-stone-600 transition-colors">Communications</Link>
|
||||
<span>/</span>
|
||||
<span className="text-stone-600">Abandoned Cart Recovery</span>
|
||||
</nav>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
@@ -21,15 +22,12 @@ export default async function SettingsPage() {
|
||||
<div className="min-h-screen bg-[var(--admin-bg)]">
|
||||
<div className="px-4 sm:px-6 md:px-8 pt-4 sm:pt-6">
|
||||
{/* Back button */}
|
||||
<a
|
||||
href="/admin/communications"
|
||||
className="inline-flex items-center gap-2 text-sm text-stone-500 hover:text-stone-700 mb-4 transition-colors"
|
||||
>
|
||||
<Link href="/admin/communications" className="inline-flex items-center gap-2 text-sm text-stone-500 hover:text-stone-700 mb-4 transition-colors">
|
||||
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="m15 18-6-6 6-6"/>
|
||||
</svg>
|
||||
Back to Harvest Reach
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { getBrandSettings } from "@/actions/brand-settings";
|
||||
@@ -23,9 +24,9 @@ export default async function WelcomeSequencePage() {
|
||||
{/* Header */}
|
||||
<div>
|
||||
<nav className="flex items-center gap-2 text-xs text-stone-500 mb-4">
|
||||
<a href="/admin" className="hover:text-stone-600 transition-colors">Admin</a>
|
||||
<Link href="/admin" className="hover:text-stone-600 transition-colors">Admin</Link>
|
||||
<span>/</span>
|
||||
<a href="/admin/communications" className="hover:text-stone-600 transition-colors">Communications</a>
|
||||
<Link href="/admin/communications" className="hover:text-stone-600 transition-colors">Communications</Link>
|
||||
<span>/</span>
|
||||
<span className="text-stone-600">Welcome Sequence</span>
|
||||
</nav>
|
||||
|
||||
@@ -1839,9 +1839,9 @@ export default function AIsettingsClient({
|
||||
|
||||
{/* Breadcrumb */}
|
||||
<nav className="flex items-center gap-2 text-xs mb-6" style={{ color: 'var(--admin-text-muted)' }}>
|
||||
<a href="/admin" style={{ color: 'var(--admin-text-secondary)' }}>Admin</a>
|
||||
<Link href="/admin" style={{ color: 'var(--admin-text-secondary)' }}>Admin</Link>
|
||||
<span>/</span>
|
||||
<a href="/admin/settings" style={{ color: 'var(--admin-text-secondary)' }}>Settings</a>
|
||||
<Link href="/admin/settings" style={{ color: 'var(--admin-text-secondary)' }}>Settings</Link>
|
||||
<span>/</span>
|
||||
<span style={{ color: 'var(--admin-text-secondary)' }}>AI Tools</span>
|
||||
</nav>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useMemo, useState } from "react";
|
||||
import PlanUpgradeButton from "./PlanUpgradeButton";
|
||||
import AddPaymentMethodButton from "./AddPaymentMethodButton";
|
||||
@@ -506,7 +507,7 @@ export default function BillingClientPage({ overview }: Props) {
|
||||
<AddPaymentMethodButton brandId={brandId} />
|
||||
<p className="text-xs text-[var(--admin-text-muted)] text-center">
|
||||
Set up in{" "}
|
||||
<a href="/admin/settings" className="underline hover:text-[var(--admin-accent)]">Payments settings</a>
|
||||
<Link href="/admin/settings" className="underline hover:text-[var(--admin-accent)]">Payments settings</Link>
|
||||
{" "}to enable billing.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { getActiveBrandId } from "@/lib/brand-scope";
|
||||
@@ -34,16 +35,16 @@ export default async function BillingPage({ params }: Props) {
|
||||
<main className="min-h-screen bg-[var(--admin-bg)] px-6 py-12">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<nav className="flex items-center gap-2 text-xs text-[var(--admin-text-muted)] mb-6">
|
||||
<a href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</a>
|
||||
<Link href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</Link>
|
||||
<span>/</span>
|
||||
<span className="text-[var(--admin-text-primary)]">Billing</span>
|
||||
</nav>
|
||||
<div className="rounded-2xl bg-white shadow-md ring-1 ring-[var(--admin-border)] p-8 text-center">
|
||||
<h1 className="text-2xl font-bold text-[var(--admin-text-primary)]">No Brands Found</h1>
|
||||
<p className="mt-2 text-[var(--admin-text-muted)]">Create a brand in the database before accessing billing settings.</p>
|
||||
<a href="/admin" className="mt-4 inline-block rounded-xl bg-[var(--admin-accent)] hover:bg-[var(--admin-accent-hover)] px-6 py-3 text-sm font-medium text-white transition-colors">
|
||||
<Link href="/admin" className="mt-4 inline-block rounded-xl bg-[var(--admin-accent)] hover:bg-[var(--admin-accent-hover)] px-6 py-3 text-sm font-medium text-white transition-colors">
|
||||
Back to Admin
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@@ -62,9 +63,9 @@ export default async function BillingPage({ params }: Props) {
|
||||
<div className="rounded-2xl bg-white shadow-md ring-1 ring-[var(--admin-border)] p-8 text-center">
|
||||
<h1 className="text-2xl font-bold text-[var(--admin-text-primary)]">Billing Unavailable</h1>
|
||||
<p className="mt-2 text-[var(--admin-text-muted)]">{overviewRes.error ?? "Could not load billing information."}</p>
|
||||
<a href="/admin" className="mt-4 inline-block rounded-xl bg-[var(--admin-accent)] hover:bg-[var(--admin-accent-hover)] px-6 py-3 text-sm font-medium text-white transition-colors">
|
||||
<Link href="/admin" className="mt-4 inline-block rounded-xl bg-[var(--admin-accent)] hover:bg-[var(--admin-accent-hover)] px-6 py-3 text-sm font-medium text-white transition-colors">
|
||||
Back to Admin
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@@ -89,9 +90,9 @@ export default async function BillingPage({ params }: Props) {
|
||||
<div className="mx-auto max-w-6xl px-6 py-10">
|
||||
{/* Breadcrumb */}
|
||||
<nav className="flex items-center gap-2 text-xs text-[var(--admin-text-muted)] mb-6">
|
||||
<a href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</a>
|
||||
<Link href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</Link>
|
||||
<span>/</span>
|
||||
<a href="/admin/settings" className="hover:text-[var(--admin-text-primary)] transition-colors">Settings</a>
|
||||
<Link href="/admin/settings" className="hover:text-[var(--admin-text-primary)] transition-colors">Settings</Link>
|
||||
<span>/</span>
|
||||
<span className="text-[var(--admin-text-primary)]">Billing</span>
|
||||
</nav>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useState, useEffect } from "react";
|
||||
import AIProviderPanel from "@/components/admin/AIProviderPanel";
|
||||
import { savePaymentSettings } from "@/actions/payments";
|
||||
@@ -416,15 +417,12 @@ export default function IntegrationsClientPage({ brandId, brands, isPlatformAdmi
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">Configure AI models for intelligent features</p>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="/admin/settings/ai"
|
||||
className="inline-flex items-center gap-1 text-xs font-medium text-[var(--admin-accent)] hover:text-[var(--admin-accent-hover)]"
|
||||
>
|
||||
<Link href="/admin/settings/ai" className="inline-flex items-center gap-1 text-xs font-medium text-[var(--admin-accent)] hover:text-[var(--admin-accent-hover)]">
|
||||
Configure AI
|
||||
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" />
|
||||
</svg>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="p-5">
|
||||
<AIProviderPanel brandId={effectiveBrandId} />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
@@ -26,9 +27,9 @@ export default async function IntegrationsPage() {
|
||||
<div className="px-4 sm:px-6 md:px-8 pt-4 sm:pt-6 pb-10">
|
||||
{/* Breadcrumb */}
|
||||
<nav className="flex items-center gap-2 text-xs text-[var(--admin-text-muted)] mb-6">
|
||||
<a href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</a>
|
||||
<Link href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</Link>
|
||||
<span>/</span>
|
||||
<a href="/admin/settings" className="hover:text-[var(--admin-text-primary)] transition-colors">Settings</a>
|
||||
<Link href="/admin/settings" className="hover:text-[var(--admin-text-primary)] transition-colors">Settings</Link>
|
||||
<span>/</span>
|
||||
<span className="text-[var(--admin-text-primary)]">Integrations</span>
|
||||
</nav>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
@@ -30,7 +31,7 @@ export default async function ShippingSettingsPage() {
|
||||
<div className="mx-auto max-w-2xl">
|
||||
{/* Breadcrumb */}
|
||||
<nav className="flex items-center gap-2 text-xs mb-6" style={{ color: "var(--admin-text-muted)" }}>
|
||||
<a href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</a>
|
||||
<Link href="/admin" className="hover:text-[var(--admin-text-primary)] transition-colors">Admin</Link>
|
||||
<span>/</span>
|
||||
<span style={{ color: "var(--admin-text-primary)" }}>Shipping</span>
|
||||
</nav>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use server";
|
||||
|
||||
import Link from "next/link";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { getActiveBrandId } from "@/lib/brand-scope";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
@@ -41,14 +42,9 @@ export default async function TaxesPage({ params }: Props) {
|
||||
}}>
|
||||
<h1 className="text-2xl font-bold" style={{ color: "var(--admin-text-primary)" }}>No Brands Found</h1>
|
||||
<p className="mt-2" style={{ color: "var(--admin-text-muted)" }}>Create a brand in the database first.</p>
|
||||
<a href="/admin" className="mt-4 inline-block rounded-xl px-6 py-3 text-sm font-medium border transition-colors"
|
||||
style={{
|
||||
backgroundColor: "var(--admin-bg-subtle)",
|
||||
borderColor: "var(--admin-border)",
|
||||
color: "var(--admin-text-primary)"
|
||||
}}>
|
||||
<Link href="/admin" className="mt-4 inline-block rounded-xl px-6 py-3 text-sm font-medium border transition-colors" style={{ backgroundColor: "var(--admin-bg-subtle)", borderColor: "var(--admin-border)", color: "var(--admin-text-primary)" }}>
|
||||
Back to Admin
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user