From 9ad934c99f77bda05e9f1a14694f67a9475cb447 Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Tue, 19 May 2026 16:05:35 +0800 Subject: [PATCH 1/2] bump: version 0.1.15 + migration --- package.json | 2 +- prisma/migrations/20260519080535_auto/migration.sql | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20260519080535_auto/migration.sql diff --git a/package.json b/package.json index 64d82be..f43b41e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sistem-desa-mandiri", - "version": "0.1.14", + "version": "0.1.15", "private": true, "scripts": { "dev": "next dev --experimental-https", diff --git a/prisma/migrations/20260519080535_auto/migration.sql b/prisma/migrations/20260519080535_auto/migration.sql new file mode 100644 index 0000000..af5102c --- /dev/null +++ b/prisma/migrations/20260519080535_auto/migration.sql @@ -0,0 +1 @@ +-- This is an empty migration. \ No newline at end of file -- 2.49.1 From 10457e96e88025141774f68f3fd501a447fbd419 Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Wed, 20 May 2026 12:23:38 +0800 Subject: [PATCH 2/2] feat: tambah autentikasi x-api-key pada NOC API dan ekstrak isValidApiKey ke shared lib --- src/app/api/ai/[[...slug]]/route.ts | 15 +-------------- src/app/api/noc/[[...slug]]/route.ts | 23 ++++++++++++++++++++++- src/lib/apiKey.ts | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 src/lib/apiKey.ts diff --git a/src/app/api/ai/[[...slug]]/route.ts b/src/app/api/ai/[[...slug]]/route.ts index 491be13..dad4a4f 100644 --- a/src/app/api/ai/[[...slug]]/route.ts +++ b/src/app/api/ai/[[...slug]]/route.ts @@ -1,3 +1,4 @@ +import { isValidApiKey } from "@/lib/apiKey"; import { prisma } from "@/module/_global"; import cors from "@elysiajs/cors"; import { swagger } from "@elysiajs/swagger"; @@ -6,20 +7,6 @@ import _ from "lodash"; import moment from "moment"; import "moment/locale/id"; -const CACHE_TTL_MS = 60_000; -let apiKeyCache: Set = new Set(); -let cacheExpiresAt = 0; - -async function isValidApiKey(incoming: string): Promise { - const now = Date.now(); - if (now > cacheExpiresAt) { - const rows = await prisma.apiKey.findMany({ where: { isActive: true }, select: { key: true } }); - apiKeyCache = new Set(rows.map((r) => r.key)); - cacheExpiresAt = now + CACHE_TTL_MS; - } - return apiKeyCache.has(incoming); -} - const AiServer = new Elysia({ prefix: "/api/ai" }) .use(cors({ origin: "*", diff --git a/src/app/api/noc/[[...slug]]/route.ts b/src/app/api/noc/[[...slug]]/route.ts index 68df427..54e0e4c 100644 --- a/src/app/api/noc/[[...slug]]/route.ts +++ b/src/app/api/noc/[[...slug]]/route.ts @@ -1,3 +1,4 @@ +import { isValidApiKey } from "@/lib/apiKey"; import { prisma } from "@/module/_global"; import cors from "@elysiajs/cors"; import { swagger } from "@elysiajs/swagger"; @@ -11,20 +12,40 @@ const NocServer = new Elysia({ prefix: "/api/noc" }) .use(cors({ origin: "*", methods: ["GET", "POST", "OPTIONS"], + allowedHeaders: ["Content-Type", "x-api-key"], })) .use(swagger({ - path: "/docs", // Karena prefix instance adalah /api/noc, maka ini akan diakses di /api/noc/docs + path: "/docs", documentation: { info: { title: "Sistem Desa Mandiri - NOC API", version: "1.0.0", description: "API Khusus untuk kebutuhan NOC (Network Operation Center) dan Monitoring Desa", }, + components: { + securitySchemes: { + ApiKeyAuth: { + type: "apiKey", + in: "header", + name: "x-api-key", + }, + }, + }, + security: [{ ApiKeyAuth: [] }], tags: [ { name: "NOC", description: "Endpoint khusus monitoring" } ] } })) + .onBeforeHandle(async ({ request, set, path }) => { + if (path.startsWith("/api/noc/docs")) return; + + const incoming = request.headers.get("x-api-key"); + if (!incoming || !(await isValidApiKey(incoming))) { + set.status = 401; + return { success: false, message: "Unauthorized" }; + } + }) // ── GET /api/noc/active-divisions ────────────────────────────────────────── .get( diff --git a/src/lib/apiKey.ts b/src/lib/apiKey.ts new file mode 100644 index 0000000..fa6788a --- /dev/null +++ b/src/lib/apiKey.ts @@ -0,0 +1,15 @@ +import { prisma } from "@/module/_global"; + +const CACHE_TTL_MS = 60_000; +let apiKeyCache: Set = new Set(); +let cacheExpiresAt = 0; + +export async function isValidApiKey(incoming: string): Promise { + const now = Date.now(); + if (now > cacheExpiresAt) { + const rows = await prisma.apiKey.findMany({ where: { isActive: true }, select: { key: true } }); + apiKeyCache = new Set(rows.map((r) => r.key)); + cacheExpiresAt = now + CACHE_TTL_MS; + } + return apiKeyCache.has(incoming); +} -- 2.49.1