#!/usr/bin/env node /** * SECURITY & AUTHENTICATION VALIDATION TEST * * Tests that claimed pages properly redirect for authentication * and that security fixes are working correctly. */ const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); const BASE_URL = 'https://upskill-staging.measurequick.com'; const SCREENSHOTS_DIR = path.join(__dirname, 'security-test-evidence'); // URLs to test for proper authentication redirects const PROTECTED_URLS = [ '/trainer/venue/list/', '/trainer/venue/manage/', '/trainer/organizer/manage/', '/trainer/profile/training-leads/', '/master-trainer/google-sheets/', '/master-trainer/announcements/', '/master-trainer/pending-approvals/', '/master-trainer/trainers/' ]; class SecurityValidator { constructor() { this.browser = null; this.page = null; this.results = { authenticationTests: [], securityTests: [], overall: { passed: 0, failed: 0 } }; } async init() { if (!fs.existsSync(SCREENSHOTS_DIR)) { fs.mkdirSync(SCREENSHOTS_DIR, { recursive: true }); } this.browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-dev-shm-usage'] }); this.page = await this.browser.newPage(); await this.page.setViewportSize({ width: 1920, height: 1080 }); } async takeScreenshot(name) { const filename = `${name}-${Date.now()}.png`; const filepath = path.join(SCREENSHOTS_DIR, filename); await this.page.screenshot({ path: filepath, fullPage: true }); console.log(`๐Ÿ“ธ Screenshot: ${filename}`); return filename; } async testAuthenticationRedirect(url) { console.log(`\n๐Ÿ” Testing Authentication for: ${url}`); const result = { url, redirectsToLogin: false, properRedirectUrl: null, errors: [], screenshot: null }; try { const response = await this.page.goto(`${BASE_URL}${url}`, { waitUntil: 'networkidle', timeout: 15000 }); const finalUrl = this.page.url(); result.screenshot = await this.takeScreenshot(`auth-test-${url.replace(/[^a-z0-9]/gi, '-')}`); // Check if redirected to login page if (finalUrl.includes('training-login') || finalUrl.includes('wp-login')) { result.redirectsToLogin = true; result.properRedirectUrl = finalUrl; console.log(` โœ… PASS: Properly redirects to login`); console.log(` ๐Ÿ“ Redirect URL: ${finalUrl}`); this.results.overall.passed++; } else if (response.status() === 200 && !finalUrl.includes('login')) { // This would be a security issue - page accessible without auth result.redirectsToLogin = false; result.errors.push('Page accessible without authentication - SECURITY ISSUE'); console.log(` โŒ FAIL: Page accessible without login - SECURITY RISK`); this.results.overall.failed++; } else { result.errors.push(`Unexpected response: ${response.status()}`); console.log(` โš ๏ธ Unexpected response: ${response.status()}`); this.results.overall.failed++; } } catch (error) { result.errors.push(`Test error: ${error.message}`); console.log(` ๐Ÿ’ฅ ERROR: ${error.message}`); this.results.overall.failed++; } return result; } async testAjaxSecurity() { console.log(`\n๐Ÿ”’ Testing AJAX Endpoint Security`); const ajaxEndpoints = [ '/wp-admin/admin-ajax.php?action=hvac_get_trainer_stats', '/wp-admin/admin-ajax.php?action=hvac_manage_announcement', '/wp-admin/admin-ajax.php?action=hvac_approve_trainer' ]; const securityResults = []; for (const endpoint of ajaxEndpoints) { console.log(` ๐Ÿงช Testing: ${endpoint}`); const result = { endpoint, secure: false, statusCode: null, response: null, errors: [] }; try { const response = await this.page.goto(`${BASE_URL}${endpoint}`, { waitUntil: 'networkidle', timeout: 10000 }); result.statusCode = response.status(); const responseText = await this.page.textContent('body'); result.response = responseText ? responseText.substring(0, 200) : 'No response'; // AJAX endpoints should return proper error codes or auth required if (response.status() === 403) { result.secure = true; console.log(` โœ… Returns 403 Forbidden - Properly secured`); } else if (response.status() === 401) { result.secure = true; console.log(` โœ… Returns 401 Unauthorized - Properly secured`); } else if (response.status() === 400 && responseText.includes('Bad Request')) { result.secure = true; // Bad request is fine - at least not accessible console.log(` โœ… Returns 400 Bad Request - Endpoint protected`); } else if (responseText && (responseText.includes('-1') || responseText.trim() === '0')) { result.secure = true; // WordPress AJAX returns -1 or 0 for unauthorized console.log(` โœ… Returns ${responseText.trim()} (WordPress auth failure) - Secured`); } else { result.secure = false; result.errors.push(`Potentially insecure: ${response.status()} - ${responseText.substring(0, 100)}`); console.log(` โŒ May not be properly secured: ${response.status()}`); } } catch (error) { result.errors.push(`AJAX test error: ${error.message}`); console.log(` ๐Ÿ’ฅ Error testing endpoint: ${error.message}`); } securityResults.push(result); } return securityResults; } async runSecurityTests() { console.log('๐Ÿ”’ SECURITY & AUTHENTICATION VALIDATION'); console.log('=' * 45); // Test authentication redirects console.log('\n๐Ÿ“‹ TESTING AUTHENTICATION REDIRECTS'); console.log('-' * 35); for (const url of PROTECTED_URLS) { const result = await this.testAuthenticationRedirect(url); this.results.authenticationTests.push(result); } // Test AJAX security console.log('\n๐Ÿ”’ TESTING AJAX ENDPOINT SECURITY'); console.log('-' * 32); this.results.securityTests = await this.testAjaxSecurity(); await this.generateSecurityReport(); } async generateSecurityReport() { console.log('\n๐Ÿ“Š SECURITY VALIDATION REPORT'); console.log('=' * 30); const totalTests = this.results.authenticationTests.length + this.results.securityTests.length; const successRate = totalTests > 0 ? ((this.results.overall.passed / totalTests) * 100).toFixed(1) : 0; console.log(`\n๐ŸŽฏ SUMMARY`); console.log(`Total Tests: ${totalTests}`); console.log(`Passed: ${this.results.overall.passed}`); console.log(`Failed: ${this.results.overall.failed}`); console.log(`Success Rate: ${successRate}%`); console.log(`\n๐Ÿ” AUTHENTICATION RESULTS:`); this.results.authenticationTests.forEach(test => { const status = test.redirectsToLogin ? 'โœ… SECURED' : 'โŒ VULNERABLE'; console.log(` ${status} ${test.url}`); if (test.errors.length > 0) { test.errors.forEach(error => console.log(` โš ๏ธ ${error}`)); } }); console.log(`\n๐Ÿ”’ AJAX SECURITY RESULTS:`); this.results.securityTests.forEach(test => { const status = test.secure ? 'โœ… SECURE' : 'โŒ INSECURE'; console.log(` ${status} ${test.endpoint} (${test.statusCode})`); if (test.errors.length > 0) { test.errors.forEach(error => console.log(` โš ๏ธ ${error}`)); } }); // Save detailed report const reportPath = path.join(__dirname, 'security-validation-report.json'); fs.writeFileSync(reportPath, JSON.stringify(this.results, null, 2)); console.log(`\n๐Ÿ“„ Detailed report: ${reportPath}`); console.log(`๐Ÿ“ธ Evidence: ${SCREENSHOTS_DIR}`); return this.results; } async cleanup() { if (this.browser) { await this.browser.close(); } } } async function main() { const validator = new SecurityValidator(); try { await validator.init(); await validator.runSecurityTests(); } catch (error) { console.error('๐Ÿ’ฅ Security test failed:', error); process.exit(1); } finally { await validator.cleanup(); } } if (require.main === module) { main().catch(console.error); } module.exports = { SecurityValidator };