-
-
-
Accepted Analytics
-
0
-
-
-
Rejected Analytics
-
0
-
-
+
+
+
ตัวอย่าง Log Entry
+
[Consent Log] {"sessionId":"abc123","essential":true,"analytics":true,"marketing":false,"timestamp":"2024-03-01T12:00:00.000Z","ip":"127.0.0.1"}
-
-
-
-
บันทึกความยินยอม (100 ล่าสุด)
-
-
-
-
-
- | วันที่/เวลา |
- Session ID |
- Essential |
- Analytics |
- Marketing |
- Policy Version |
- Actions |
-
-
-
- | กำลังโหลด... |
-
-
-
+
+
+
Production Setup แนะนำ
+
+ - ตั้งค่า Docker logging driver เป็น
json-file และ limit log size
+ - ใช้ log aggregation service เช่น Datadog, CloudWatch, หรือ ELK Stack
+ - หรือเพิ่ม
@astrojs/db พร้อม Turso SQLite สำหรับ persistent storage
+
+
+
+
) : (
@@ -102,122 +81,4 @@ const isAuthorized = password === adminPassword;
-
-
diff --git a/src/pages/api/consent/[sessionId].ts b/src/pages/api/consent/[sessionId].ts
deleted file mode 100644
index 1e3d861..0000000
--- a/src/pages/api/consent/[sessionId].ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import type { APIRoute } from 'astro';
-import Database from 'better-sqlite3';
-import { join } from 'path';
-import { mkdirSync, existsSync } from 'fs';
-
-export const prerender = false;
-
-const DATA_DIR = join(process.cwd(), 'data');
-const DB_PATH = join(DATA_DIR, 'consent.db');
-
-function getDb() {
- if (!existsSync(DATA_DIR)) {
- mkdirSync(DATA_DIR, { recursive: true });
- }
- const db = new Database(DB_PATH);
- db.exec(`
- CREATE TABLE IF NOT EXISTS ConsentLog (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- sessionId TEXT UNIQUE NOT NULL,
- timestamp TEXT NOT NULL,
- essential INTEGER NOT NULL DEFAULT 0,
- analytics INTEGER NOT NULL DEFAULT 0,
- marketing INTEGER NOT NULL DEFAULT 0,
- policyVersion TEXT NOT NULL,
- ipHash TEXT,
- userAgent TEXT
- )
- `);
- return db;
-}
-
-export const DELETE: APIRoute = async ({ params }) => {
- try {
- const sessionId = params.sessionId;
- if (!sessionId) {
- return new Response(
- JSON.stringify({ error: 'Missing sessionId' }),
- { status: 400, headers: { 'Content-Type': 'application/json' } }
- );
- }
-
- const db = getDb();
- const stmt = db.prepare('DELETE FROM ConsentLog WHERE sessionId = ?');
- stmt.run(sessionId);
- db.close();
-
- return new Response(
- JSON.stringify({ success: true, message: 'Consent deleted' }),
- { status: 200, headers: { 'Content-Type': 'application/json' } }
- );
- } catch (error) {
- console.error('Error deleting consent:', error);
- return new Response(
- JSON.stringify({ error: 'Failed to delete consent' }),
- { status: 500, headers: { 'Content-Type': 'application/json' } }
- );
- }
-};
diff --git a/src/pages/api/consent/index.ts b/src/pages/api/consent/index.ts
index 335ad5b..0ae2500 100644
--- a/src/pages/api/consent/index.ts
+++ b/src/pages/api/consent/index.ts
@@ -1,74 +1,6 @@
import type { APIRoute } from 'astro';
-import Database from 'better-sqlite3';
-import { join } from 'path';
-import { mkdirSync, existsSync } from 'fs';
-
-export const prerender = false;
-
-const DATA_DIR = join(process.cwd(), 'data');
-const DB_PATH = join(DATA_DIR, 'consent.db');
-
-function getDb() {
- if (!existsSync(DATA_DIR)) {
- mkdirSync(DATA_DIR, { recursive: true });
- }
- const db = new Database(DB_PATH);
- db.exec(`
- CREATE TABLE IF NOT EXISTS ConsentLog (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- sessionId TEXT UNIQUE NOT NULL,
- timestamp TEXT NOT NULL,
- essential INTEGER NOT NULL DEFAULT 0,
- analytics INTEGER NOT NULL DEFAULT 0,
- marketing INTEGER NOT NULL DEFAULT 0,
- policyVersion TEXT NOT NULL,
- ipHash TEXT,
- userAgent TEXT
- )
- `);
- return db;
-}
-
-const rateLimitMap = new Map
();
-const RATE_LIMIT = 10;
-const RATE_WINDOW = 60000;
-
-function checkRateLimit(ip: string): boolean {
- const now = Date.now();
- const record = rateLimitMap.get(ip);
-
- if (!record || now > record.resetTime) {
- rateLimitMap.set(ip, { count: 1, resetTime: now + RATE_WINDOW });
- return true;
- }
-
- if (record.count >= RATE_LIMIT) {
- return false;
- }
-
- record.count++;
- return true;
-}
-
-async function hashIP(ip: string): Promise {
- try {
- if (crypto.subtle) {
- const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(ip));
- return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 16);
- }
- } catch {}
- return `fallback-${Date.now()}`;
-}
export const POST: APIRoute = async ({ request, clientAddress }) => {
- const ip = clientAddress || 'unknown';
- if (!checkRateLimit(ip)) {
- return new Response(
- JSON.stringify({ error: 'Too many requests' }),
- { status: 429, headers: { 'Content-Type': 'application/json' } }
- );
- }
-
try {
let body: any = {};
const text = await request.text();
@@ -78,28 +10,20 @@ export const POST: APIRoute = async ({ request, clientAddress }) => {
const { sessionId, essential, analytics, marketing, policyVersion, userAgent } = body;
- if (!sessionId || essential === undefined || !policyVersion) {
- return new Response(
- JSON.stringify({ error: 'Missing required fields' }),
- { status: 400, headers: { 'Content-Type': 'application/json' } }
- );
- }
-
- const db = getDb();
- const ipHash = await hashIP(ip);
- const timestamp = new Date().toISOString();
-
- const stmt = db.prepare(`
- INSERT INTO ConsentLog (sessionId, timestamp, essential, analytics, marketing, policyVersion, ipHash, userAgent)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- `);
-
- stmt.run(sessionId, timestamp, essential ? 1 : 0, analytics ? 1 : 0, marketing ? 1 : 0, policyVersion, ipHash, userAgent || 'unknown');
- db.close();
+ console.log('[Consent Log]', JSON.stringify({
+ sessionId,
+ essential,
+ analytics,
+ marketing,
+ policyVersion,
+ userAgent,
+ ip: clientAddress || 'unknown',
+ timestamp: new Date().toISOString()
+ }));
return new Response(
- JSON.stringify({ success: true, sessionId, message: 'Consent logged' }),
- { status: 201, headers: { 'Content-Type': 'application/json' } }
+ JSON.stringify({ success: true, message: 'Consent logged' }),
+ { status: 200, headers: { 'Content-Type': 'application/json' } }
);
} catch (error) {
console.error('Error logging consent:', error);
@@ -111,28 +35,8 @@ export const POST: APIRoute = async ({ request, clientAddress }) => {
};
export const GET: APIRoute = async () => {
- try {
- const db = getDb();
- const stmt = db.prepare('SELECT * FROM ConsentLog ORDER BY timestamp DESC LIMIT 100');
- const logs = stmt.all();
- db.close();
-
- const formattedLogs = logs.map((log: any) => ({
- ...log,
- essential: log.essential === 1,
- analytics: log.analytics === 1,
- marketing: log.marketing === 1
- }));
-
- return new Response(
- JSON.stringify({ logs: formattedLogs, message: 'Success' }),
- { status: 200, headers: { 'Content-Type': 'application/json' } }
- );
- } catch (error) {
- console.error('Error fetching logs:', error);
- return new Response(
- JSON.stringify({ logs: [], error: 'Failed to fetch logs' }),
- { status: 500, headers: { 'Content-Type': 'application/json' } }
- );
- }
+ return new Response(
+ JSON.stringify({ logs: [], message: 'Static build - logs go to Docker logs. See: docker logs ' }),
+ { status: 200, headers: { 'Content-Type': 'application/json' } }
+ );
};