/* ==============================================
مكونات تفاعلية - مشروع سياسة أمان المحتوى
Interactive Components JavaScript
============================================== */
// Example Tabs Functionality
function showExampleTab(tabName) {
// Hide all example content
const exampleContents = document.querySelectorAll('.example-content');
exampleContents.forEach(content => {
content.classList.remove('active');
});
// Remove active class from all tabs
const tabButtons = document.querySelectorAll('.examples-tabs .tab-btn');
tabButtons.forEach(btn => {
btn.classList.remove('active');
});
// Show selected example content
const selectedContent = document.getElementById(tabName + '-example');
if (selectedContent) {
selectedContent.classList.add('active');
}
// Add active class to clicked tab
const clickedTab = event.target;
clickedTab.classList.add('active');
// Announce change for screen readers
CSPProject.announceMessage(`تم التبديل إلى ${tabName} example`);
}
// Guide Section Functionality
function showSection(sectionName) {
const targetSection = document.getElementById(sectionName);
if (targetSection) {
const navbarHeight = document.querySelector('.navbar').offsetHeight;
const elementPosition = targetSection.offsetTop - navbarHeight - 20;
window.scrollTo({
top: elementPosition,
behavior: 'smooth'
});
// Highlight the section
targetSection.style.border = '2px solid var(--primary-500)';
targetSection.style.borderRadius = '12px';
targetSection.style.padding = 'var(--space-lg)';
targetSection.style.margin = 'var(--space-lg)';
targetSection.style.background = 'rgba(0, 224, 213, 0.05)';
setTimeout(() => {
targetSection.style.border = '';
targetSection.style.borderRadius = '';
targetSection.style.padding = '';
targetSection.style.margin = '';
targetSection.style.background = '';
}, 2000);
CSPProject.announceMessage(`تم الانتقال إلى قسم ${sectionName}`);
}
}
// Modal Management
function openModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) {
modal.classList.add('active');
document.body.style.overflow = 'hidden';
// Focus first input in modal
const firstInput = modal.querySelector('input, button, textarea, select');
if (firstInput) {
setTimeout(() => firstInput.focus(), 100);
}
CSPProject.announceMessage('تم فتح نافذة منبثقة');
}
}
function closeModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) {
modal.classList.remove('active');
document.body.style.overflow = '';
CSPProject.announceMessage('تم إغلاق النافذة المنبثقة');
}
}
// CSP Builder Modal
function openCSPBuilder() {
openModal('cspBuilderModal');
initializeCSPBuilder();
}
function closeCSPBuilder() {
closeModal('cspBuilderModal');
}
// CSP Builder Functionality
function initializeCSPBuilder() {
const builderTabs = document.querySelectorAll('.builder-tabs .tab-btn');
const builderTabContents = document.querySelectorAll('.builder-tab');
builderTabs.forEach(tab => {
tab.addEventListener('click', function() {
const tabName = this.textContent.toLowerCase().replace(/\s+/g, '-');
showBuilderTab(tabName);
});
});
// Initialize form handlers
initializeBuilderForm();
generateInitialCSP();
}
function showBuilderTab(tabName) {
// Hide all builder tabs
builderTabContents.forEach(content => {
content.classList.remove('active');
});
// Remove active class from all builder tabs
const builderTabButtons = document.querySelectorAll('.builder-tabs .tab-btn');
builderTabButtons.forEach(btn => {
btn.classList.remove('active');
});
// Show selected builder tab
const selectedTab = document.getElementById(tabName + '-builder');
if (selectedTab) {
selectedTab.classList.add('active');
}
// Add active class to clicked tab
event.target.classList.add('active');
}
function initializeBuilderForm() {
const inputs = document.querySelectorAll('#cspBuilderModal input, #cspBuilderModal textarea');
inputs.forEach(input => {
input.addEventListener('input', CSPProject.debounce(generateCSPFromForm, 300));
});
const checkboxes = document.querySelectorAll('#cspBuilderModal input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', generateCSPFromForm);
});
}
function generateInitialCSP() {
// Set default values
document.getElementById('jsSources').value = "'self' 'unsafe-inline'";
document.getElementById('cssSources').value = "'self' 'unsafe-inline'";
document.getElementById('imgSources').value = "'self' data: https:";
document.getElementById('fontSources').value = "'self'";
document.getElementById('connectSources').value = "'self'";
// Set default checkboxes
document.getElementById('blockMixedContent').checked = true;
document.getElementById('upgradeInsecure').checked = true;
document.getElementById('frameAncestors').checked = false;
generateCSPFromForm();
}
function generateCSPFromForm() {
const jsSources = document.getElementById('jsSources').value || "'self'";
const cssSources = document.getElementById('cssSources').value || "'self'";
const imgSources = document.getElementById('imgSources').value || "'self'";
const fontSources = document.getElementById('fontSources').value || "'self'";
const connectSources = document.getElementById('connectSources').value || "'self'";
const blockMixedContent = document.getElementById('blockMixedContent').checked;
const upgradeInsecure = document.getElementById('upgradeInsecure').checked;
const frameAncestors = document.getElementById('frameAncestors').checked;
const strictDynamic = document.getElementById('strictDynamic').checked;
let csp = "default-src 'self';\n";
csp += `script-src ${jsSources};\n`;
csp += `style-src ${cssSources};\n`;
csp += `img-src ${imgSources};\n`;
csp += `font-src ${fontSources};\n`;
csp += `connect-src ${connectSources};\n`;
if (strictDynamic) {
csp += "script-src 'strict-dynamic';\n";
}
if (frameAncestors) {
csp += "frame-ancestors 'self';\n";
} else {
csp += "frame-ancestors 'none';\n";
}
csp += "base-uri 'self';\n";
csp += "form-action 'self';\n";
if (blockMixedContent) {
csp += "block-all-mixed-content;\n";
}
if (upgradeInsecure) {
csp += "upgrade-insecure-requests;\n";
}
// Update the generated CSP display
const generatedCSP = document.getElementById('generatedCSP');
if (generatedCSP) {
generatedCSP.textContent = csp;
}
// Run tests
runCSPTests(csp);
}
function copyGeneratedCSP() {
const generatedCSP = document.getElementById('generatedCSP');
if (generatedCSP) {
CSPProject.copyToClipboard(generatedCSP.textContent);
showCopyFeedback();
}
}
function runCSPTests(csp) {
const testResults = document.querySelector('.test-results');
if (!testResults) return;
// Clear existing tests
testResults.innerHTML = '';
const tests = [
{
name: 'Default-src Policy',
check: () => csp.includes('default-src'),
status: csp.includes('default-src') ? 'success' : 'error'
},
{
name: 'Script-src Validation',
check: () => csp.includes('script-src'),
status: csp.includes('script-src') ? 'success' : 'error'
},
{
name: 'Unsafe-inline Warning',
check: () => !csp.includes("'unsafe-inline'") || csp.includes('script-src'),
status: csp.includes("'unsafe-inline'") ? 'warning' : 'success'
},
{
name: 'Frame Protection',
check: () => csp.includes('frame-ancestors'),
status: csp.includes('frame-ancestors') ? 'success' : 'warning'
},
{
name: 'Mixed Content Protection',
check: () => csp.includes('block-all-mixed-content'),
status: csp.includes('block-all-mixed-content') ? 'success' : 'warning'
}
];
tests.forEach(test => {
const testItem = document.createElement('div');
testItem.className = 'test-item';
const statusIcon = document.createElement('span');
statusIcon.className = `test-status ${test.status}`;
statusIcon.textContent = test.status === 'success' ? '✓' : test.status === 'warning' ? '⚠' : '✗';
const statusText = document.createElement('span');
statusText.textContent = test.name;
testItem.appendChild(statusIcon);
testItem.appendChild(statusText);
testResults.appendChild(testItem);
});
}
// CSP Tester Modal
function openCSPTester() {
showModalWithContent('cspTesterModal', `
أدخل سياسة CSP للاختبار:
`);
}
function analyzeCSP() {
const cspInput = document.getElementById('cspToTest');
const results = document.getElementById('testResults');
if (!cspInput || !results) return;
const csp = cspInput.value.trim();
if (!csp) {
results.innerHTML = 'يرجى إدخال سياسة CSP للاختبار
';
return;
}
results.innerHTML = '';
setTimeout(() => {
const analysis = performCSPAnalysis(csp);
displayCSPAnalysis(analysis, results);
}, 1000);
}
function performCSPAnalysis(csp) {
const directives = csp.split(';').map(d => d.trim()).filter(d => d);
const analysis = {
directives: [],
securityScore: 0,
recommendations: [],
vulnerabilities: []
};
directives.forEach(directive => {
const [name, ...values] = directive.split(/\s+/);
const directiveAnalysis = analyzeDirective(name, values.join(' '));
analysis.directives.push(directiveAnalysis);
analysis.securityScore += directiveAnalysis.score;
});
// Overall recommendations
if (!csp.includes('default-src')) {
analysis.recommendations.push('إضافة default-src لتحديد السياسة الافتراضية');
}
if (csp.includes("'unsafe-inline'") && csp.includes('script-src')) {
analysis.vulnerabilities.push("'unsafe-inline' في script-src يسمح بتنفيذ JavaScript ضار");
}
if (!csp.includes('frame-ancestors')) {
analysis.recommendations.push('إضافة frame-ancestors لمنع clickjacking');
}
if (!csp.includes('object-src')) {
analysis.recommendations.push('إضافة object-src \'none\' لمنع plugins خطرة');
}
analysis.securityScore = Math.min(100, Math.max(0, analysis.securityScore));
return analysis;
}
function analyzeDirective(name, values) {
const directive = {
name: name,
values: values,
score: 0,
issues: [],
recommendations: []
};
switch (name) {
case 'default-src':
directive.score = 20;
if (!values.includes("'self'")) {
directive.issues.push("يفضل إضافة 'self' كقيمة افتراضية");
directive.score -= 5;
}
break;
case 'script-src':
directive.score = 30;
if (values.includes("'unsafe-inline'")) {
directive.issues.push("'unsafe-inline' يسمح بتنفيذ JavaScript ضار");
directive.score -= 10;
}
if (values.includes("'unsafe-eval'")) {
directive.issues.push("'unsafe-eval' يسمح بـ code injection");
directive.score -= 10;
}
if (values.includes('*')) {
directive.issues.push("* يسمح بجميع المصادر");
directive.score -= 15;
}
break;
case 'style-src':
directive.score = 15;
if (values.includes("'unsafe-inline'")) {
directive.recommendations.push("استخدم nonces أو hashes بدلاً من 'unsafe-inline'");
directive.score -= 5;
}
break;
case 'frame-ancestors':
directive.score = 15;
if (values.includes('*')) {
directive.issues.push("* يسمح بجميع المواقع بتضمين موقعك");
directive.score -= 10;
}
break;
default:
directive.score = 5;
}
return directive;
}
function displayCSPAnalysis(analysis, container) {
const scoreColor = analysis.securityScore >= 80 ? 'success' :
analysis.securityScore >= 60 ? 'warning' : 'error';
container.innerHTML = `
📊 نتيجة التحليل:
النتيجة: ${analysis.securityScore}/100
📋 تحليل التوجيهات:
${analysis.directives.map(directive => `
${directive.name}
القيم: ${directive.values}
النقاط: ${directive.score}/30
${directive.issues.length > 0 ? `
⚠️
مشاكل:
${directive.issues.map(issue => `- ${issue}
`).join('')}
` : ''}
${directive.recommendations.length > 0 ? `
💡
توصيات:
${directive.recommendations.map(rec => `- ${rec}
`).join('')}
` : ''}
`).join('')}
${analysis.vulnerabilities.length > 0 ? `
🚨
ثغرات أمنية مكتشفة:
${analysis.vulnerabilities.map(vuln => `- ${vuln}
`).join('')}
` : ''}
${analysis.recommendations.length > 0 ? `
💡
توصيات التحسين:
${analysis.recommendations.map(rec => `- ${rec}
`).join('')}
` : ''}
`;
}
// Security Scanner Modal
function openSecurityScanner() {
showModalWithContent('securityScannerModal', `
`);
}
function scanWebsite() {
const urlInput = document.getElementById('siteToScan');
const results = document.getElementById('scanResults');
if (!urlInput || !results) return;
const url = urlInput.value.trim();
if (!url) {
results.innerHTML = 'يرجى إدخال رابط صحيح
';
return;
}
if (!CSPProject.isValidUrl(url)) {
results.innerHTML = 'رابط غير صحيح
';
return;
}
results.innerHTML = '';
// Simulate scanning process
setTimeout(() => {
const scanResults = performSecurityScan(url);
displayScanResults(scanResults, results);
}, 2000);
}
function performSecurityScan(url) {
// Simulate security scan results
return {
url: url,
timestamp: new Date().toLocaleString('ar-SA'),
cspStatus: Math.random() > 0.5 ? 'secure' : 'warning',
headersStatus: Math.random() > 0.7 ? 'secure' : 'warning',
xssVulnerability: Math.random() > 0.8,
mixedContent: Math.random() > 0.6,
score: Math.floor(Math.random() * 40) + 60,
findings: [
{
type: 'CSP',
severity: 'medium',
description: 'سياسة أمان المحتوى موجودة ولكن تحتاج تحسين',
recommendation: 'استخدم strict-dynamic وإزالة unsafe-inline'
},
{
type: 'Headers',
severity: 'low',
description: 'بعض رؤوس الأمان مفقودة',
recommendation: 'أضف X-Frame-Options و X-Content-Type-Options'
}
]
};
}
function displayScanResults(results, container) {
const overallStatus = results.score >= 80 ? 'success' :
results.score >= 60 ? 'warning' : 'error';
container.innerHTML = `
🔍 نتائج الفحص:
النتيجة الإجمالية: ${results.score}/100
الموقع: ${results.url}
وقت الفحص: ${results.timestamp}
📋 النتائج المفصلة:
${results.findings.map(finding => `
${finding.description}
التوصية: ${finding.recommendation}
`).join('')}
🎯 التوصيات:
- تطبيق سياسة CSP شاملة
- تفعيل HTTPS فقط
- إضافة رؤوس الأمان المطلوبة
- فحص دوري للثغرات الأمنية
`;
}
// Code Analyzer Modal
function openCodeAnalyzer() {
showModalWithContent('codeAnalyzerModal', `
أدخل كود JavaScript للتحليل:
`);
}
function analyzeCode() {
const codeInput = document.getElementById('codeToAnalyze');
const results = document.getElementById('codeAnalysisResults');
if (!codeInput || !results) return;
const code = codeInput.value.trim();
if (!code) {
results.innerHTML = 'يرجى إدخال كود للتحليل
';
return;
}
results.innerHTML = '';
setTimeout(() => {
const analysis = performCodeAnalysis(code);
displayCodeAnalysis(analysis, results);
}, 1500);
}
function performCodeAnalysis(code) {
const issues = [];
const recommendations = [];
let securityScore = 100;
// Check for XSS vulnerabilities
if (code.includes('innerHTML') && !code.includes('DOMPurify')) {
issues.push({
type: 'XSS Risk',
severity: 'high',
description: 'استخدام innerHTML قد يؤدي إلى XSS',
line: findLineWithIssue(code, 'innerHTML')
});
securityScore -= 20;
}
if (code.includes('eval(')) {
issues.push({
type: 'Code Injection',
severity: 'critical',
description: 'eval() يسمح بتنفيذ كود ضار',
line: findLineWithIssue(code, 'eval')
});
securityScore -= 30;
}
if (code.includes('document.write')) {
issues.push({
type: 'XSS Risk',
severity: 'medium',
description: 'document.write يمكن أن يسبب XSS',
line: findLineWithIssue(code, 'document.write')
});
securityScore -= 15;
}
// Check for good practices
if (code.includes('trustedTypes') || code.includes('createPolicy')) {
recommendations.push('ممتاز! استخدام Trusted Types للحماية من XSS');
securityScore += 10;
}
if (code.includes('CSP') || code.includes('Content-Security-Policy')) {
recommendations.push('جيد! تطبيق سياسة أمان المحتوى');
securityScore += 5;
}
securityScore = Math.max(0, Math.min(100, securityScore));
return {
issues,
recommendations,
securityScore,
summary: {
totalLines: code.split('\n').length,
securityIssues: issues.length,
recommendations: recommendations.length
}
};
}
function findLineWithIssue(code, issue) {
const lines = code.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].includes(issue)) {
return i + 1;
}
}
return null;
}
function displayCodeAnalysis(analysis, container) {
const status = analysis.securityScore >= 80 ? 'success' :
analysis.securityScore >= 60 ? 'warning' : 'error';
container.innerHTML = `
📊 تحليل الكود:
نقاط الأمان: ${analysis.securityScore}/100
عدد الأسطر: ${analysis.summary.totalLines}
المشاكل الأمنية: ${analysis.summary.securityIssues}
التوصيات: ${analysis.summary.recommendations}
${analysis.issues.length > 0 ? `
⚠️ المشاكل المكتشفة:
${analysis.issues.map(issue => `
`).join('')}
` : ''}
${analysis.recommendations.length > 0 ? `
💡 التوصيات:
${analysis.recommendations.map(rec => `
`).join('')}
` : ''}
🚀 اقتراحات للتحسين:
- استخدم DOMPurify لتنظيف HTML
- طبق Trusted Types للحماية المتقدمة
- تجنب eval() و innerHTML غير المنضبط
- استخدم Content Security Policy
- فحص المدخلات من المستخدمين
`;
}
// Helper function to show modal with custom content
function showModalWithContent(modalId, content) {
const modal = document.getElementById(modalId);
if (modal) {
modal.innerHTML = content;
modal.classList.add('active');
document.body.style.overflow = 'hidden';
// Focus first input
const firstInput = modal.querySelector('input, button, textarea, select');
if (firstInput) {
setTimeout(() => firstInput.focus(), 100);
}
}
}
// Initialize component event listeners
document.addEventListener('DOMContentLoaded', function() {
// Initialize modal close on outside click
document.addEventListener('click', function(e) {
if (e.target.classList.contains('modal')) {
closeModal(e.target.id);
}
});
// Initialize keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
const activeModal = document.querySelector('.modal.active');
if (activeModal) {
closeModal(activeModal.id);
}
}
});
});