Handling Legacy JavaScript Patterns

Handling Legacy JavaScript Patterns

Legacy applications often use JavaScript patterns that conflict with CSP. Here's how to modernize these patterns:

// Legacy JavaScript Pattern Modernization
class LegacyJSModernizer {
  constructor() {
    this.patterns = this.definePatternReplacements();
  }
  
  definePatternReplacements() {
    return {
      // Replace eval() usage
      evalReplacement: {
        pattern: /eval\s*\(\s*([^)]+)\s*\)/g,
        replace: (match, code) => {
          // For JSON parsing
          if (code.includes('{') || code.includes('[')) {
            return `JSON.parse(${code})`;
          }
          // For dynamic property access
          if (code.includes('.')) {
            return `getPropertyByPath(${code})`;
          }
          // Flag for manual review
          return `/* CSP-REVIEW: eval(${code}) */`;
        }
      },
      
      // Replace new Function()
      functionConstructor: {
        pattern: /new\s+Function\s*\(([^)]+)\)/g,
        replace: (match, args) => {
          console.warn('Function constructor found, needs manual refactoring:', match);
          return `/* CSP-TODO: new Function(${args}) */`;
        }
      },
      
      // Replace setTimeout/setInterval with strings
      setTimeoutString: {
        pattern: /setTimeout\s*\(\s*["']([^"']+)["']\s*,/g,
        replace: (match, code) => {
          return `setTimeout(function() { ${code} },`;
        }
      },
      
      // Replace document.write
      documentWrite: {
        pattern: /document\.(write|writeln)\s*\(([^)]+)\)/g,
        replace: (match, method, content) => {
          return `appendToDocument(${content})`;
        }
      }
    };
  }
  
  modernizeCode(code) {
    let modernized = code;
    
    Object.values(this.patterns).forEach(({ pattern, replace }) => {
      modernized = modernized.replace(pattern, replace);
    });
    
    // Add helper functions
    const helpers = `
      // Helper functions for CSP compliance
      function getPropertyByPath(obj, path) {
        return path.split('.').reduce((current, prop) => current?.[prop], obj);
      }
      
      function appendToDocument(content) {
        const div = document.createElement('div');
        div.innerHTML = content;
        document.body.appendChild(div);
      }
      
      function safeEval(expression) {
        console.warn('safeEval called, consider refactoring:', expression);
        // Implement safe evaluation logic
        return null;
      }
    `;
    
    return helpers + '\n' + modernized;
  }
  
  // Specific pattern migrations
  migrateAjaxPatterns() {
    return {
      // Old jQuery AJAX with eval
      old: `
        $.ajax({
          url: '/api/data',
          dataType: 'script',
          success: function(data) {
            eval(data);
          }
        });
      `,
      
      // Modern CSP-compliant version
      new: `
        $.ajax({
          url: '/api/data',
          dataType: 'json',
          success: function(data) {
            processData(data);
          }
        });
        
        function processData(data) {
          // Process JSON data instead of executing scripts
          if (data.action) {
            handleAction(data.action, data.parameters);
          }
        }
      `
    };
  }
}