![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/public_html/scripts/ |
#!/usr/bin/env ts-node
import * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
interface AuditResult {
file: string;
type: 'page' | 'api';
hasPermissionGuard: boolean;
missingGuard: boolean;
suggestedFix: string;
}
class PermissionAuditor {
private results: AuditResult[] = [];
async auditCodebase() {
console.log('š Starting Permission Audit...\n');
// Audit pages
await this.auditPages();
// Audit API endpoints
await this.auditApiEndpoints();
// Generate report
this.generateReport();
}
private async auditPages() {
console.log('š Auditing Pages...');
const pageFiles = glob.sync('src/pages/**/*.tsx', { ignore: ['**/node_modules/**'] });
for (const file of pageFiles) {
const content = fs.readFileSync(file, 'utf-8');
const isPage = this.isPageComponent(content);
if (isPage) {
const hasGuard = this.hasPermissionGuard(content);
const missingGuard = this.shouldHavePermissionGuard(file, content);
this.results.push({
file,
type: 'page',
hasPermissionGuard: hasGuard,
missingGuard: missingGuard && !hasGuard,
suggestedFix: this.getSuggestedFix(file, 'page')
});
}
}
}
private async auditApiEndpoints() {
console.log('š Auditing API Endpoints...');
const apiFiles = glob.sync('src/pages/api/**/*.ts', { ignore: ['**/node_modules/**'] });
for (const file of apiFiles) {
const content = fs.readFileSync(file, 'utf-8');
const isApiHandler = this.isApiHandler(content);
if (isApiHandler) {
const hasGuard = this.hasApiPermissionGuard(content);
const missingGuard = this.shouldHaveApiPermissionGuard(file, content);
this.results.push({
file,
type: 'api',
hasPermissionGuard: hasGuard,
missingGuard: missingGuard && !hasGuard,
suggestedFix: this.getSuggestedFix(file, 'api')
});
}
}
}
private isPageComponent(content: string): boolean {
return content.includes('export default') &&
(content.includes('React.FC') || content.includes('NextPage') || content.includes('function'));
}
private isApiHandler(content: string): boolean {
return content.includes('export default') &&
(content.includes('NextApiRequest') || content.includes('NextApiResponse'));
}
private hasPermissionGuard(content: string): boolean {
return content.includes('useRequireRole') ||
content.includes('canAccessAdmin') ||
content.includes('canAccessLawyer') ||
content.includes('canAccessPage');
}
private hasApiPermissionGuard(content: string): boolean {
return content.includes('requireAuth') ||
content.includes('requireRole') ||
content.includes('canAccessAdmin') ||
content.includes('canAccessLawyer') ||
content.includes('canAccessCase');
}
private shouldHavePermissionGuard(file: string, content: string): boolean {
// Skip certain files that don't need guards
const skipFiles = [
'_app.tsx', '_document.tsx', '_error.tsx', 'index.tsx', 'unauthorized.tsx',
'terms.tsx', 'privacy.tsx', 'who.tsx', 'test-', 'society-dashboard.tsx'
];
if (skipFiles.some(skip => file.includes(skip))) {
return false;
}
// Check if it's a dashboard or protected page
const protectedPaths = [
'/admin/', '/lawyer/', '/user/', '/client/', '/judge/', '/jurist/',
'/mediator/', '/investigator/', '/expert/', '/notary/', '/secretary/',
'/paralegal/', '/student/', '/support/'
];
return protectedPaths.some(path => file.includes(path));
}
private shouldHaveApiPermissionGuard(file: string, content: string): boolean {
// Skip public APIs
const publicApis = [
'/api/public/', '/api/auth/', '/api/register', '/api/webhooks/',
'/api/test-', '/api/debug-'
];
if (publicApis.some(api => file.includes(api))) {
return false;
}
// Check if it's a protected API
const protectedApis = [
'/api/admin/', '/api/lawyer/', '/api/user/', '/api/cases/',
'/api/analytics/', '/api/payments/', '/api/live-cases/'
];
return protectedApis.some(api => file.includes(api));
}
private getSuggestedFix(file: string, type: 'page' | 'api'): string {
if (type === 'page') {
return `Add useRequireRole hook to protect this page. Example:
import { useRequireRole, USER_ROLES } from '@/lib/auth-utils';
const { isAuthorized } = useRequireRole([USER_ROLES.LAWYER], '/auth/login');`;
} else {
return `Add requireAuth and requireRole guards. Example:
import { requireAuth, requireRole } from '@/lib/auth-utils';
const session = await requireAuth(req, res);
await requireRole(req, res, [USER_ROLES.ADMIN]);`;
}
}
private generateReport() {
console.log('\nš PERMISSION AUDIT REPORT\n');
console.log('=' .repeat(50));
const missingGuards = this.results.filter(r => r.missingGuard);
const hasGuards = this.results.filter(r => r.hasPermissionGuard);
console.log(`\nā
Files with permission guards: ${hasGuards.length}`);
console.log(`ā Files missing permission guards: ${missingGuards.length}`);
console.log(`š Total files audited: ${this.results.length}`);
if (missingGuards.length > 0) {
console.log('\nš“ CRITICAL: Missing Permission Guards\n');
const missingPages = missingGuards.filter(r => r.type === 'page');
const missingApis = missingGuards.filter(r => r.type === 'api');
if (missingPages.length > 0) {
console.log('š Pages missing permission guards:');
missingPages.forEach(result => {
console.log(` ā ${result.file}`);
console.log(` ${result.suggestedFix.split('\n')[0]}`);
});
}
if (missingApis.length > 0) {
console.log('\nš API endpoints missing permission guards:');
missingApis.forEach(result => {
console.log(` ā ${result.file}`);
console.log(` ${result.suggestedFix.split('\n')[0]}`);
});
}
console.log('\nš ļø RECOMMENDED ACTIONS:');
console.log('1. Add useRequireRole to all missing pages');
console.log('2. Add requireAuth/requireRole to all missing API endpoints');
console.log('3. Test with different user roles');
console.log('4. Update PERMISSIONS.md documentation');
} else {
console.log('\nš All files have proper permission guards!');
}
// Save detailed report
const reportPath = 'permission-audit-report.json';
fs.writeFileSync(reportPath, JSON.stringify(this.results, null, 2));
console.log(`\nš Detailed report saved to: ${reportPath}`);
}
}
// Run the audit
async function main() {
const auditor = new PermissionAuditor();
await auditor.auditCodebase();
}
if (require.main === module) {
main().catch(console.error);
}
export { PermissionAuditor };