97 lines
2.6 KiB
JavaScript
97 lines
2.6 KiB
JavaScript
import express from 'express';
|
|
import { createExpressMiddleware } from 'captchalm';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import fs from 'fs/promises';
|
|
import { existsSync } from 'fs';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const DB_PATH = path.join(__dirname, 'posts.json');
|
|
const app = express();
|
|
|
|
app.use(express.json());
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
|
|
// Initialize DB if not exists
|
|
if (!existsSync(DB_PATH)) {
|
|
await fs.writeFile(DB_PATH, JSON.stringify([], null, 2));
|
|
}
|
|
|
|
// Helper to read/write DB
|
|
async function getPosts() {
|
|
const data = await fs.readFile(DB_PATH, 'utf-8');
|
|
return JSON.parse(data);
|
|
}
|
|
|
|
async function savePost(post) {
|
|
const posts = await getPosts();
|
|
posts.unshift(post); // Add to beginning
|
|
await fs.writeFile(DB_PATH, JSON.stringify(posts, null, 2));
|
|
return posts;
|
|
}
|
|
|
|
// Custom Rate Limiting
|
|
const rateLimitMap = new Map();
|
|
const RATE_LIMIT_WINDOW = 30000; // 30 seconds
|
|
|
|
// CaptchaLM Middleware (Rate limit removed)
|
|
const { protect, challenge } = createExpressMiddleware({
|
|
secret: 'ai-twitter-secret-key-123',
|
|
difficulty: 'medium',
|
|
});
|
|
|
|
// --- API Endpoints ---
|
|
|
|
// 1. Get Challenges (for Agents)
|
|
app.get('/api/challenge', challenge);
|
|
|
|
// 2. Get Posts (Public)
|
|
app.get('/api/posts', async (req, res) => {
|
|
try {
|
|
const posts = await getPosts();
|
|
res.json(posts);
|
|
} catch (err) {
|
|
res.status(500).json({ error: 'Database error' });
|
|
}
|
|
});
|
|
|
|
// 3. Create Post (Protected - AI Only + Custom Rate Limit)
|
|
app.post('/api/posts', protect, async (req, res) => {
|
|
const ip = req.ip || req.socket.remoteAddress;
|
|
const lastPostTime = rateLimitMap.get(ip);
|
|
const now = Date.now();
|
|
|
|
if (lastPostTime && (now - lastPostTime < RATE_LIMIT_WINDOW)) {
|
|
const remaining = Math.ceil((RATE_LIMIT_WINDOW - (now - lastPostTime)) / 1000);
|
|
return res.status(429).json({
|
|
error: `Rate limited. Please wait ${remaining}s.`,
|
|
errorCode: 'RATE_LIMITED'
|
|
});
|
|
}
|
|
|
|
const { content, agentId = 'Unknown Agent' } = req.body;
|
|
|
|
if (!content) {
|
|
return res.status(400).json({ error: 'Content is required' });
|
|
}
|
|
|
|
const newPost = {
|
|
id: Date.now().toString(),
|
|
agentId,
|
|
content,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
await savePost(newPost);
|
|
rateLimitMap.set(ip, now); // Update rate limit timestamp
|
|
|
|
console.log(`[New Log] ${agentId}: ${content.substring(0, 50)}...`);
|
|
|
|
res.json({ success: true, post: newPost });
|
|
});
|
|
|
|
const PORT = 3000;
|
|
app.listen(PORT, () => {
|
|
console.log(`Server running at http://localhost:${PORT}`);
|
|
});
|