云
昨天 a87fcc60346dfc799bd3c2cddc7acfffb105cb61
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const fs = require('node:fs');
const path = require('node:path');
const root = path.resolve(__dirname, '..');
function walk(dir) {
  if (!fs.existsSync(dir)) return [];
  return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? walk(path.join(dir, entry.name)) : [path.join(dir, entry.name)]);
}
const permissionPattern = /['"]((?:system|infra|bpm|crm|erp|hrm|mdm|mes|srm|im|ai|bi|aftersales|member|report|wms)(?::[a-z][a-z0-9-]*){1,5})['"]/g;
const backend = new Map();
const frontend = new Map();
function add(map, permission, file) {
  if (!map.has(permission)) map.set(permission, []);
  map.get(permission).push(path.relative(root, file).replaceAll('\\', '/'));
}
for (const module of fs.readdirSync(root).filter((name) => name.startsWith('yudao-module-'))) {
  for (const file of walk(path.join(root, module, 'src/main/java')).filter((name) => name.endsWith('Controller.java'))) {
    const source = fs.readFileSync(file, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
    for (const annotation of source.matchAll(/@PreAuthorize\(\s*"([^"]+)"\s*\)/g)) {
      for (const match of annotation[1].matchAll(permissionPattern)) add(backend, match[1], file);
    }
  }
}
for (const file of walk(path.join(root, 'mom-pro2-before/src/views')).filter((name) => /\.(vue|ts)$/.test(name))) {
  const source = fs.readFileSync(file, 'utf8').replace(/<!--[^]*?-->/g, '').replace(/\/\*[^]*?\*\//g, '');
  for (const match of source.matchAll(permissionPattern)) add(frontend, match[1], file);
}
const menus = JSON.parse(fs.readFileSync(path.join(__dirname, 'permission-menu-snapshot.json'), 'utf8'));
const active = menus.filter((row) => !row.deleted && row.status === 0);
const db = new Set(active.map((row) => row.permission).filter(Boolean));
const report = {
  counts: { backend: backend.size, frontend: frontend.size, database: db.size },
  frontendWithoutBackend: [...frontend].filter(([key]) => !backend.has(key)).map(([key, files]) => ({ key, files, menus: active.filter((m) => m.permission === key).map((m) => ({ id: m.id, name: m.name, parent_id: m.parent_id })) })),
  frontendWithoutMenu: [...frontend].filter(([key]) => !db.has(key)).map(([key, files]) => ({ key, files })),
  backendWithoutMenu: [...backend].filter(([key]) => !db.has(key)).map(([key, files]) => ({ key, files: [...new Set(files)], usedInFrontend: frontend.has(key) })),
  menuWithoutBackend: active.filter((m) => m.permission && !backend.has(m.permission)),
  duplicatePermissions: [...db].map((key) => ({ key, menus: active.filter((m) => m.permission === key).map((m) => m.id) })).filter((m) => m.menus.length > 1),
};
fs.writeFileSync(path.join(__dirname, 'permission-audit-report.json'), JSON.stringify(report, null, 2));
console.log(JSON.stringify({ counts: report.counts, frontendWithoutBackend: report.frontendWithoutBackend.map((x) => x.key), frontendWithoutMenu: report.frontendWithoutMenu.map((x) => x.key), backendWithoutMenuUsedInFrontend: report.backendWithoutMenu.filter((x) => x.usedInFrontend).map((x) => x.key), menuWithoutBackend: report.menuWithoutBackend.map((x) => ({ id: x.id, permission: x.permission, parent: x.parent_id })), duplicatePermissions: report.duplicatePermissions }, null, 2));