firewalla-mcp-server
Version:
Model Context Protocol (MCP) server for Firewalla MSP API - Provides real-time network monitoring, security analysis, and firewall management through 28 specialized tools compatible with any MCP client
151 lines • 5.48 kB
JavaScript
/**
* Base Filter Interface and Abstract Classes
* Provides foundation for specialized filter implementations
*/
/**
* Abstract base filter with common functionality
*/
export class BaseFilter {
/**
* Create a post-processing function for field-based filtering
*/
createFieldFilter(field, predicate) {
return (items) => items.filter(item => {
const value = this.getNestedValue(item, field);
return predicate(value);
});
}
/**
* Get nested value from object using dot notation
*/
getNestedValue(obj, path) {
return path.split('.').reduce((current, key) => current?.[key], obj);
}
/**
* Check if a value matches a wildcard pattern
*/
matchWildcard(value, pattern) {
if (!value || !pattern) {
return false;
}
// Convert wildcard pattern to regex
const regexPattern = pattern
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex chars except * and ?
.replace(/\*/g, '.*') // Convert * to .*
.replace(/\?/g, '.'); // Convert ? to .
const regex = new RegExp(`^${regexPattern}$`, 'i');
return regex.test(String(value));
}
/**
* Parse numeric value with validation
*/
parseNumeric(value) {
if (typeof value === 'number') {
return value;
}
if (typeof value === 'string') {
const parsed = parseFloat(value);
return isNaN(parsed) ? null : parsed;
}
return null;
}
/**
* Parse timestamp value to Unix timestamp with robust detection
*/
parseTimestamp(value) {
if (typeof value === 'number') {
// Handle invalid numbers (NaN, Infinity)
if (!Number.isFinite(value)) {
return null;
}
// Handle negative timestamps (invalid)
if (value < 0) {
return null;
}
// Handle Unix epoch (1970-01-01): 0 seconds
if (value === 0) {
return 0;
}
// More robust detection: timestamps after year 3000 in seconds would be > 32503680000
// Timestamps in milliseconds for current era would be > 1000000000000
// This handles both current millisecond timestamps and future second timestamps correctly
if (value > 32503680000 && value < 1000000000000) {
// Likely seconds for far future dates
return value;
}
else if (value > 1000000000000) {
// Likely milliseconds - validate reasonable range (not beyond year 9999)
if (value > 253402300800000) {
// Year 9999 in milliseconds
return null;
}
return Math.floor(value / 1000);
}
else if (value > 946684800) {
// Likely seconds for dates after 2000-01-01
return value;
}
else if (value >= 31536000) {
// Valid Unix timestamp for dates after 1971 (to account for older logs)
return value;
}
// Too small to be a valid timestamp
return null;
}
if (typeof value === 'string') {
// Trim whitespace and check for empty string
const trimmed = value.trim();
if (!trimmed) {
return null;
}
// Try parsing as number string first
const numericValue = parseFloat(trimmed);
if (!isNaN(numericValue) && Number.isFinite(numericValue)) {
return this.parseTimestamp(numericValue);
}
// Try parsing as ISO date
const date = new Date(trimmed);
if (!isNaN(date.getTime())) {
const timestamp = Math.floor(date.getTime() / 1000);
// Validate the parsed timestamp is reasonable
if (timestamp >= 0 && timestamp <= 253402300800) {
// Year 9999
return timestamp;
}
}
// Try parsing as relative time (1h, 24h, 7d, etc.)
const relativeMatch = trimmed.match(/^(\d+)([smhdw])$/i);
if (relativeMatch) {
const amount = parseInt(relativeMatch[1]);
const unit = relativeMatch[2].toLowerCase();
// Validate amount is reasonable
if (amount < 0 || amount > 1000000) {
return null;
}
const now = Math.floor(Date.now() / 1000);
switch (unit) {
case 's':
return now - amount;
case 'm':
return now - amount * 60;
case 'h':
return now - amount * 60 * 60;
case 'd':
return now - amount * 24 * 60 * 60;
case 'w':
return now - amount * 7 * 24 * 60 * 60;
default:
return null;
}
}
}
return null;
}
/**
* Create cache key component for this filter
*/
createCacheKey(node) {
return `${this.name}:${JSON.stringify(node)}`;
}
}
//# sourceMappingURL=base.js.map