i18ntk 1.10.2 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +141 -1191
- package/main/i18ntk-analyze.js +65 -84
- package/main/i18ntk-backup-class.js +420 -0
- package/main/i18ntk-backup.js +3 -3
- package/main/i18ntk-complete.js +90 -65
- package/main/i18ntk-doctor.js +123 -103
- package/main/i18ntk-fixer.js +61 -725
- package/main/i18ntk-go.js +14 -15
- package/main/i18ntk-init.js +77 -26
- package/main/i18ntk-java.js +27 -32
- package/main/i18ntk-js.js +70 -68
- package/main/i18ntk-manage.js +129 -30
- package/main/i18ntk-php.js +75 -75
- package/main/i18ntk-py.js +55 -56
- package/main/i18ntk-scanner.js +59 -57
- package/main/i18ntk-setup.js +9 -404
- package/main/i18ntk-sizing.js +6 -6
- package/main/i18ntk-summary.js +21 -18
- package/main/i18ntk-ui.js +11 -10
- package/main/i18ntk-usage.js +54 -18
- package/main/i18ntk-validate.js +13 -13
- package/main/manage/commands/AnalyzeCommand.js +1124 -0
- package/main/manage/commands/BackupCommand.js +62 -0
- package/main/manage/commands/CommandRouter.js +295 -0
- package/main/manage/commands/CompleteCommand.js +61 -0
- package/main/manage/commands/DoctorCommand.js +60 -0
- package/main/manage/commands/FixerCommand.js +624 -0
- package/main/manage/commands/InitCommand.js +62 -0
- package/main/manage/commands/ScannerCommand.js +654 -0
- package/main/manage/commands/SizingCommand.js +60 -0
- package/main/manage/commands/SummaryCommand.js +61 -0
- package/main/manage/commands/UsageCommand.js +60 -0
- package/main/manage/commands/ValidateCommand.js +978 -0
- package/main/manage/index-fixed.js +1447 -0
- package/main/manage/index.js +1462 -0
- package/main/manage/managers/DebugMenu.js +140 -0
- package/main/manage/managers/InteractiveMenu.js +177 -0
- package/main/manage/managers/LanguageMenu.js +62 -0
- package/main/manage/managers/SettingsMenu.js +53 -0
- package/main/manage/services/AuthenticationService.js +263 -0
- package/main/manage/services/ConfigurationService-fixed.js +449 -0
- package/main/manage/services/ConfigurationService.js +449 -0
- package/main/manage/services/FileManagementService.js +368 -0
- package/main/manage/services/FrameworkDetectionService.js +458 -0
- package/main/manage/services/InitService.js +1051 -0
- package/main/manage/services/SetupService.js +462 -0
- package/main/manage/services/SummaryService.js +450 -0
- package/main/manage/services/UsageService.js +1502 -0
- package/package.json +32 -29
- package/runtime/enhanced.d.ts +221 -221
- package/runtime/index.d.ts +29 -29
- package/runtime/index.full.d.ts +331 -331
- package/runtime/index.js +7 -6
- package/scripts/build-lite.js +17 -17
- package/scripts/deprecate-versions.js +23 -6
- package/scripts/export-translations.js +5 -5
- package/scripts/fix-all-i18n.js +3 -3
- package/scripts/fix-and-purify-i18n.js +3 -2
- package/scripts/fix-locale-control-chars.js +110 -0
- package/scripts/lint-locales.js +80 -0
- package/scripts/locale-optimizer.js +8 -8
- package/scripts/prepublish.js +21 -21
- package/scripts/security-check.js +117 -117
- package/scripts/sync-translations.js +4 -4
- package/scripts/sync-ui-locales.js +9 -8
- package/scripts/validate-all-translations.js +8 -7
- package/scripts/verify-deprecations.js +157 -161
- package/scripts/verify-translations.js +6 -5
- package/settings/i18ntk-config.json +282 -282
- package/settings/language-config.json +5 -5
- package/settings/settings-cli.js +9 -9
- package/settings/settings-manager.js +18 -18
- package/ui-locales/de.json +2417 -2348
- package/ui-locales/en.json +2415 -2352
- package/ui-locales/es.json +2425 -2353
- package/ui-locales/fr.json +2418 -2348
- package/ui-locales/ja.json +2463 -2361
- package/ui-locales/ru.json +2463 -2359
- package/ui-locales/zh.json +2418 -2351
- package/utils/admin-auth.js +2 -2
- package/utils/admin-cli.js +297 -297
- package/utils/admin-pin.js +9 -9
- package/utils/cli-helper.js +9 -9
- package/utils/config-helper.js +73 -104
- package/utils/config-manager.js +204 -171
- package/utils/config.js +5 -4
- package/utils/env-manager.js +249 -263
- package/utils/framework-detector.js +27 -24
- package/utils/i18n-helper.js +85 -41
- package/utils/init-helper.js +152 -94
- package/utils/json-output.js +98 -98
- package/utils/mini-commander.js +179 -0
- package/utils/missing-key-validator.js +5 -5
- package/utils/plugin-loader.js +40 -29
- package/utils/prompt.js +14 -44
- package/utils/safe-json.js +40 -0
- package/utils/secure-errors.js +3 -3
- package/utils/security-check-improved.js +390 -0
- package/utils/security-config.js +5 -5
- package/utils/security-fixed.js +607 -0
- package/utils/security.js +652 -602
- package/utils/setup-enforcer.js +136 -44
- package/utils/setup-validator.js +33 -32
- package/utils/ultra-performance-optimizer.js +11 -9
- package/utils/watch-locales.js +2 -1
- package/utils/prompt-fixed.js +0 -55
- package/utils/security-check.js +0 -454
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* i18ntk Security Check Utility - IMPROVED VERSION
|
|
5
|
+
* Performs comprehensive security validation before build/publish
|
|
6
|
+
* Enhanced to intelligently distinguish between safe and dangerous requires
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const crypto = require('crypto');
|
|
12
|
+
|
|
13
|
+
class SecurityChecker {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.issues = [];
|
|
16
|
+
this.warnings = [];
|
|
17
|
+
this.projectRoot = path.resolve(__dirname, '..');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
log(message, type = 'info') {
|
|
21
|
+
const timestamp = new Date().toISOString();
|
|
22
|
+
const colors = {
|
|
23
|
+
error: '\x1b[31m',
|
|
24
|
+
warning: '\x1b[33m',
|
|
25
|
+
success: '\x1b[32m',
|
|
26
|
+
info: '\x1b[36m',
|
|
27
|
+
reset: '\x1b[0m'
|
|
28
|
+
};
|
|
29
|
+
console.log(`${colors[type]}[${timestamp}] ${message}${colors.reset}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
addIssue(message, file = null, line = null) {
|
|
33
|
+
this.issues.push({ message, file, line, type: 'error' });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
addWarning(message, file = null, line = null) {
|
|
37
|
+
this.warnings.push({ message, file, line, type: 'warning' });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async checkFileExists(filePath) {
|
|
41
|
+
try {
|
|
42
|
+
await fs.promises.access(filePath);
|
|
43
|
+
return true;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async readFile(filePath) {
|
|
50
|
+
try {
|
|
51
|
+
return await fs.promises.readFile(filePath, 'utf8');
|
|
52
|
+
} catch (error) {
|
|
53
|
+
this.addIssue(`Cannot read file: ${filePath}`, filePath);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async checkPackageJson() {
|
|
59
|
+
this.log('Checking package.json security...');
|
|
60
|
+
|
|
61
|
+
const packageJsonPath = path.join(this.projectRoot, 'package.json');
|
|
62
|
+
const content = await this.readFile(packageJsonPath);
|
|
63
|
+
|
|
64
|
+
if (!content) return;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const pkg = JSON.parse(content);
|
|
68
|
+
|
|
69
|
+
// Check for dangerous scripts
|
|
70
|
+
const dangerousScripts = ['preinstall', 'postinstall', 'preuninstall', 'postuninstall'];
|
|
71
|
+
const scripts = pkg.scripts || {};
|
|
72
|
+
|
|
73
|
+
for (const script of dangerousScripts) {
|
|
74
|
+
if (scripts[script]) {
|
|
75
|
+
this.addWarning(`Potentially dangerous script found: ${script}`, packageJsonPath);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check dependencies for known vulnerabilities (basic check)
|
|
80
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
81
|
+
for (const [dep, version] of Object.entries(allDeps || {})) {
|
|
82
|
+
if (version.includes('*') || version.includes('latest')) {
|
|
83
|
+
this.addWarning(`Unpinned dependency version: ${dep}@${version}`, packageJsonPath);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Verify security scripts exist
|
|
88
|
+
const requiredScripts = ['security:check', 'security:test', 'security:audit'];
|
|
89
|
+
for (const script of requiredScripts) {
|
|
90
|
+
if (!scripts[script]) {
|
|
91
|
+
this.addIssue(`Missing required security script: ${script}`, packageJsonPath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
} catch (error) {
|
|
96
|
+
this.addIssue(`Invalid JSON in package.json: ${error.message}`, packageJsonPath);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async checkSecurityUtils() {
|
|
101
|
+
this.log('Checking SecurityUtils implementation...');
|
|
102
|
+
|
|
103
|
+
const securityUtilsPath = path.join(this.projectRoot, 'utils/security.js');
|
|
104
|
+
if (!(await this.checkFileExists(securityUtilsPath))) {
|
|
105
|
+
this.addIssue('SecurityUtils file not found', securityUtilsPath);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const content = await this.readFile(securityUtilsPath);
|
|
110
|
+
if (!content) return;
|
|
111
|
+
|
|
112
|
+
// Check for required security methods
|
|
113
|
+
const requiredMethods = [
|
|
114
|
+
'safeReadFileSync',
|
|
115
|
+
'safeExistsSync',
|
|
116
|
+
'safeWriteFileSync',
|
|
117
|
+
'validatePath',
|
|
118
|
+
'sanitizeInput',
|
|
119
|
+
'safeParseJSON'
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
for (const method of requiredMethods) {
|
|
123
|
+
if (!content.includes(method)) {
|
|
124
|
+
this.addIssue(`Missing security method: ${method}`, securityUtilsPath);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check for dangerous patterns (excluding the overly broad require pattern)
|
|
129
|
+
const dangerousPatterns = [
|
|
130
|
+
/fs\.readFileSync\s*\(/g,
|
|
131
|
+
/fs\.writeFileSync\s*\(/g,
|
|
132
|
+
/fs\.existsSync\s*\(/g,
|
|
133
|
+
/eval\s*\(/g,
|
|
134
|
+
/Function\s*\(/g
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
for (const pattern of dangerousPatterns) {
|
|
138
|
+
const matches = content.match(pattern);
|
|
139
|
+
if (matches) {
|
|
140
|
+
this.addWarning(`Potentially unsafe pattern found: ${pattern}`, securityUtilsPath);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async checkSourceFiles() {
|
|
146
|
+
this.log('Checking source files for security issues...');
|
|
147
|
+
|
|
148
|
+
const sourceDirs = ['main', 'utils', 'scripts', 'settings'];
|
|
149
|
+
const excludeFiles = ['security.js', 'security-fixed.js', 'security-check.js', 'security-check-improved.js'];
|
|
150
|
+
|
|
151
|
+
for (const dir of sourceDirs) {
|
|
152
|
+
const dirPath = path.join(this.projectRoot, dir);
|
|
153
|
+
if (!(await this.checkFileExists(dirPath))) continue;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const files = await fs.promises.readdir(dirPath);
|
|
157
|
+
for (const file of files) {
|
|
158
|
+
if (!file.endsWith('.js') || excludeFiles.includes(file)) continue;
|
|
159
|
+
|
|
160
|
+
const filePath = path.join(dirPath, file);
|
|
161
|
+
const content = await this.readFile(filePath);
|
|
162
|
+
if (!content) continue;
|
|
163
|
+
|
|
164
|
+
await this.analyzeFileSecurity(filePath, content);
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
this.addIssue(`Cannot read directory: ${dirPath}`, dirPath);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async analyzeFileSecurity(filePath, content) {
|
|
173
|
+
const lines = content.split('\n');
|
|
174
|
+
|
|
175
|
+
lines.forEach((line, index) => {
|
|
176
|
+
// Check for direct fs operations
|
|
177
|
+
if (line.includes('fs.readFileSync(') && !line.includes('SecurityUtils')) {
|
|
178
|
+
this.addIssue('Direct fs.readFileSync usage (use SecurityUtils.safeReadFileSync)', filePath, index + 1);
|
|
179
|
+
}
|
|
180
|
+
if (line.includes('fs.writeFileSync(') && !line.includes('SecurityUtils')) {
|
|
181
|
+
this.addIssue('Direct fs.writeFileSync usage (use SecurityUtils.safeWriteFileSync)', filePath, index + 1);
|
|
182
|
+
}
|
|
183
|
+
if (line.includes('fs.existsSync(') && !line.includes('SecurityUtils')) {
|
|
184
|
+
this.addIssue('Direct fs.existsSync usage (use SecurityUtils.safeExistsSync)', filePath, index + 1);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check for dangerous patterns
|
|
188
|
+
if (line.includes('eval(') || line.includes('Function(')) {
|
|
189
|
+
this.addIssue('Dangerous code execution pattern detected', filePath, index + 1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Check for unsafe require patterns - be more intelligent
|
|
193
|
+
if (line.includes('require(')) {
|
|
194
|
+
this.analyzeRequireStatement(line, filePath, index + 1);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
analyzeRequireStatement(line, filePath, lineNumber) {
|
|
200
|
+
// Extract the require path
|
|
201
|
+
const requireMatch = line.match(/require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/);
|
|
202
|
+
if (!requireMatch) return;
|
|
203
|
+
|
|
204
|
+
const requirePath = requireMatch[1];
|
|
205
|
+
|
|
206
|
+
// Skip safe built-in modules
|
|
207
|
+
// Note: child_process is intentionally excluded to keep runtime zero-shell
|
|
208
|
+
const safeBuiltins = ['fs', 'path', 'crypto', 'os', 'util', 'events', 'stream', 'buffer', 'http', 'https', 'url', 'querystring'];
|
|
209
|
+
if (safeBuiltins.includes(requirePath)) {
|
|
210
|
+
return; // Safe built-in module
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Skip safe relative requires within project structure
|
|
214
|
+
if (requirePath.startsWith('../') || requirePath.startsWith('./')) {
|
|
215
|
+
// Check if it's going too far up (more than 2 levels)
|
|
216
|
+
const upLevels = (requirePath.match(/\.\.\//g) || []).length;
|
|
217
|
+
if (upLevels > 2) {
|
|
218
|
+
this.addWarning('Deep relative require (more than 2 levels up)', filePath, lineNumber);
|
|
219
|
+
}
|
|
220
|
+
// Otherwise, relative requires within project are generally safe
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Check for dynamic requires (variables)
|
|
225
|
+
if (requirePath.includes('${') || requirePath.includes('+') || requirePath.includes('variable')) {
|
|
226
|
+
this.addIssue('Dynamic require statement detected (potential security risk)', filePath, lineNumber);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Check for absolute paths outside node_modules
|
|
231
|
+
if (requirePath.startsWith('/') && !requirePath.includes('node_modules')) {
|
|
232
|
+
this.addWarning('Absolute path require outside node_modules', filePath, lineNumber);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check for suspicious patterns
|
|
237
|
+
const suspiciousPatterns = [
|
|
238
|
+
/\.\./, // path traversal
|
|
239
|
+
/^~/, // home directory shorthand
|
|
240
|
+
/\$(HOME|USER)\b/, // shell env expansions
|
|
241
|
+
/^[a-z][a-z0-9+.-]*:/i // URL/protocol-like require targets
|
|
242
|
+
];
|
|
243
|
+
for (const pattern of suspiciousPatterns) {
|
|
244
|
+
if (pattern.test(requirePath)) {
|
|
245
|
+
this.addIssue(`Suspicious require path pattern: ${pattern}`, filePath, lineNumber);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// If we get here, it's likely a safe npm package require
|
|
251
|
+
// No action needed for legitimate package requires
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async checkFilePermissions() {
|
|
255
|
+
this.log('Checking file permissions...');
|
|
256
|
+
|
|
257
|
+
const criticalFiles = [
|
|
258
|
+
'utils/security.js',
|
|
259
|
+
'tests/security.test.js',
|
|
260
|
+
'package.json'
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
for (const file of criticalFiles) {
|
|
264
|
+
const filePath = path.join(this.projectRoot, file);
|
|
265
|
+
if (!(await this.checkFileExists(filePath))) {
|
|
266
|
+
this.addIssue(`Critical file not found: ${file}`, filePath);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
const stats = await fs.promises.stat(filePath);
|
|
272
|
+
const permissions = (stats.mode & parseInt('777', 8)).toString(8);
|
|
273
|
+
|
|
274
|
+
// Check if file is writable by group or others
|
|
275
|
+
if (permissions[1] !== '0' || permissions[2] !== '0') {
|
|
276
|
+
this.addWarning(`File has overly permissive permissions: ${file} (${permissions})`, filePath);
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
this.addIssue(`Cannot check permissions for: ${file}`, filePath);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async checkDependencies() {
|
|
285
|
+
this.log('Checking for dependency vulnerabilities...');
|
|
286
|
+
|
|
287
|
+
const packageJsonPath = path.join(this.projectRoot, 'package.json');
|
|
288
|
+
const content = await this.readFile(packageJsonPath);
|
|
289
|
+
|
|
290
|
+
if (!content) return;
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
const pkg = JSON.parse(content);
|
|
294
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
295
|
+
|
|
296
|
+
// Check for zero dependencies claim
|
|
297
|
+
if (Object.keys(allDeps || {}).length > 0) {
|
|
298
|
+
this.addWarning('Package claims zero dependencies but has dependencies in package.json');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Check for suspicious dependency names
|
|
302
|
+
const suspiciousDeps = ['malicious', 'hack', 'exploit', 'trojan'];
|
|
303
|
+
for (const dep of Object.keys(allDeps || {})) {
|
|
304
|
+
for (const suspicious of suspiciousDeps) {
|
|
305
|
+
if (dep.toLowerCase().includes(suspicious)) {
|
|
306
|
+
this.addIssue(`Suspicious dependency name: ${dep}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
this.addIssue(`Cannot parse package.json: ${error.message}`, packageJsonPath);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async run() {
|
|
316
|
+
this.log('Starting i18ntk Security Check (IMPROVED VERSION)...', 'info');
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
await this.checkPackageJson();
|
|
320
|
+
await this.checkSecurityUtils();
|
|
321
|
+
await this.checkSourceFiles();
|
|
322
|
+
await this.checkFilePermissions();
|
|
323
|
+
await this.checkDependencies();
|
|
324
|
+
|
|
325
|
+
// Generate report
|
|
326
|
+
this.generateReport();
|
|
327
|
+
|
|
328
|
+
// Final status with detailed counts
|
|
329
|
+
const totalIssues = this.issues.length + this.warnings.length;
|
|
330
|
+
if (this.issues.length > 0) {
|
|
331
|
+
this.log(`Security check FAILED: ${this.issues.length} critical issues, ${this.warnings.length} warnings found`, 'error');
|
|
332
|
+
this.log(`Total: ${totalIssues} issues detected`, 'error');
|
|
333
|
+
// Ensure output is flushed before exit
|
|
334
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
335
|
+
process.exit(1);
|
|
336
|
+
} else if (this.warnings.length > 0) {
|
|
337
|
+
this.log('Security check PASSED: No critical issues found', 'success');
|
|
338
|
+
this.log(`${this.warnings.length} warnings found (non-blocking)`, 'warning');
|
|
339
|
+
this.log(`Total: ${totalIssues} issues detected`, 'warning');
|
|
340
|
+
} else {
|
|
341
|
+
this.log('Security check PASSED: No issues found', 'success');
|
|
342
|
+
}
|
|
343
|
+
} catch (error) {
|
|
344
|
+
this.log(`Security check failed with error: ${error.message}`, 'error');
|
|
345
|
+
console.error('Stack trace:', error.stack);
|
|
346
|
+
process.exit(1);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
generateReport() {
|
|
351
|
+
if (this.issues.length === 0 && this.warnings.length === 0) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
console.log('\n=== SECURITY CHECK REPORT (IMPROVED) ===\n');
|
|
356
|
+
|
|
357
|
+
if (this.issues.length > 0) {
|
|
358
|
+
console.log('🔴 CRITICAL ISSUES:');
|
|
359
|
+
this.issues.forEach(issue => {
|
|
360
|
+
console.log(` • ${issue.message}`);
|
|
361
|
+
if (issue.file) {
|
|
362
|
+
console.log(` File: ${issue.file}${issue.line ? `:${issue.line}` : ''}`);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
console.log('');
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (this.warnings.length > 0) {
|
|
369
|
+
console.log('🟡 WARNINGS:');
|
|
370
|
+
this.warnings.forEach(warning => {
|
|
371
|
+
console.log(` • ${warning.message}`);
|
|
372
|
+
if (warning.file) {
|
|
373
|
+
console.log(` File: ${warning.file}${warning.line ? `:${warning.line}` : ''}`);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
console.log('');
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Run security check if called directly
|
|
382
|
+
if (require.main === module) {
|
|
383
|
+
const checker = new SecurityChecker();
|
|
384
|
+
checker.run().catch(error => {
|
|
385
|
+
console.error('Security check failed:', error);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
module.exports = SecurityChecker;
|
package/utils/security-config.js
CHANGED
|
@@ -124,7 +124,7 @@ class SecurityConfig {
|
|
|
124
124
|
|
|
125
125
|
// Ensure config directory exists
|
|
126
126
|
const configDir = path.dirname(this.configPath);
|
|
127
|
-
if (!
|
|
127
|
+
if (!SecurityUtils.safeExistsSync(configDir)) {
|
|
128
128
|
fs.mkdirSync(configDir, { recursive: true });
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -138,7 +138,7 @@ class SecurityConfig {
|
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
SecurityUtils.safeWriteFileSync(this.configPath, JSON.stringify(safeConfig, null, 2));
|
|
142
142
|
|
|
143
143
|
return {
|
|
144
144
|
configPath: this.configPath,
|
|
@@ -150,12 +150,12 @@ class SecurityConfig {
|
|
|
150
150
|
* Load and validate existing configuration
|
|
151
151
|
*/
|
|
152
152
|
loadSecurityConfig() {
|
|
153
|
-
if (!
|
|
153
|
+
if (!SecurityUtils.safeExistsSync(this.configPath)) {
|
|
154
154
|
return this.createSecureConfig();
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
try {
|
|
158
|
-
const config = JSON.parse(
|
|
158
|
+
const config = JSON.parse(SecurityUtils.safeReadFileSync(this.configPath, path.dirname(this.configPath), 'utf8'));
|
|
159
159
|
const validation = this.validateSecurityConfig(config);
|
|
160
160
|
|
|
161
161
|
return {
|
|
@@ -178,7 +178,7 @@ class SecurityConfig {
|
|
|
178
178
|
const timestamp = new Date().toISOString();
|
|
179
179
|
|
|
180
180
|
// Create backup of old config
|
|
181
|
-
if (
|
|
181
|
+
if (SecurityUtils.safeExistsSync(this.configPath)) {
|
|
182
182
|
fs.copyFileSync(this.configPath, `${this.configPath}.backup.${timestamp}`);
|
|
183
183
|
}
|
|
184
184
|
|