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.
Files changed (108) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +141 -1191
  3. package/main/i18ntk-analyze.js +65 -84
  4. package/main/i18ntk-backup-class.js +420 -0
  5. package/main/i18ntk-backup.js +3 -3
  6. package/main/i18ntk-complete.js +90 -65
  7. package/main/i18ntk-doctor.js +123 -103
  8. package/main/i18ntk-fixer.js +61 -725
  9. package/main/i18ntk-go.js +14 -15
  10. package/main/i18ntk-init.js +77 -26
  11. package/main/i18ntk-java.js +27 -32
  12. package/main/i18ntk-js.js +70 -68
  13. package/main/i18ntk-manage.js +129 -30
  14. package/main/i18ntk-php.js +75 -75
  15. package/main/i18ntk-py.js +55 -56
  16. package/main/i18ntk-scanner.js +59 -57
  17. package/main/i18ntk-setup.js +9 -404
  18. package/main/i18ntk-sizing.js +6 -6
  19. package/main/i18ntk-summary.js +21 -18
  20. package/main/i18ntk-ui.js +11 -10
  21. package/main/i18ntk-usage.js +54 -18
  22. package/main/i18ntk-validate.js +13 -13
  23. package/main/manage/commands/AnalyzeCommand.js +1124 -0
  24. package/main/manage/commands/BackupCommand.js +62 -0
  25. package/main/manage/commands/CommandRouter.js +295 -0
  26. package/main/manage/commands/CompleteCommand.js +61 -0
  27. package/main/manage/commands/DoctorCommand.js +60 -0
  28. package/main/manage/commands/FixerCommand.js +624 -0
  29. package/main/manage/commands/InitCommand.js +62 -0
  30. package/main/manage/commands/ScannerCommand.js +654 -0
  31. package/main/manage/commands/SizingCommand.js +60 -0
  32. package/main/manage/commands/SummaryCommand.js +61 -0
  33. package/main/manage/commands/UsageCommand.js +60 -0
  34. package/main/manage/commands/ValidateCommand.js +978 -0
  35. package/main/manage/index-fixed.js +1447 -0
  36. package/main/manage/index.js +1462 -0
  37. package/main/manage/managers/DebugMenu.js +140 -0
  38. package/main/manage/managers/InteractiveMenu.js +177 -0
  39. package/main/manage/managers/LanguageMenu.js +62 -0
  40. package/main/manage/managers/SettingsMenu.js +53 -0
  41. package/main/manage/services/AuthenticationService.js +263 -0
  42. package/main/manage/services/ConfigurationService-fixed.js +449 -0
  43. package/main/manage/services/ConfigurationService.js +449 -0
  44. package/main/manage/services/FileManagementService.js +368 -0
  45. package/main/manage/services/FrameworkDetectionService.js +458 -0
  46. package/main/manage/services/InitService.js +1051 -0
  47. package/main/manage/services/SetupService.js +462 -0
  48. package/main/manage/services/SummaryService.js +450 -0
  49. package/main/manage/services/UsageService.js +1502 -0
  50. package/package.json +32 -29
  51. package/runtime/enhanced.d.ts +221 -221
  52. package/runtime/index.d.ts +29 -29
  53. package/runtime/index.full.d.ts +331 -331
  54. package/runtime/index.js +7 -6
  55. package/scripts/build-lite.js +17 -17
  56. package/scripts/deprecate-versions.js +23 -6
  57. package/scripts/export-translations.js +5 -5
  58. package/scripts/fix-all-i18n.js +3 -3
  59. package/scripts/fix-and-purify-i18n.js +3 -2
  60. package/scripts/fix-locale-control-chars.js +110 -0
  61. package/scripts/lint-locales.js +80 -0
  62. package/scripts/locale-optimizer.js +8 -8
  63. package/scripts/prepublish.js +21 -21
  64. package/scripts/security-check.js +117 -117
  65. package/scripts/sync-translations.js +4 -4
  66. package/scripts/sync-ui-locales.js +9 -8
  67. package/scripts/validate-all-translations.js +8 -7
  68. package/scripts/verify-deprecations.js +157 -161
  69. package/scripts/verify-translations.js +6 -5
  70. package/settings/i18ntk-config.json +282 -282
  71. package/settings/language-config.json +5 -5
  72. package/settings/settings-cli.js +9 -9
  73. package/settings/settings-manager.js +18 -18
  74. package/ui-locales/de.json +2417 -2348
  75. package/ui-locales/en.json +2415 -2352
  76. package/ui-locales/es.json +2425 -2353
  77. package/ui-locales/fr.json +2418 -2348
  78. package/ui-locales/ja.json +2463 -2361
  79. package/ui-locales/ru.json +2463 -2359
  80. package/ui-locales/zh.json +2418 -2351
  81. package/utils/admin-auth.js +2 -2
  82. package/utils/admin-cli.js +297 -297
  83. package/utils/admin-pin.js +9 -9
  84. package/utils/cli-helper.js +9 -9
  85. package/utils/config-helper.js +73 -104
  86. package/utils/config-manager.js +204 -171
  87. package/utils/config.js +5 -4
  88. package/utils/env-manager.js +249 -263
  89. package/utils/framework-detector.js +27 -24
  90. package/utils/i18n-helper.js +85 -41
  91. package/utils/init-helper.js +152 -94
  92. package/utils/json-output.js +98 -98
  93. package/utils/mini-commander.js +179 -0
  94. package/utils/missing-key-validator.js +5 -5
  95. package/utils/plugin-loader.js +40 -29
  96. package/utils/prompt.js +14 -44
  97. package/utils/safe-json.js +40 -0
  98. package/utils/secure-errors.js +3 -3
  99. package/utils/security-check-improved.js +390 -0
  100. package/utils/security-config.js +5 -5
  101. package/utils/security-fixed.js +607 -0
  102. package/utils/security.js +652 -602
  103. package/utils/setup-enforcer.js +136 -44
  104. package/utils/setup-validator.js +33 -32
  105. package/utils/ultra-performance-optimizer.js +11 -9
  106. package/utils/watch-locales.js +2 -1
  107. package/utils/prompt-fixed.js +0 -55
  108. 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;
@@ -124,7 +124,7 @@ class SecurityConfig {
124
124
 
125
125
  // Ensure config directory exists
126
126
  const configDir = path.dirname(this.configPath);
127
- if (!fs.existsSync(configDir)) {
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
- fs.writeFileSync(this.configPath, JSON.stringify(safeConfig, null, 2));
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 (!fs.existsSync(this.configPath)) {
153
+ if (!SecurityUtils.safeExistsSync(this.configPath)) {
154
154
  return this.createSecureConfig();
155
155
  }
156
156
 
157
157
  try {
158
- const config = JSON.parse(fs.readFileSync(this.configPath, 'utf8'));
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 (fs.existsSync(this.configPath)) {
181
+ if (SecurityUtils.safeExistsSync(this.configPath)) {
182
182
  fs.copyFileSync(this.configPath, `${this.configPath}.backup.${timestamp}`);
183
183
  }
184
184