v1.1: Add CIDR subnet filtering and Agent filter in Devices page

This commit is contained in:
ypratama committed 2026-08-27 12:02:01 +07:00
commit 966058e2fe
422 files changed
+54656

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
import { NextRequest, NextResponse } from 'next/server';
export async function GET(req: NextRequest, props: { params: Promise<{ route: string[] }> }) {
return handleProxy(req, props);
}
export async function POST(req: NextRequest, props: { params: Promise<{ route: string[] }> }) {
return handleProxy(req, props);
}
export async function PUT(req: NextRequest, props: { params: Promise<{ route: string[] }> }) {
return handleProxy(req, props);
}
export async function DELETE(req: NextRequest, props: { params: Promise<{ route: string[] }> }) {
return handleProxy(req, props);
}
export async function PATCH(req: NextRequest, props: { params: Promise<{ route: string[] }> }) {
return handleProxy(req, props);
}
async function handleProxy(req: NextRequest, { params }: { params: Promise<{ route: string[] }> }) {
try {
const routeArray = (await params).route;
const route = routeArray.join('/');
const url = new URL(req.url);
// Force ALL traffic to go through our own Centralized Proxy Server (Express Backend)
const localBase = process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:3001';
const destinationUrl = `${localBase}/api/${route}${url.search}`;
// Prepare headers
const headers = new Headers();
const contentType = req.headers.get('content-type');
if (contentType) {
headers.set('Content-Type', contentType);
} else {
headers.set('Content-Type', 'application/json');
}
const contentLength = req.headers.get('content-length');
if (contentLength) {
headers.set('Content-Length', contentLength);
}
// Forward cookie for authentication
const cookie = req.headers.get('cookie');
if (cookie) {
headers.set('cookie', cookie);
}
// Forward all custom headers starting with x- (e.g. x-backone-site-uuid, x-view-as-agent)
req.headers.forEach((value, name) => {
if (name.toLowerCase().startsWith('x-')) {
headers.set(name, value);
}
});
const hasBody = !['GET', 'HEAD'].includes(req.method);
const body = hasBody ? req.body : undefined;
const response = await fetch(destinationUrl, {
method: req.method,
headers,
body: body,
cache: 'no-store', // Prevent Next.js from aggressively caching the backend response
// @ts-ignore
duplex: hasBody ? 'half' : undefined,
});
const responseBuffer = await response.arrayBuffer();
const nextResponse = new NextResponse(responseBuffer, {
status: response.status,
headers: {
'Content-Type': response.headers.get('content-type') || 'application/json',
}
});
const rawCookies = response.headers.getSetCookie ? response.headers.getSetCookie() : [];
if (rawCookies.length > 0) {
rawCookies.forEach(cookie => {
nextResponse.headers.append('Set-Cookie', cookie);
});
} else {
const setCookieHeader = response.headers.get('set-cookie');
if (setCookieHeader) {
nextResponse.headers.set('Set-Cookie', setCookieHeader);
}
}
return nextResponse;
} catch (error: any) {
console.error('[Proxy Error]', error);
return NextResponse.json({ ok: false, message: error.message }, { status: 500 });
}
}
@@ -0,0 +1,48 @@
import { NextRequest, NextResponse } from "next/server";
import { cookies } from "next/headers";
const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL || "http://127.0.0.1:3011";
export async function POST(req: NextRequest) {
try {
const cookieStore = await cookies();
const token = cookieStore.get("token")?.value;
// Menerima JSON dari frontend (bukan multipart)
const body = await req.json();
const headers = new Headers();
headers.set("Content-Type", "application/json");
if (token) {
headers.set("Cookie", `token=${token}`);
}
req.headers.forEach((value, name) => {
if (name.toLowerCase().startsWith("x-")) {
headers.set(name, value);
}
});
const destinationUrl = `${BACKEND_URL}/api/auth/admin/create-external-user`;
const response = await fetch(destinationUrl, {
method: "POST",
headers,
body: JSON.stringify(body),
cache: "no-store",
});
const responseBuffer = await response.arrayBuffer();
return new NextResponse(responseBuffer, {
status: response.status,
headers: {
"Content-Type": response.headers.get("content-type") || "application/json",
},
});
} catch (err: any) {
console.error("[Create External User Proxy] Error:", err.message);
return NextResponse.json(
{ ok: false, error: "Failed to connect to the server." },
{ status: 502 }
);
}
}
@@ -0,0 +1,48 @@
import { NextRequest, NextResponse } from "next/server";
import { cookies } from "next/headers";
const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL || "http://127.0.0.1:3011";
export async function POST(req: NextRequest) {
try {
const cookieStore = await cookies();
const token = cookieStore.get("token")?.value;
// Baca body sebagai JSON (tidak ada multipart lagi)
const body = await req.json();
const headers = new Headers();
headers.set("Content-Type", "application/json");
if (token) {
headers.set("Cookie", `token=${token}`);
}
req.headers.forEach((value, name) => {
if (name.toLowerCase().startsWith("x-")) {
headers.set(name, value);
}
});
const destinationUrl = `${BACKEND_URL}/api/auth/admin/update-agent-user`;
const response = await fetch(destinationUrl, {
method: "POST",
headers,
body: JSON.stringify(body),
cache: "no-store",
});
const responseBuffer = await response.arrayBuffer();
return new NextResponse(responseBuffer, {
status: response.status,
headers: {
"Content-Type": response.headers.get("content-type") || "application/json",
},
});
} catch (err: any) {
console.error("[Update Agent User Proxy] Error:", err.message);
return NextResponse.json(
{ ok: false, error: "Failed to connect to the server." },
{ status: 502 }
);
}
}
@@ -0,0 +1,53 @@
// src/app/api/auth/remove-profile-picture/route.ts
// Next.js API Route — proxies remove-profile-picture ke backend Express.
import { NextRequest, NextResponse } from "next/server";
import { cookies } from "next/headers";
const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL || "http://127.0.0.1:3001";
export async function POST(req: NextRequest) {
try {
const cookieStore = await cookies();
const token = cookieStore.get("token")?.value;
const headers: HeadersInit = { "Content-Type": "application/json" };
if (token) {
headers["Cookie"] = `token=${token}`;
}
const backendRes = await fetch(
`${BACKEND_URL}/api/auth/remove-profile-picture`,
{
method: "POST",
headers,
}
);
const contentType = backendRes.headers.get("content-type") || "";
if (!contentType.includes("application/json")) {
const text = await backendRes.text();
console.error("[Remove-Picture Proxy] Backend returned non-JSON:", text.slice(0, 200));
return NextResponse.json(
{ error: `Server error (HTTP ${backendRes.status}): Please try again.` },
{ status: backendRes.status }
);
}
const data = await backendRes.json();
const response = NextResponse.json(data, { status: backendRes.status });
const setCookie = backendRes.headers.get("set-cookie");
if (setCookie) {
response.headers.set("set-cookie", setCookie);
}
return response;
} catch (err: any) {
console.error("[Remove-Picture Proxy] Error:", err.message);
return NextResponse.json(
{ error: "Failed to connect to the server." },
{ status: 502 }
);
}
}
@@ -0,0 +1,48 @@
import { NextRequest, NextResponse } from "next/server";
import { cookies } from "next/headers";
const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL || "http://127.0.0.1:3011";
export async function POST(req: NextRequest) {
try {
const cookieStore = await cookies();
const token = cookieStore.get("token")?.value;
// Menerima JSON (base64 image) dari frontend
const body = await req.json();
const headers = new Headers();
headers.set("Content-Type", "application/json");
if (token) {
headers.set("Cookie", `token=${token}`);
}
req.headers.forEach((value, name) => {
if (name.toLowerCase().startsWith("x-")) {
headers.set(name, value);
}
});
const destinationUrl = `${BACKEND_URL}/api/auth/upload-profile-picture`;
const response = await fetch(destinationUrl, {
method: "POST",
headers,
body: JSON.stringify(body),
cache: "no-store",
});
const responseBuffer = await response.arrayBuffer();
return new NextResponse(responseBuffer, {
status: response.status,
headers: {
"Content-Type": response.headers.get("content-type") || "application/json",
},
});
} catch (err: any) {
console.error("[Upload Profile Picture Proxy] Error:", err.message);
return NextResponse.json(
{ error: "Failed to connect to the server." },
{ status: 502 }
);
}
}