fix: protect admin routes and ignore local docs
This commit is contained in:
1 parent
6a08db8dd0
commit
17264dfc06
6 files changed
+37
-413
No files matched your search
@@ -13,3 +13,6 @@ prod.log
|
||||
|
||||
# Database backups
|
||||
db_backup_*.sql
|
||||
|
||||
# Local project documentation
|
||||
/docs/
|
||||
@@ -1,345 +0,0 @@
|
||||
# EpicNext CMS Admin Feature Recovery Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Restore all admin functionality removed by `4d515bc` and make the complete EpicNext CMS application pass tests, typecheck, and production build.
|
||||
|
||||
**Architecture:** Revert the destructive revert, inventory unresolved imports, then port the smallest compatible shared and domain layers from `E:\Users\simol\Desktop\habbo-next`. EpicNext CMS remains authoritative for routing, authentication, Prisma models, and error handling.
|
||||
|
||||
**Tech Stack:** Next.js 16, React 19, TypeScript, Prisma 7/MariaDB, NextAuth 5, Vitest, Tailwind CSS 4, Radix UI/shadcn-style primitives.
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Never delete a feature merely to make compilation succeed.
|
||||
- Treat `E:\Users\simol\Desktop\habbo-next` as read-only reference material.
|
||||
- Preserve all security, PayPal, pagination, and public contrast changes from `4a1e111`.
|
||||
- Adapt every database operation to EpicNext CMS's local Prisma schema.
|
||||
- Every server mutation must use the existing staff authorization path and validated input.
|
||||
- Do not push until `pnpm test`, `pnpm typecheck`, and `pnpm build` all exit zero.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Restore the Removed Feature Set and Capture the Failure Inventory
|
||||
|
||||
**Files:**
|
||||
- Restore: files deleted or rewound by commit `4d515bc`
|
||||
- Create: `scripts/check-local-imports.mjs`
|
||||
- Test: `src/lib/local-imports.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: `findMissingLocalImports(root: string): Promise<Array<{ importer: string; specifier: string }>>`
|
||||
- Produces: a deterministic unresolved-import report used by every later task.
|
||||
|
||||
- [ ] **Step 1: Write a failing local-import test**
|
||||
|
||||
Create a fixture containing `import { Button } from "@/components/ui/button"` and assert that `findMissingLocalImports()` reports it when no matching file exists.
|
||||
|
||||
- [ ] **Step 2: Verify RED**
|
||||
|
||||
Run: `pnpm vitest run src/lib/local-imports.test.ts`
|
||||
|
||||
Expected: failure because the scanner does not exist.
|
||||
|
||||
- [ ] **Step 3: Implement the scanner**
|
||||
|
||||
Scan `.ts` and `.tsx` files, resolve `@/` against `src`, and test `.ts`, `.tsx`, `.js`, `.jsx`, and `/index` candidates. Return sorted importer/specifier pairs and expose the same function through `scripts/check-local-imports.mjs` for CI output.
|
||||
|
||||
- [ ] **Step 4: Verify GREEN**
|
||||
|
||||
Run: `pnpm vitest run src/lib/local-imports.test.ts`
|
||||
|
||||
Expected: fixture test passes.
|
||||
|
||||
- [ ] **Step 5: Restore functionality**
|
||||
|
||||
Run: `git revert 4d515bc`
|
||||
|
||||
Resolve overlaps by preserving current security/contrast implementations while restoring every admin consumer and action from `41be683`.
|
||||
|
||||
- [ ] **Step 6: Capture the build and import failures**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node scripts/check-local-imports.mjs
|
||||
$env:DATABASE_URL='mysql://user:[email protected]:3306/atomcms'
|
||||
pnpm prisma:generate
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Expected: build fails for unresolved modules, and the scanner lists the complete local dependency inventory.
|
||||
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```powershell
|
||||
git add scripts/check-local-imports.mjs src/lib/local-imports.test.ts src
|
||||
git commit -m "fix: restore incomplete admin feature set"
|
||||
```
|
||||
|
||||
### Task 2: Restore Shared UI, Hooks, Utilities, Types, and Packages
|
||||
|
||||
**Files:**
|
||||
- Create/modify: `src/components/ui/*.tsx`
|
||||
- Create: `src/hooks/use-server-action.ts`
|
||||
- Create/modify: `src/lib/utils.ts`
|
||||
- Create/modify: `src/types/index.ts`
|
||||
- Modify: `package.json`
|
||||
- Modify: `pnpm-lock.yaml`
|
||||
- Test: `src/hooks/use-server-action.test.tsx`
|
||||
- Test: `src/lib/utils.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: `cn(...inputs: ClassValue[]): string`
|
||||
- Produces: `useServerAction<TArgs, TResult>(action, options)` with pending, result, and error state.
|
||||
- Produces: shadcn-compatible exports consumed by restored admin pages, including Button, Badge, Card, Dialog, Input, Label, Select, Table, Tabs, Textarea, Checkbox, Command, Popover, Switch, Tooltip, Skeleton, and AlertDialog.
|
||||
|
||||
- [ ] **Step 1: Add failing utility and hook tests**
|
||||
|
||||
Assert that `cn("a", false && "b", "c")` returns `"a c"`, conflicting Tailwind classes merge correctly, successful actions expose results, and thrown actions expose a safe error while clearing pending state.
|
||||
|
||||
- [ ] **Step 2: Verify RED**
|
||||
|
||||
Run: `pnpm vitest run src/lib/utils.test.ts src/hooks/use-server-action.test.tsx`
|
||||
|
||||
Expected: missing-module failures.
|
||||
|
||||
- [ ] **Step 3: Port the minimal shared layer**
|
||||
|
||||
Use the corresponding Habbo Next files as reference. Remove locale routing and unrelated providers. Add only packages directly imported by restored consumers, including Radix primitives, `class-variance-authority`, `clsx`, `tailwind-merge`, `cmdk`, `sonner`, and the three `@dnd-kit` packages.
|
||||
|
||||
- [ ] **Step 4: Verify GREEN and rescan**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
pnpm vitest run src/lib/utils.test.ts src/hooks/use-server-action.test.tsx
|
||||
node scripts/check-local-imports.mjs
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
Expected: shared-layer tests pass; remaining missing imports are domain-specific.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```powershell
|
||||
git add package.json pnpm-lock.yaml src/components/ui src/hooks src/lib/utils.ts src/lib/utils.test.ts src/types
|
||||
git commit -m "fix: restore admin shared component layer"
|
||||
```
|
||||
|
||||
### Task 3: Restore Catalog and Furni Import Domains
|
||||
|
||||
**Files:**
|
||||
- Create/modify: `src/components/admin/catalog/**`
|
||||
- Create/modify: `src/components/admin/catalog-manager/**`
|
||||
- Create/modify: `src/lib/furni/**`
|
||||
- Create/modify: `src/lib/client-cache/**`
|
||||
- Create/modify: `src/lib/catalog-layouts.ts`
|
||||
- Create/modify: `src/lib/move-suggestions.ts`
|
||||
- Modify: `src/actions/catalog.ts`
|
||||
- Modify: `src/actions/catalog-bc.ts`
|
||||
- Modify: `src/actions/catalog-items.ts`
|
||||
- Modify: `src/actions/import-badges.ts`
|
||||
- Modify: `src/actions/import-furni.ts`
|
||||
- Test: focused tests under `src/lib/furni/*.test.ts` and `src/actions/catalog-items.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: catalog page/item CRUD actions returning `{ ok: true; data } | { ok: false; error }`.
|
||||
- Produces: safe furni classname/path helpers and import validation.
|
||||
|
||||
- [ ] **Step 1: Add failing tests**
|
||||
|
||||
Cover invalid catalog identifiers, unauthorized mutation, safe furni classnames, duplicate imported items, and transactional bulk updates.
|
||||
|
||||
- [ ] **Step 2: Verify RED**
|
||||
|
||||
Run: `pnpm vitest run src/lib/furni src/actions/catalog-items.test.ts`
|
||||
|
||||
- [ ] **Step 3: Port and adapt implementations**
|
||||
|
||||
Use Habbo Next catalog/import helpers as reference. Replace `[locale]` paths with EpicNext routes, use `requireStaffRateLimited()`, and map every Prisma field against `prisma/schema.prisma` before writing queries.
|
||||
|
||||
- [ ] **Step 4: Verify GREEN and checkpoint build**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
pnpm vitest run src/lib/furni src/actions/catalog-items.test.ts
|
||||
node scripts/check-local-imports.mjs
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```powershell
|
||||
git add src/components/admin/catalog src/components/admin/catalog-manager src/lib/furni src/lib/client-cache src/lib/catalog-layouts.ts src/lib/move-suggestions.ts src/actions/catalog*.ts src/actions/import-*.ts
|
||||
git commit -m "fix: restore catalog and furni administration"
|
||||
```
|
||||
|
||||
### Task 4: Restore Permissions, Users, and Rooms
|
||||
|
||||
**Files:**
|
||||
- Create/modify: `src/lib/permissions.ts`
|
||||
- Create/modify: `src/lib/admin-list.ts`
|
||||
- Create/modify: `src/lib/imager.ts`
|
||||
- Create/modify: `src/lib/services/watch.ts`
|
||||
- Modify: `src/actions/permissions.ts`
|
||||
- Modify: `src/actions/bulk-users.ts`
|
||||
- Modify: `src/actions/rooms.ts`
|
||||
- Modify: `src/actions/multi-account-detect.ts`
|
||||
- Test: `src/lib/permissions.test.ts`, `src/actions/permissions.test.ts`, `src/actions/rooms.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: permission reads and mutations based on EpicNext rank tables.
|
||||
- Produces: room and bulk-user actions with staff checks and validated numeric IDs.
|
||||
|
||||
- [ ] **Step 1: Add failing authorization and schema tests**
|
||||
|
||||
Test denial without a staff session, denial without the named permission, preservation of immutable permission fields, positive integer IDs, and atomic room updates.
|
||||
|
||||
- [ ] **Step 2: Verify RED**
|
||||
|
||||
Run: `pnpm vitest run src/lib/permissions.test.ts src/actions/permissions.test.ts src/actions/rooms.test.ts`
|
||||
|
||||
- [ ] **Step 3: Implement against the EpicNext schema**
|
||||
|
||||
Use Habbo Next only for workflow structure. Preserve EpicNext's `resolveStaffUser` path and adapt permission/rank queries to actual local Prisma models.
|
||||
|
||||
- [ ] **Step 4: Verify GREEN and typecheck**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
pnpm vitest run src/lib/permissions.test.ts src/actions/permissions.test.ts src/actions/rooms.test.ts
|
||||
node scripts/check-local-imports.mjs
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```powershell
|
||||
git add src/lib/permissions.ts src/lib/admin-list.ts src/lib/imager.ts src/lib/services/watch.ts src/actions/permissions.ts src/actions/bulk-users.ts src/actions/rooms.ts src/actions/multi-account-detect.ts src/app/admin/permissions src/app/admin/users src/app/admin/rooms
|
||||
git commit -m "fix: restore permissions users and room administration"
|
||||
```
|
||||
|
||||
### Task 5: Restore Tickets, Translations, and Sounds
|
||||
|
||||
**Files:**
|
||||
- Create/modify: `src/actions/tickets.ts`
|
||||
- Create/modify: `src/actions/ticket-templates.ts`
|
||||
- Create/modify: `src/actions/translations.ts`
|
||||
- Create/modify: `src/lib/services/ticket-replies.ts`
|
||||
- Create/modify: sound and translation helpers identified by the import scanner.
|
||||
- Test: `src/actions/tickets.test.ts`, `src/actions/translations.test.ts`, existing `src/lib/services/ticket-replies.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: ticket assignment/status/priority/reply actions.
|
||||
- Produces: template CRUD actions.
|
||||
- Produces: validated CMS/client translation writes.
|
||||
- Produces: sound metadata operations required by admin pages.
|
||||
|
||||
- [ ] **Step 1: Add failing domain tests**
|
||||
|
||||
Cover cross-ticket reply rejection, invalid status transitions, template ownership/permission, translation key validation, path traversal rejection, and unsupported sound metadata.
|
||||
|
||||
- [ ] **Step 2: Verify RED**
|
||||
|
||||
Run: `pnpm vitest run src/actions/tickets.test.ts src/actions/translations.test.ts src/lib/services/ticket-replies.test.ts`
|
||||
|
||||
- [ ] **Step 3: Port compatible implementations**
|
||||
|
||||
Use Habbo Next actions as behavioral reference, route errors through `logServerError`, validate all identifiers and paths, and retain EpicNext's existing ticket-reply service protections.
|
||||
|
||||
- [ ] **Step 4: Verify GREEN and clear imports**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
pnpm vitest run src/actions/tickets.test.ts src/actions/translations.test.ts src/lib/services/ticket-replies.test.ts
|
||||
node scripts/check-local-imports.mjs
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
Expected: zero unresolved local imports.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```powershell
|
||||
git add src/actions/tickets.ts src/actions/ticket-templates.ts src/actions/translations.ts src/lib/services src/app/admin/tickets src/app/admin/translations src/app/admin/sounds
|
||||
git commit -m "fix: restore ticket translation and sound administration"
|
||||
```
|
||||
|
||||
### Task 6: Integration Hardening and Navigation
|
||||
|
||||
**Files:**
|
||||
- Modify: restored admin navigation and messages.
|
||||
- Modify: action files with inconsistent result or authorization contracts.
|
||||
- Test: `src/lib/admin-action-contract.test.ts`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: consistent admin action contract and reachable navigation for every restored page.
|
||||
|
||||
- [ ] **Step 1: Add failing contract checks**
|
||||
|
||||
Assert every restored action module begins with `"use server"`, imports an approved staff guard for mutations, and every restored route has a navigation label in all supported message files.
|
||||
|
||||
- [ ] **Step 2: Verify RED**
|
||||
|
||||
Run: `pnpm vitest run src/lib/admin-action-contract.test.ts`
|
||||
|
||||
- [ ] **Step 3: Correct integration gaps**
|
||||
|
||||
Add missing guards, stable result shapes, narrow `revalidatePath()` calls, navigation entries, and translations without changing unrelated public behavior.
|
||||
|
||||
- [ ] **Step 4: Verify GREEN**
|
||||
|
||||
Run: `pnpm vitest run src/lib/admin-action-contract.test.ts`
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```powershell
|
||||
git add src/actions src/components/admin src/app/admin src/messages src/lib/admin-action-contract.test.ts
|
||||
git commit -m "fix: harden restored admin integrations"
|
||||
```
|
||||
|
||||
### Task 7: Full Verification and Publication
|
||||
|
||||
**Files:**
|
||||
- Modify only files required by fresh verification failures.
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: a complete, buildable `main` with restored admin functionality.
|
||||
|
||||
- [ ] **Step 1: Clean generated state and generate Prisma**
|
||||
|
||||
```powershell
|
||||
Remove-Item -Recurse -Force .next -ErrorAction SilentlyContinue
|
||||
$env:DATABASE_URL='mysql://user:[email protected]:3306/atomcms'
|
||||
pnpm prisma:generate
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run complete gates**
|
||||
|
||||
```powershell
|
||||
node scripts/check-local-imports.mjs
|
||||
pnpm test
|
||||
pnpm typecheck
|
||||
pnpm build
|
||||
git diff --check nextjs/main..HEAD
|
||||
```
|
||||
|
||||
Expected: zero missing imports, zero failed tests, typecheck exit 0, build exit 0, and clean diff check.
|
||||
|
||||
- [ ] **Step 3: Audit retained fixes**
|
||||
|
||||
Confirm PayPal capture ownership/idempotency, staff session normalization, safe pagination, and readable theme variables remain present and covered by their existing tests.
|
||||
|
||||
- [ ] **Step 4: Fetch and publish only by fast-forward**
|
||||
|
||||
```powershell
|
||||
git fetch nextjs main
|
||||
git rev-list --left-right --count nextjs/main...HEAD
|
||||
git push nextjs HEAD:main
|
||||
git ls-remote nextjs refs/heads/main
|
||||
```
|
||||
|
||||
Expected before push: `0 N`. Expected after push: remote SHA equals local `HEAD`.
|
||||
@@ -1,67 +0,0 @@
|
||||
# EpicNext CMS Admin Feature Recovery Design
|
||||
|
||||
## Objective
|
||||
|
||||
Restore every admin page and server action introduced by commit `41be683` without reintroducing unresolved imports or sacrificing the security, PayPal, pagination, and public-theme contrast fixes already on `main`.
|
||||
|
||||
`E:\Users\simol\Desktop\habbo-next` is a read-only architectural reference. Its files may guide implementation, but EpicNext CMS keeps its own routing, authentication, Prisma schema, conventions, and public behavior.
|
||||
|
||||
## Constraints
|
||||
|
||||
- No feature may be removed merely to make compilation succeed.
|
||||
- Do not modify `E:\Users\simol\Desktop\habbo-next`.
|
||||
- Do not overwrite or depend on uncommitted changes in the user's original AtomCMS checkout.
|
||||
- Preserve the existing security, PayPal, pagination, and contrast changes.
|
||||
- Adapt referenced code to EpicNext CMS rather than copying it blindly.
|
||||
- Publish to `main` only after tests, typecheck, and production build pass.
|
||||
|
||||
## Recovery Architecture
|
||||
|
||||
Recovery proceeds in dependency order. First restore the shared foundation used by the imported admin pages: package dependencies, UI primitives, hooks, utilities, common types, permissions helpers, cache helpers, and focused domain services. Restore feature groups only after that foundation compiles.
|
||||
|
||||
Feature groups are:
|
||||
|
||||
1. Catalog and furni import.
|
||||
2. Permissions and users.
|
||||
3. Rooms and room furni.
|
||||
4. Tickets and ticket templates.
|
||||
5. Translations.
|
||||
6. Sounds and remaining admin navigation.
|
||||
|
||||
Each group must expose explicit server-action interfaces and use the existing EpicNext CMS staff authorization guard. Data access must match the local Prisma schema; Habbo Next models and field names are references, not assumptions.
|
||||
|
||||
## Data and Authorization Flow
|
||||
|
||||
Client admin components invoke typed server actions. Each mutation validates input, resolves the signed-in staff member through the existing guard, checks the relevant permission or minimum rank, performs a Prisma transaction where multiple writes must be atomic, and returns a stable result shape suitable for the existing `useServerAction` hook. Successful mutations invalidate the narrowest affected route or cache key.
|
||||
|
||||
User-controlled paths, URLs, identifiers, JSON, and imported archive content are validated before filesystem or database access. Errors returned to clients remain safe and actionable; detailed failures go through the existing server logger.
|
||||
|
||||
## Source-Recovery Method
|
||||
|
||||
Restore the feature consumers from `41be683`, then generate a complete unresolved-import inventory. For every missing module:
|
||||
|
||||
- Prefer an existing EpicNext CMS implementation when available.
|
||||
- Otherwise use the corresponding Habbo Next file as a behavioral reference.
|
||||
- Remove locale-specific routing assumptions and unsupported integrations.
|
||||
- Port only the API needed by current consumers.
|
||||
- Add the smallest compatible dependency set to `package.json`.
|
||||
|
||||
This avoids both extremes: deleting consumers to hide failures and copying the entire Habbo Next application into EpicNext CMS.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
The previously failing production build is the top-level regression test. Lower-level tests cover permission checks, validation, transactional behavior, error results, and domain helpers. Recovery follows red-green cycles: expose one missing dependency or failing behavior, add the minimal compatible implementation, then rerun its focused test.
|
||||
|
||||
Every feature-group checkpoint requires:
|
||||
|
||||
- Focused Vitest tests for new helpers and action behavior.
|
||||
- `pnpm typecheck` after regenerating Next route metadata where necessary.
|
||||
- `pnpm test` with zero failures.
|
||||
- `pnpm build` with a valid build-time database configuration.
|
||||
- An unresolved-import scan with zero missing local modules.
|
||||
|
||||
The final build may log database connection warnings when run against a deliberately unreachable validation URL, but it must exit successfully and produce the expected route manifest.
|
||||
|
||||
## Delivery
|
||||
|
||||
Work occurs in the existing isolated publication worktree on a dedicated recovery branch. Commits are grouped by independently verifiable dependency or feature boundaries. Nothing is pushed to `main` until the complete restored application passes all final gates and the remote branch is confirmed unchanged before a fast-forward push.
|
||||
@@ -0,0 +1,14 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { shouldRedirectAdminRequest } from "./proxy-access";
|
||||
|
||||
describe("shouldRedirectAdminRequest", () => {
|
||||
it("redirects anonymous and non-staff admin requests before rendering", () => {
|
||||
expect(shouldRedirectAdminRequest("/admin", null)).toBe(true);
|
||||
expect(shouldRedirectAdminRequest("/admin/tickets", { rank: 1 })).toBe(true);
|
||||
});
|
||||
|
||||
it("allows staff admin requests and never affects public routes", () => {
|
||||
expect(shouldRedirectAdminRequest("/admin/permissions", { rank: 7 })).toBe(false);
|
||||
expect(shouldRedirectAdminRequest("/news", null)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface ProxyToken {
|
||||
rank?: unknown;
|
||||
}
|
||||
|
||||
export function shouldRedirectAdminRequest(pathname: string, token: ProxyToken | null): boolean {
|
||||
if (pathname !== "/admin" && !pathname.startsWith("/admin/")) return false;
|
||||
const rank = typeof token?.rank === "number" ? token.rank : Number(token?.rank);
|
||||
return !Number.isInteger(rank) || rank < 7;
|
||||
}
|
||||
+11
-1
@@ -1,10 +1,20 @@
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
import { shouldRedirectAdminRequest } from "@/lib/proxy-access";
|
||||
|
||||
// Edge proxy (formerly "middleware"): Prisma can't run here, so we only forward
|
||||
// the request path (so server components / the access guard can read it via
|
||||
// headers()) and normalize the real client IP. The DB-backed banned/maintenance
|
||||
// checks happen in src/lib/access-guard.ts (Node runtime) from the root layout.
|
||||
export function proxy(req: NextRequest) {
|
||||
export async function proxy(req: NextRequest) {
|
||||
if (req.nextUrl.pathname === "/admin" || req.nextUrl.pathname.startsWith("/admin/")) {
|
||||
const secret = process.env.AUTH_SECRET;
|
||||
const token = secret ? await getToken({ req, secret }) : null;
|
||||
if (shouldRedirectAdminRequest(req.nextUrl.pathname, token)) {
|
||||
return NextResponse.redirect(new URL("/login", req.url));
|
||||
}
|
||||
}
|
||||
|
||||
const headers = new Headers(req.headers);
|
||||
headers.set("x-pathname", req.nextUrl.pathname);
|
||||
const ip =
|
||||
|
||||
Reference in new issue
Block a user