// Example 1: Safe URL parameter processing
function processUrlParameter() {
const params = new URLSearchParams(window.location.search);
const action = params.get('action');
// Secure: Whitelist allowed actions
const allowedActions = {
'showHelp': () => displayHelp(),
'refreshData': () => loadData(),
'toggleTheme': () => switchTheme()
};
if (action && allowedActions[action]) {
allowedActions[action]();
}
}
// Example 2: Safe function calls with whitelist
function callFunction(funcName, args) {
// Secure: Predefined function whitelist
const allowedFunctions = {
'calculateTotal': (items) => items.reduce((sum, item) => sum + (item.price || 0), 0),
'formatDate': (date) => new Date(date).toLocaleDateString(),
'validateEmail': (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
};
const func = allowedFunctions[funcName];
if (!func || typeof func !== 'function') {
throw new Error('Function not allowed: ' + funcName);
}
// Validate arguments
if (!Array.isArray(args)) {
throw new Error('Invalid arguments');
}
try {
return func(...args);
} catch (error) {
console.error('Function execution error:', error);
throw new Error('Function execution failed');
}
}
// Example 3: Safe configuration processing
function applySettings(settingsString) {
try {
// Secure: Use JSON.parse instead of eval
const settings = JSON.parse(settingsString);
// Validate and apply settings safely
const allowedSettings = ['theme', 'language', 'fontSize', 'autoSave'];
for (const [key, value] of Object.entries(settings)) {
if (allowedSettings.includes(key)) {
applySetting(key, value);
} else {
console.warn('Unknown setting ignored:', key);
}
}
} catch (error) {
console.error('Invalid settings format:', error);
throw new Error('Settings must be valid JSON');
}
}
function applySetting(key, value) {
switch (key) {
case 'theme':
if (['light', 'dark'].includes(value)) {
document.body.className = 'theme-' + value;
}
break;
case 'language':
if (/^[a-z]{2}$/.test(value)) {
setLanguage(value);
}
break;
case 'fontSize':
if (typeof value === 'number' && value >= 10 && value <= 24) {
document.documentElement.style.fontSize = value + 'px';
}
break;
case 'autoSave':
if (typeof value === 'boolean') {
setAutoSave(value);
}
break;
}
}
// Example 4: Safe template processing
function renderTemplate(template, data) {
// Secure: Safe template interpolation
return template.replace(/\{\{([a-zA-Z_$][a-zA-Z0-9_$.]*)}\}/g, function(match, path) {
const value = getNestedValue(data, path);
return value !== undefined ? escapeHtml(String(value)) : '';
});
}
function getNestedValue(obj, path) {
const keys = path.split('.').filter(key => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key));
return keys.reduce((current, key) => {
return current && typeof current === 'object' ? current[key] : undefined;
}, obj);
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Example 5: Safe callback handling
function handleCallback(callbackName, data) {
// Secure: Whitelist allowed callbacks
const allowedCallbacks = {
'onDataLoaded': (data) => updateUI(data),
'onError': (error) => showError(error),
'onSuccess': (message) => showSuccess(message)
};
const callback = allowedCallbacks[callbackName];
if (!callback) {
console.warn('Unknown callback:', callbackName);
return;
}
// Validate data before calling
if (data && typeof data === 'object') {
callback(sanitizeData(data));
}
}
// Example 6: Safe math expression evaluator
function calculateExpression(expression) {
// Secure: Whitelist allowed operations
const allowedChars = /^[0-9+\-*/(). ]+$/;
if (!allowedChars.test(expression)) {
throw new Error('Invalid characters in expression');
}
// Additional validation: no consecutive operators, balanced parentheses
if (!isValidMathExpression(expression)) {
throw new Error('Invalid math expression');
}
try {
// Use Function constructor with restricted scope (still better than eval)
// Or better yet, implement a proper math parser
return evaluateMathExpression(expression);
} catch (error) {
throw new Error('Calculation error');
}
}
function isValidMathExpression(expr) {
// Check for balanced parentheses
let balance = 0;
for (const char of expr) {
if (char === '(') balance++;
if (char === ')') balance--;
if (balance < 0) return false;
}
return balance === 0;
}
// Example 7: Safe property access
class UserSettings {
constructor() {
this.theme = 'light';
this.language = 'en';
this.fontSize = 14;
this.autoSave = true;
}
getSetting(key) {
// Secure: Direct property access with validation
const allowedSettings = ['theme', 'language', 'fontSize', 'autoSave'];
if (!allowedSettings.includes(key)) {
throw new Error('Setting not found: ' + key);
}
return this[key];
}
setSetting(key, value) {
const allowedSettings = ['theme', 'language', 'fontSize', 'autoSave'];
if (!allowedSettings.includes(key)) {
throw new Error('Setting not allowed: ' + key);
}
// Validate value based on setting type
switch (key) {
case 'theme':
if (['light', 'dark'].includes(value)) {
this.theme = value;
}
break;
case 'language':
if (typeof value === 'string' && /^[a-z]{2}$/.test(value)) {
this.language = value;
}
break;
case 'fontSize':
if (typeof value === 'number' && value >= 10 && value <= 24) {
this.fontSize = value;
}
break;
case 'autoSave':
if (typeof value === 'boolean') {
this.autoSave = value;
}
break;
}
}
}