bot-guardian-js
Version:
A powerful bot detection and prevention library for Node.js applications
206 lines (205 loc) • 7.07 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createGuardianMiddleware = exports.middleware = exports.closeServer = exports.startServer = exports.createMiddleware = exports.setGuardian = exports.guardian = exports.app = void 0;
const express_1 = __importDefault(require("express"));
const path_1 = __importDefault(require("path"));
const GuardianJS_1 = require("../core/GuardianJS");
exports.app = (0, express_1.default)();
exports.guardian = new GuardianJS_1.GuardianJS({
useTLS: true,
useBehavior: true
});
// For testing purposes
const setGuardian = (newGuardian) => {
exports.guardian = newGuardian;
};
exports.setGuardian = setGuardian;
// Custom error types with status codes
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
this.status = 400;
}
}
class DetectionError extends Error {
constructor(message, status = 500) {
super(message);
this.name = 'DetectionError';
this.status = status;
}
}
// Error handler middleware
const errorHandler = (err, _req, res, _next) => {
// Only log errors in non-test environment
if (process.env.NODE_ENV !== 'test') {
console.error('Error:', err.message);
}
if (err instanceof SyntaxError && 'status' in err && err.status === 400) {
return res.status(400).json({ error: 'Invalid JSON payload' });
}
if (err instanceof ValidationError) {
return res.status(err.status).json({ error: err.message });
}
if (err instanceof DetectionError) {
return res.status(err.status).json({ error: err.message });
}
return res.status(500).json({ error: 'Internal Server Error' });
};
// Validation middleware
const validateTrackingData = (req, _res, next) => {
try {
if (!req.body) {
throw new ValidationError('Missing request body');
}
const { mouseMovements, scrollEvents } = req.body;
if (!mouseMovements) {
throw new ValidationError('Mouse movements data is required');
}
if (!Array.isArray(mouseMovements)) {
throw new ValidationError('Invalid mouse movements data');
}
if (!scrollEvents) {
throw new ValidationError('Scroll events data is required');
}
if (!Array.isArray(scrollEvents)) {
throw new ValidationError('Invalid scroll events data');
}
next();
}
catch (error) {
next(error instanceof Error ? error : new ValidationError('Invalid request data'));
}
};
// Configure express
exports.app.use(express_1.default.json({
strict: true,
limit: '10kb'
}));
// Serve static files from dashboard
exports.app.use(express_1.default.static(path_1.default.join(__dirname, '../dashboard')));
// Create a default index.html if it doesn't exist
exports.app.get('/', (_req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>GuardianJS Dashboard</title>
</head>
<body>
<h1>GuardianJS Dashboard</h1>
<p>Welcome to the GuardianJS monitoring dashboard.</p>
</body>
</html>
`);
});
// Track behavioral data
exports.app.post('/track', validateTrackingData, (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
try {
const result = yield exports.guardian.detect(req);
if (!result) {
throw new DetectionError('Detection failed', 500);
}
res.json(result);
}
catch (error) {
if (error instanceof Error) {
next(new DetectionError(error.message, 500));
}
else {
next(new DetectionError('Unknown error', 500));
}
}
}));
// Get dashboard data
exports.app.get('/data', (_req, res, next) => {
try {
res.json({
totalRequests: 100,
detectedBots: 15,
recentDetections: []
});
}
catch (error) {
next(error);
}
});
// Handle 404
exports.app.use((_req, res) => {
res.status(404).json({ error: 'Not found' });
});
// Add error handler
exports.app.use(errorHandler);
const createMiddleware = () => {
const app = (0, express_1.default)();
return app;
};
exports.createMiddleware = createMiddleware;
const startServer = (port = 3000) => __awaiter(void 0, void 0, void 0, function* () {
if (isNaN(port) || port < 0 || port > 65535) {
throw new Error('Invalid port number');
}
const app = (0, exports.createMiddleware)();
return new Promise((resolve, reject) => {
const server = app.listen(port, () => {
resolve(server);
}).on('error', reject);
});
});
exports.startServer = startServer;
const closeServer = (server) => __awaiter(void 0, void 0, void 0, function* () {
return new Promise((resolve) => {
if (server.listening) {
server.close(() => resolve());
}
else {
resolve();
}
});
});
exports.closeServer = closeServer;
exports.middleware = {
create: exports.createMiddleware,
start: exports.startServer,
close: exports.closeServer
};
function createGuardianMiddleware(config = {}) {
const guardian = new GuardianJS_1.GuardianJS(Object.assign({ threshold: 0.5, useBehavior: true, customRules: [] }, config));
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
try {
const result = yield guardian.isBot({
userAgent: req.headers['user-agent'] || '',
ip: req.ip || '',
req
});
req.botDetection = {
timestamp: new Date(),
isBot: result.isBot,
confidence: result.confidence,
path: req.path,
userAgent: req.headers['user-agent'] || 'Unknown',
ip: req.ip || 'Unknown',
reasons: result.reasons,
behavior: result.behavior
};
next();
}
catch (error) {
console.error('GuardianJS error:', error);
next();
}
});
}
exports.createGuardianMiddleware = createGuardianMiddleware;