Skip to content

Architecture

Comprehensive overview of TrojanHorse.js architecture, design patterns, and system components for developers and contributors.

Overview

TrojanHorse.js is built with a modular, extensible architecture that supports multiple deployment patterns, from simple single-node implementations to large-scale distributed enterprise deployments.

graph TB
    A[Application Layer] --> B[Core Engine]
    A --> C[API Layer]
    A --> D[Web Interface]

    B --> E[Threat Feeds]
    B --> F[Correlation Engine]
    B --> G[Analytics Engine]
    B --> H[Security Layer]

    E --> I[URLhaus]
    E --> J[VirusTotal]
    E --> K[AlienVault OTX]
    E --> L[Custom Feeds]

    H --> M[Encryption]
    H --> N[Authentication]
    H --> O[Authorization]
    H --> P[Audit Logging]

    B --> Q[Storage Layer]
    Q --> R[Key Vault]
    Q --> S[Cache Layer]
    Q --> T[Database]

    B --> U[Integration Layer]
    U --> V[SIEM Connectors]
    U --> W[Webhook Manager]
    U --> X[Enterprise Auth]

Core Architecture Principles

1. Modularity and Extensibility

The system is designed around loosely coupled modules that can be independently developed, tested, and deployed.

// Core module structure
src/
├── core/                 // Core engine components
   ├── TrojanHorse.ts   // Main orchestrator
   ├── CircuitBreaker.ts
   ├── EventEmitter.ts
   └── CorrelationEngine.ts
├── feeds/               // Threat intelligence feeds
   ├── base/
      └── ThreatFeed.ts
   ├── URLhausFeed.ts
   ├── VirusTotalFeed.ts
   └── CustomFeed.ts
├── security/            // Security components
   ├── CryptoEngine.ts
   ├── KeyVault.ts
   └── AuthManager.ts
├── analytics/           // Analytics and correlation
   ├── RealTimeAnalytics.ts
   ├── MLEngine.ts
   └── ReportGenerator.ts
├── integrations/        // External integrations
   ├── SIEMConnector.ts
   ├── WebhookManager.ts
   └── EnterpriseAuth.ts
└── utils/               // Utility functions
    ├── validators.ts
    ├── formatters.ts
    └── helpers.ts

2. Event-Driven Architecture

The system uses an event-driven pattern for loose coupling and scalability.

// Event flow architecture
class TrojanHorse extends EventEmitter {
  async scout(indicator: string): Promise<ThreatFeedResult[]> {
    // Emit pre-processing event
    this.emit('beforeScout', { indicator });

    try {
      // Process through feeds
      const results = await this.processFeeds(indicator);

      // Emit threat detection events
      results.forEach(result => {
        if (result.threat) {
          this.emit('threatDetected', result);
        }
      });

      // Emit post-processing event
      this.emit('afterScout', { indicator, results });

      return results;
    } catch (error) {
      this.emit('error', error);
      throw error;
    }
  }
}

3. Plugin-Based Feed System

Threat intelligence feeds are implemented as plugins with a common interface.

// Feed plugin interface
abstract class ThreatFeed {
  abstract name: string;
  abstract version: string;

  abstract async fetchThreatData(
    indicator: string, 
    options?: FeedOptions
  ): Promise<ThreatFeedResult>;

  abstract async batchQuery(
    indicators: string[], 
    options?: BatchOptions
  ): Promise<ThreatFeedResult[]>;

  abstract async getHealthStatus(): Promise<FeedHealthStatus>;
}

// Feed registration system
class FeedRegistry {
  private feeds = new Map<string, ThreatFeed>();

  register(name: string, feed: ThreatFeed): void {
    this.feeds.set(name, feed);
  }

  async queryAll(indicator: string): Promise<ThreatFeedResult[]> {
    const promises = Array.from(this.feeds.values()).map(
      feed => feed.fetchThreatData(indicator)
    );

    return Promise.allSettled(promises).then(results =>
      results.filter(r => r.status === 'fulfilled')
              .map(r => (r as PromiseFulfilledResult<ThreatFeedResult>).value)
    );
  }
}

Component Architecture

Core Engine

The core engine orchestrates all system operations and maintains state.

interface CoreEngineConfig {
  feeds: FeedConfig[];
  performance: PerformanceConfig;
  security: SecurityConfig;
  analytics: AnalyticsConfig;
}

class CoreEngine {
  private feedRegistry: FeedRegistry;
  private correlationEngine: CorrelationEngine;
  private analyticsEngine: AnalyticsEngine;
  private securityManager: SecurityManager;
  private circuitBreaker: CircuitBreaker;

  constructor(config: CoreEngineConfig) {
    this.initialize(config);
  }

  private async initialize(config: CoreEngineConfig): Promise<void> {
    // Initialize components in dependency order
    this.securityManager = new SecurityManager(config.security);
    this.feedRegistry = new FeedRegistry();
    this.correlationEngine = new CorrelationEngine(config.analytics);
    this.analyticsEngine = new AnalyticsEngine(config.analytics);
    this.circuitBreaker = new CircuitBreaker(config.performance);

    // Register feeds
    for (const feedConfig of config.feeds) {
      const feed = this.createFeed(feedConfig);
      this.feedRegistry.register(feedConfig.name, feed);
    }
  }

  async processThreatQuery(
    indicator: string, 
    options: QueryOptions
  ): Promise<ProcessedThreatResult> {
    // Pre-processing
    const sanitizedIndicator = this.sanitizeIndicator(indicator);
    await this.validateAccess(options.userId, 'threat:read');

    // Circuit breaker protection
    const results = await this.circuitBreaker.execute(async () => {
      return this.feedRegistry.queryFeeds(sanitizedIndicator, options.sources);
    });

    // Correlation and enrichment
    const correlatedResults = await this.correlationEngine.correlate(results);
    const enrichedResults = await this.analyticsEngine.enrich(correlatedResults);

    // Post-processing
    await this.auditLogger.log('threat_query', {
      user: options.userId,
      indicator: sanitizedIndicator,
      results: enrichedResults.length
    });

    return {
      indicator: sanitizedIndicator,
      results: enrichedResults,
      correlation: correlatedResults.metadata,
      timestamp: new Date().toISOString()
    };
  }
}

Feed Architecture

Each threat intelligence feed implements the standard ThreatFeed interface.

// Feed implementation pattern
class URLhausFeed extends ThreatFeed {
  name = 'URLhaus';
  version = '1.0.0';

  private client: HTTPClient;
  private cache: CacheManager;
  private rateLimiter: RateLimiter;

  constructor(config: URLhausFeedConfig) {
    super(config);
    this.client = new HTTPClient(config.http);
    this.cache = new CacheManager(config.cache);
    this.rateLimiter = new RateLimiter(config.rateLimit);
  }

  async fetchThreatData(
    indicator: string, 
    options: FeedOptions = {}
  ): Promise<ThreatFeedResult> {
    // Rate limiting
    await this.rateLimiter.acquire();

    try {
      // Check cache first
      const cached = await this.cache.get(indicator);
      if (cached && !options.ignoreCache) {
        return cached;
      }

      // Fetch from API
      const response = await this.client.get(`/api/url/${indicator}`);
      const result = this.transformResponse(response.data, indicator);

      // Cache result
      await this.cache.set(indicator, result, options.cacheTTL);

      return result;
    } catch (error) {
      this.handleError(error, indicator);
      throw error;
    } finally {
      this.rateLimiter.release();
    }
  }

  private transformResponse(apiData: any, indicator: string): ThreatFeedResult {
    return {
      indicator,
      type: this.detectIndicatorType(indicator),
      threat: Boolean(apiData.threat),
      confidence: this.normalizeConfidence(apiData.confidence),
      sources: [this.name],
      timestamp: new Date().toISOString(),
      metadata: {
        source: this.name,
        version: this.version,
        raw_data: apiData
      }
    };
  }
}

Security Architecture

Security is implemented as a layered system with multiple controls.

class SecurityManager {
  private cryptoEngine: CryptoEngine;
  private keyVault: KeyVault;
  private authManager: AuthManager;
  private auditLogger: AuditLogger;

  constructor(config: SecurityConfig) {
    this.cryptoEngine = new CryptoEngine(config.crypto);
    this.keyVault = new KeyVault(config.vault);
    this.authManager = new AuthManager(config.auth);
    this.auditLogger = new AuditLogger(config.audit);
  }

  async validateAccess(
    userId: string, 
    permission: string, 
    resource?: string
  ): Promise<boolean> {
    // Authentication check
    const user = await this.authManager.validateUser(userId);
    if (!user) {
      throw new AuthenticationError('Invalid user');
    }

    // Authorization check
    const authorized = await this.authManager.checkPermission(
      user, permission, resource
    );
    if (!authorized) {
      throw new AuthorizationError('Insufficient permissions');
    }

    // Audit logging
    await this.auditLogger.log('access_check', {
      userId,
      permission,
      resource,
      result: 'granted'
    });

    return true;
  }

  async encryptSensitiveData(data: any): Promise<EncryptedData> {
    const key = await this.keyVault.getEncryptionKey();
    return this.cryptoEngine.encrypt(JSON.stringify(data), key);
  }

  async decryptSensitiveData(encryptedData: EncryptedData): Promise<any> {
    const key = await this.keyVault.getEncryptionKey();
    const decrypted = await this.cryptoEngine.decrypt(encryptedData, key);
    return JSON.parse(decrypted);
  }
}

Data Flow Architecture

Request Processing Flow

sequenceDiagram
    participant C as Client
    participant A as API Layer
    participant CE as Core Engine
    participant F as Feed
    participant CoE as Correlation Engine
    participant AnE as Analytics Engine
    participant S as Storage

    C->>A: Threat Query
    A->>A: Validate Request
    A->>CE: Process Query
    CE->>F: Fetch Threat Data
    F->>F: Check Cache
    F->>F: Query External API
    F-->>CE: Return Results
    CE->>CoE: Correlate Results
    CoE-->>CE: Correlation Data
    CE->>AnE: Enrich Results
    AnE-->>CE: Enriched Results
    CE->>S: Store Results
    CE-->>A: Processed Results
    A-->>C: Response

Event Flow Architecture

graph LR
    A[Threat Detected] --> B[Event Emitter]
    B --> C[SIEM Connector]
    B --> D[Webhook Manager]
    B --> E[Analytics Engine]
    B --> F[Audit Logger]

    C --> G[Splunk]
    C --> H[QRadar]
    C --> I[Sentinel]

    D --> J[Slack]
    D --> K[Teams]
    D --> L[Custom Webhooks]

    E --> M[Real-time Metrics]
    E --> N[ML Analysis]
    E --> O[Correlation]

Scalability Architecture

Horizontal Scaling

The system supports horizontal scaling through multiple patterns:

// Worker pool for parallel processing
class WorkerPool {
  private workers: Worker[] = [];
  private taskQueue: Queue<Task> = new Queue();

  constructor(private poolSize: number) {
    this.initializeWorkers();
  }

  private initializeWorkers(): void {
    for (let i = 0; i < this.poolSize; i++) {
      const worker = new Worker('./threat-worker.js');
      worker.on('message', this.handleWorkerMessage.bind(this));
      this.workers.push(worker);
    }
  }

  async processBatch(indicators: string[]): Promise<ThreatFeedResult[]> {
    const chunks = this.chunkArray(indicators, this.poolSize);
    const promises = chunks.map(chunk => this.processChunk(chunk));

    const results = await Promise.all(promises);
    return results.flat();
  }

  private async processChunk(chunk: string[]): Promise<ThreatFeedResult[]> {
    const availableWorker = await this.getAvailableWorker();

    return new Promise((resolve, reject) => {
      const timeout = setTimeout(() => {
        reject(new Error('Worker timeout'));
      }, 30000);

      availableWorker.once('message', (result) => {
        clearTimeout(timeout);
        resolve(result);
      });

      availableWorker.postMessage({ type: 'process_batch', data: chunk });
    });
  }
}

Caching Architecture

Multi-layer caching for performance optimization:

class CacheManager {
  private l1Cache: LRUCache;  // In-memory cache
  private l2Cache: RedisClient;  // Distributed cache
  private l3Cache: DatabaseCache;  // Persistent cache

  constructor(config: CacheConfig) {
    this.l1Cache = new LRUCache({ max: config.l1.maxSize });
    this.l2Cache = new RedisClient(config.l2);
    this.l3Cache = new DatabaseCache(config.l3);
  }

  async get(key: string): Promise<any> {
    // L1 cache check
    let value = this.l1Cache.get(key);
    if (value) {
      return value;
    }

    // L2 cache check
    value = await this.l2Cache.get(key);
    if (value) {
      this.l1Cache.set(key, value);
      return value;
    }

    // L3 cache check
    value = await this.l3Cache.get(key);
    if (value) {
      this.l1Cache.set(key, value);
      await this.l2Cache.set(key, value, 3600); // 1 hour TTL
      return value;
    }

    return null;
  }

  async set(key: string, value: any, ttl?: number): Promise<void> {
    // Set in all cache layers
    this.l1Cache.set(key, value);
    await this.l2Cache.set(key, value, ttl || 3600);
    await this.l3Cache.set(key, value, ttl || 86400);
  }
}

Deployment Architectures

Single Node Deployment

Simple deployment for development and small-scale use:

// Single node configuration
const trojan = new TrojanHorse({
  deployment: 'single-node',

  feeds: [
    { name: 'urlhaus', enabled: true },
    { name: 'virustotal', enabled: true }
  ],

  cache: {
    type: 'memory',
    maxSize: '100MB'
  },

  storage: {
    type: 'sqlite',
    path: './data/threats.db'
  },

  performance: {
    workers: 4,
    batchSize: 50,
    timeout: 10000
  }
});

Distributed Deployment

Enterprise-scale distributed deployment:

// Distributed cluster configuration
const cluster = new TrojanHorseCluster({
  deployment: 'distributed',

  coordinator: {
    enabled: true,
    port: 8080,
    endpoints: ['node1:8080', 'node2:8080', 'node3:8080']
  },

  worker_nodes: {
    count: 10,
    resources: {
      cpu: '2',
      memory: '4Gi',
      storage: '10Gi'
    }
  },

  load_balancer: {
    type: 'nginx',
    algorithm: 'round_robin',
    health_checks: true
  },

  cache: {
    type: 'redis-cluster',
    nodes: ['redis1:6379', 'redis2:6379', 'redis3:6379']
  },

  storage: {
    type: 'postgresql-cluster',
    nodes: ['db1:5432', 'db2:5432', 'db3:5432'],
    replication: 'streaming'
  }
});

Microservices Architecture

Service-oriented deployment pattern:

// Microservices configuration
const services = {
  api_gateway: {
    port: 8080,
    routes: {
      '/threats': 'threat-service:8081',
      '/analytics': 'analytics-service:8082',
      '/auth': 'auth-service:8083'
    }
  },

  threat_service: {
    port: 8081,
    feeds: ['urlhaus', 'virustotal', 'alienvault'],
    replicas: 3
  },

  analytics_service: {
    port: 8082,
    engines: ['correlation', 'ml', 'reporting'],
    replicas: 2
  },

  auth_service: {
    port: 8083,
    providers: ['ldap', 'oauth2', 'saml'],
    replicas: 2
  },

  storage_service: {
    port: 8084,
    database: 'postgresql',
    cache: 'redis',
    replicas: 3
  }
};

Error Handling Architecture

Hierarchical Error Handling

// Error hierarchy
abstract class TrojanHorseError extends Error {
  abstract code: string;
  abstract httpStatus: number;

  constructor(message: string, public details?: any) {
    super(message);
    this.name = this.constructor.name;
  }
}

class FeedError extends TrojanHorseError {
  code = 'FEED_ERROR';
  httpStatus = 502;
}

class AuthenticationError extends TrojanHorseError {
  code = 'AUTH_ERROR';
  httpStatus = 401;
}

class RateLimitError extends TrojanHorseError {
  code = 'RATE_LIMIT';
  httpStatus = 429;

  constructor(message: string, public retryAfter: number) {
    super(message);
  }
}

// Global error handler
class ErrorHandler {
  static handle(error: Error, context: string): void {
    if (error instanceof TrojanHorseError) {
      this.handleKnownError(error, context);
    } else {
      this.handleUnknownError(error, context);
    }
  }

  private static handleKnownError(error: TrojanHorseError, context: string): void {
    console.error(`[${context}] ${error.code}: ${error.message}`, error.details);

    // Send to monitoring system
    this.sendToMonitoring(error, context);

    // Handle specific error types
    switch (error.constructor.name) {
      case 'RateLimitError':
        this.handleRateLimit(error as RateLimitError);
        break;
      case 'FeedError':
        this.handleFeedError(error as FeedError);
        break;
    }
  }
}

Monitoring and Observability

Metrics Architecture

class MetricsCollector {
  private prometheus: PrometheusRegistry;
  private counters: Map<string, Counter> = new Map();
  private gauges: Map<string, Gauge> = new Map();
  private histograms: Map<string, Histogram> = new Map();

  constructor() {
    this.prometheus = new PrometheusRegistry();
    this.initializeMetrics();
  }

  private initializeMetrics(): void {
    // Threat detection metrics
    this.counters.set('threats_detected', new Counter({
      name: 'trojanhorse_threats_detected_total',
      help: 'Total number of threats detected',
      labelNames: ['source', 'type', 'confidence_level']
    }));

    // Performance metrics
    this.histograms.set('request_duration', new Histogram({
      name: 'trojanhorse_request_duration_seconds',
      help: 'Request duration in seconds',
      labelNames: ['method', 'endpoint'],
      buckets: [0.1, 0.5, 1, 2, 5, 10]
    }));

    // System metrics
    this.gauges.set('active_connections', new Gauge({
      name: 'trojanhorse_active_connections',
      help: 'Number of active connections'
    }));
  }

  recordThreatDetection(source: string, type: string, confidence: number): void {
    const confidenceLevel = confidence >= 90 ? 'high' : 
                           confidence >= 70 ? 'medium' : 'low';

    this.counters.get('threats_detected')?.inc({
      source,
      type,
      confidence_level: confidenceLevel
    });
  }

  recordRequestDuration(method: string, endpoint: string, duration: number): void {
    this.histograms.get('request_duration')?.observe({ method, endpoint }, duration);
  }
}

Distributed Tracing

import { trace, context, SpanStatusCode } from '@opentelemetry/api';

class TracingManager {
  private tracer = trace.getTracer('trojanhorse-js');

  async traceOperation<T>(
    operationName: string,
    operation: () => Promise<T>,
    attributes?: Record<string, string>
  ): Promise<T> {
    const span = this.tracer.startSpan(operationName, { attributes });

    try {
      const result = await context.with(trace.setSpan(context.active(), span), operation);
      span.setStatus({ code: SpanStatusCode.OK });
      return result;
    } catch (error) {
      span.setStatus({
        code: SpanStatusCode.ERROR,
        message: error instanceof Error ? error.message : 'Unknown error'
      });
      throw error;
    } finally {
      span.end();
    }
  }

  addSpanEvent(name: string, attributes?: Record<string, string>): void {
    const activeSpan = trace.getActiveSpan();
    if (activeSpan) {
      activeSpan.addEvent(name, attributes);
    }
  }
}

// Usage in core operations
class CoreEngine {
  private tracing = new TracingManager();

  async processThreatQuery(indicator: string): Promise<ThreatFeedResult[]> {
    return this.tracing.traceOperation(
      'process_threat_query',
      async () => {
        this.tracing.addSpanEvent('query_started', { indicator });

        const results = await this.feedRegistry.queryFeeds(indicator);

        this.tracing.addSpanEvent('feeds_queried', { 
          indicator, 
          result_count: results.length.toString() 
        });

        return results;
      },
      { indicator, operation: 'threat_query' }
    );
  }
}

Security Architecture

Zero-Trust Implementation

class ZeroTrustManager {
  private policyEngine: PolicyEngine;
  private identityVerifier: IdentityVerifier;
  private deviceVerifier: DeviceVerifier;

  async verifyAccess(request: AccessRequest): Promise<AccessDecision> {
    // Never trust, always verify
    const verifications = await Promise.all([
      this.identityVerifier.verify(request.user),
      this.deviceVerifier.verify(request.device),
      this.policyEngine.evaluate(request.context)
    ]);

    const decision = this.makeAccessDecision(verifications);

    // Continuous monitoring
    if (decision.allowed) {
      this.setupContinuousMonitoring(request.session);
    }

    return decision;
  }

  private makeAccessDecision(verifications: VerificationResult[]): AccessDecision {
    const allPassed = verifications.every(v => v.passed);
    const trustScore = verifications.reduce((sum, v) => sum + v.score, 0) / verifications.length;

    return {
      allowed: allPassed && trustScore >= 0.8,
      trustScore,
      conditions: this.calculateConditions(verifications),
      monitoring: this.calculateMonitoringLevel(trustScore)
    };
  }
}

Next Steps: - Review Testing Guide for testing strategies - Check Building Guide for build processes - Explore Contributing Guide for development guidelines