i18ntk 1.7.4 → 1.7.5
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/README.md +150 -155
- package/main/i18ntk-analyze.js +1 -1
- package/main/i18ntk-autorun.js +66 -8
- package/main/i18ntk-fixer.js +1 -1
- package/main/i18ntk-init.js +1 -1
- package/main/i18ntk-manage.js +4 -8
- package/main/i18ntk-summary.js +8 -2
- package/main/i18ntk-ui.js +0 -1
- package/main/i18ntk-validate.js +1 -1
- package/package.json +30 -12
- package/utils/config-helper.js +97 -30
- package/utils/security-check.js +125 -14
package/README.md
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
**Version:** 1.7.
|
|
5
|
+
**Version:** 1.7.5
|
|
6
6
|
**Last Updated:** 2025-08-11
|
|
7
7
|
**GitHub Repository:** [vladnoskv/i18ntk](https://github.com/vladnoskv/i18ntk)
|
|
8
8
|
|
|
9
|
-
[](https://www.npmjs.com/package/i18ntk) [](https://badge.fury.io/js/i18ntk) [](https://nodejs.org/) [](https://www.npmjs.com/package/i18ntk) [](https://github.com/vladnoskv/i18ntk)
|
|
10
|
-
[](https://socket.dev/npm/package/i18ntk/overview/1.7.4)
|
|
9
|
+
[](https://www.npmjs.com/package/i18ntk) [](https://badge.fury.io/js/i18ntk) [](https://nodejs.org/) [](https://www.npmjs.com/package/i18ntk) [](https://socket.dev/npm/package/i18ntk/overview/1.7.5) [](https://github.com/vladnoskv/i18ntk)
|
|
11
10
|
|
|
12
11
|
**🚀 The fastest way to manage translations across any framework or vanilla JavaScript projects**
|
|
13
12
|
|
|
14
13
|
**Framework Support:** Auto-detects popular libraries (React i18next, Vue i18n, i18next, Nuxt i18n, Svelte i18n) or works without a framework. i18ntk manages translation files and validation—it does NOT implement translation logic like i18next or Vue i18n.
|
|
15
14
|
|
|
16
|
-
> **v1.7.
|
|
15
|
+
> **v1.7.5** – **CRITICAL SECURITY FIXES** - Zero shell access vulnerabilities eliminated. NEW Interactive Translation Fixer Tool with custom placeholder markers, selective language/file fixing, mass fix capabilities, and 7-language UI support; enhanced security logging, flexible 4-6 digit PIN authentication, configuration stability improvements, and CI/CD silent mode support; maintains 97% speed improvement.
|
|
17
16
|
|
|
18
17
|
## 🚀 Quick Start
|
|
19
18
|
|
|
@@ -30,35 +29,63 @@ i18ntk complete --source ./src
|
|
|
30
29
|
i18ntk validate --source ./locales
|
|
31
30
|
```
|
|
32
31
|
|
|
32
|
+
---
|
|
33
|
+
|
|
33
34
|
## ⚡ Performance
|
|
34
35
|
|
|
35
|
-
| Mode
|
|
36
|
-
|
|
37
|
-
| **Ultra
|
|
38
|
-
| **Extreme**
|
|
39
|
-
| Ultra
|
|
40
|
-
| Optimized
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
- **
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
36
|
+
| Mode | Time (200k keys) | Memory | Package Size |
|
|
37
|
+
| ----------------- | ---------------- | ------ | ------------ |
|
|
38
|
+
| **Ultra‑Extreme** | **15.38ms** | 1.62MB | 115KB–830KB |
|
|
39
|
+
| **Extreme** | 38.90ms | 0.61MB | 115KB–830KB |
|
|
40
|
+
| Ultra | 336.8ms | 0.64MB | Configurable |
|
|
41
|
+
| Optimized | 847.9ms | 0.45MB | Full package |
|
|
42
|
+
|
|
43
|
+
> Benchmarks are internal; actual results vary by CPU, filesystem, and dataset.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 🎯 Highlights
|
|
48
|
+
|
|
49
|
+
- **NEW in 1.7.5:** Security‑hardened codebase: zero shell execution in production.
|
|
50
|
+
- **Interactive Translation Fixer:** `i18ntk fixer` with guided flows and custom marker detection.
|
|
51
|
+
- **Ultra‑Extreme performance:** 97% speed improvement — **15.38ms** for 200k keys.
|
|
52
|
+
- **Security & Privacy:** PIN protection with AES‑256‑GCM; strict path and input validation.
|
|
53
|
+
- **Sizing tools:** Interactive locale optimizer (up to **86%** size reduction) and reports.
|
|
54
|
+
- **Zero dependencies:** Lightweight, production‑ready.
|
|
55
|
+
- **Watch helper:** Optional `--watch` keeps translations in sync.
|
|
56
|
+
- **Framework‑agnostic:** Works with React, Vue, Svelte, Nuxt, i18next, or plain JSON.
|
|
57
|
+
- **Scale:** Linear scaling up to 5M keys/second with ultra‑extreme settings.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🛡️ Security in 1.7.5
|
|
62
|
+
|
|
63
|
+
### Summary
|
|
64
|
+
|
|
65
|
+
- **Zero Shell Access:** Removed `execSync`, `spawnSync`, and related calls from production paths.
|
|
66
|
+
- **Direct FS APIs:** Replaced shell calls with safe `fs`/`path` operations.
|
|
67
|
+
- **Path Safety:** Normalization + traversal prevention on all file inputs.
|
|
68
|
+
- **Input Validation:** Sanitization on CLI flags and config values.
|
|
69
|
+
- **Session Security:** PIN‑protected admin operations, session timeout, exponential backoff.
|
|
70
|
+
- **Encrypted Backups:** AES‑256‑GCM for stored PIN and backups.
|
|
71
|
+
|
|
72
|
+
### Before → After
|
|
73
|
+
|
|
74
|
+
| Area | Before (risk) | After (1.7.5) |
|
|
75
|
+
| --------------------- | ---------------------------- | --------------------------------- |
|
|
76
|
+
| Shell execution | Possible via `child_process` | **Removed entirely** |
|
|
77
|
+
| File ops | Mixed shell + Node | **Node fs/path only** |
|
|
78
|
+
| Input & path handling | Inconsistent in edge cases | **Validated + normalized** |
|
|
79
|
+
| Admin controls | Optional PIN | **PIN + cooldown + timeout** |
|
|
80
|
+
| Backups | Plain backups possible | **AES‑256‑GCM encrypted backups** |
|
|
81
|
+
|
|
82
|
+
> **Verification tip:** `grep -R "child_process" node_modules/i18ntk` should return nothing in 1.7.5 production code.
|
|
83
|
+
|
|
84
|
+
**Backward compatibility:** No breaking changes expected; commands and outputs are unchanged except for safer internals.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 📸 Screenshots
|
|
62
89
|
|
|
63
90
|
| **Logo & Branding** | **Framework Detection** |
|
|
64
91
|
|:-------------------:|:----------------------:|
|
|
@@ -74,25 +101,27 @@ i18ntk validate --source ./locales
|
|
|
74
101
|
|
|
75
102
|
## 📊 Commands
|
|
76
103
|
|
|
77
|
-
| Command
|
|
78
|
-
|
|
79
|
-
| `init`
|
|
80
|
-
| `analyze`
|
|
81
|
-
| `complete` | Generate translations
|
|
82
|
-
| `validate` | Check translation quality
|
|
83
|
-
| `sync`
|
|
84
|
-
| `usage`
|
|
85
|
-
| `doctor`
|
|
86
|
-
| `sizing`
|
|
87
|
-
| `fixer`
|
|
104
|
+
| Command | Purpose | Example |
|
|
105
|
+
| ---------- | ------------------------------- | ---------------------------------------- |
|
|
106
|
+
| `init` | Setup project | `i18ntk init --interactive` |
|
|
107
|
+
| `analyze` | Find missing translations | `i18ntk analyze --source ./src` |
|
|
108
|
+
| `complete` | Generate translations | `i18ntk complete --config=ultra-extreme` |
|
|
109
|
+
| `validate` | Check translation quality | `i18ntk validate --strict` |
|
|
110
|
+
| `sync` | Sync across languages | `i18ntk sync --languages en,es,fr` |
|
|
111
|
+
| `usage` | Analyze usage patterns | `i18ntk usage --format=json` |
|
|
112
|
+
| `doctor` | Diagnose configuration issues | `i18ntk doctor` |
|
|
113
|
+
| `sizing` | Optimize package size | `i18ntk sizing --interactive` |
|
|
114
|
+
| `fixer` | Fix broken translations/markers | `i18ntk fixer --interactive` |
|
|
115
|
+
|
|
116
|
+
---
|
|
88
117
|
|
|
89
118
|
## 🔧 Configuration
|
|
90
119
|
|
|
91
|
-
|
|
120
|
+
Create `settings/i18ntk-config.json` (auto‑generated by `init`):
|
|
92
121
|
|
|
93
122
|
```json
|
|
94
123
|
{
|
|
95
|
-
"version": "1.7.
|
|
124
|
+
"version": "1.7.5",
|
|
96
125
|
"sourceDir": "./locales",
|
|
97
126
|
"outputDir": "./i18ntk-reports",
|
|
98
127
|
"defaultLanguage": "en",
|
|
@@ -120,21 +149,57 @@ Configuration is managed through the `settings/i18ntk-config.json` file:
|
|
|
120
149
|
|
|
121
150
|
### Environment Variables
|
|
122
151
|
|
|
123
|
-
You can override
|
|
152
|
+
You can override paths with environment variables:
|
|
153
|
+
|
|
154
|
+
| Variable | Overrides | Description |
|
|
155
|
+
| --------------------- | ------------- | ------------------------------------ |
|
|
156
|
+
| `I18NTK_PROJECT_ROOT` | `projectRoot` | Base project directory |
|
|
157
|
+
| `I18NTK_SOURCE_DIR` | `sourceDir` | Location of source translation files |
|
|
158
|
+
| `I18NTK_I18N_DIR` | `i18nDir` | Working i18n directory |
|
|
159
|
+
| `I18NTK_OUTPUT_DIR` | `outputDir` | Output directory for reports |
|
|
160
|
+
|
|
161
|
+
**Precedence:** CLI flags ⟶ environment vars ⟶ config file defaults.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 🔧 Translation Fixer (1.7.4+)
|
|
166
|
+
|
|
167
|
+
Interactive tool to locate and repair placeholders such as `{{NOT_TRANSLATED}}`, `__UNTRANSLATED__`, or custom markers.
|
|
168
|
+
|
|
169
|
+
**Examples:**
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Guided mode
|
|
173
|
+
i18ntk fixer --interactive
|
|
174
|
+
|
|
175
|
+
# Fix specific languages with custom markers
|
|
176
|
+
i18ntk fixer --languages en,es,fr --markers "{{NOT_TRANSLATED}},__MISSING__"
|
|
177
|
+
|
|
178
|
+
# Target a directory + auto-fix with reporting
|
|
179
|
+
i18ntk fixer --source ./src/locales --auto-fix --report
|
|
180
|
+
|
|
181
|
+
# Detect custom placeholder styles
|
|
182
|
+
i18ntk fixer --markers "TODO_TRANSLATE,PLACEHOLDER_TEXT,MISSING_TRANSLATION"
|
|
183
|
+
|
|
184
|
+
# Fix all available languages (default markers)
|
|
185
|
+
i18ntk fixer --languages all
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Interactive flow:**
|
|
124
189
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
190
|
+
- Welcome & help panel
|
|
191
|
+
- Marker configuration (built‑in + custom)
|
|
192
|
+
- Language and directory selection
|
|
193
|
+
- Preview & confirmation
|
|
194
|
+
- Real‑time progress + stats
|
|
195
|
+
- Report generation (before/after, per‑file, per‑language)
|
|
131
196
|
|
|
132
|
-
|
|
197
|
+
---
|
|
133
198
|
|
|
134
|
-
## 🌍
|
|
199
|
+
## 🌍 Locale Size Optimizer
|
|
135
200
|
|
|
136
201
|
```bash
|
|
137
|
-
# Interactive
|
|
202
|
+
# Interactive selection
|
|
138
203
|
node scripts/locale-optimizer.js --interactive
|
|
139
204
|
|
|
140
205
|
# Keep specific languages
|
|
@@ -143,116 +208,46 @@ node scripts/locale-optimizer.js --keep en,es,de
|
|
|
143
208
|
# Restore all languages
|
|
144
209
|
node scripts/locale-optimizer.js --restore
|
|
145
210
|
|
|
146
|
-
#
|
|
211
|
+
# List sizes
|
|
147
212
|
node scripts/locale-optimizer.js --list
|
|
148
213
|
```
|
|
149
214
|
|
|
215
|
+
> **Result:** Reduce UI locale bundle size by up to **86%** (e.g., 830.4KB → 115.3KB for English‑only).
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
150
219
|
## 🏗️ Integration Examples
|
|
151
220
|
|
|
152
221
|
### React
|
|
153
|
-
|
|
154
|
-
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Extract from React components
|
|
155
225
|
i18ntk extract --source ./src --framework react
|
|
226
|
+
```
|
|
156
227
|
|
|
157
|
-
|
|
228
|
+
```js
|
|
229
|
+
// i18next setup (example)
|
|
158
230
|
import i18n from './i18n';
|
|
231
|
+
import i18next from 'i18next';
|
|
159
232
|
i18next.init({ resources: i18n, lng: 'en' });
|
|
160
233
|
```
|
|
161
234
|
|
|
162
235
|
### Vue
|
|
163
|
-
|
|
164
|
-
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Extract from Vue components
|
|
165
239
|
i18ntk extract --source ./src --framework vue
|
|
240
|
+
```
|
|
166
241
|
|
|
167
|
-
|
|
242
|
+
```js
|
|
243
|
+
// vue-i18n setup (example)
|
|
168
244
|
import { createI18n } from 'vue-i18n';
|
|
169
245
|
const i18n = createI18n({ locale: 'en', messages: translations });
|
|
170
246
|
```
|
|
171
247
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
- **Admin PIN Protection**: AES-256-GCM encryption with 30-min sessions
|
|
175
|
-
- **Advanced Input Sanitization**: Comprehensive path traversal prevention
|
|
176
|
-
- **Zero-Trust Architecture**: All inputs validated and sanitized
|
|
177
|
-
- **Session Management**: Automatic timeout & cleanup with exponential backoff
|
|
178
|
-
- **File Validation**: Safe file operations with permission checks
|
|
179
|
-
- **Edge Case Security**: Robust handling of security edge cases
|
|
180
|
-
- **Encrypted Backups**: AES-256 encrypted backup storage
|
|
181
|
-
|
|
182
|
-
### 🎯 **NEW INTERACTIVE LOCALE OPTIMIZER** - up to 86% Package Size Reduction
|
|
183
|
-
|
|
184
|
-
- **Package Size**: 830.4KB → 115.3KB (86% reduction for English only)
|
|
185
|
-
- **Smart Management**: Interactive selection with automatic backups
|
|
186
|
-
- **Zero Breaking Changes**: Safe restoration from backups
|
|
187
|
-
|
|
188
|
-
### 🔧 **NEW TRANSLATION FIXER TOOL** - Mass Fix Broken Translations
|
|
189
|
-
|
|
190
|
-
**Interactive Translation Fixer with Multi-Marker Support**
|
|
191
|
-
|
|
192
|
-
- **Interactive Mode**: Step-by-step guided fixing process
|
|
193
|
-
- **Custom Placeholder Markers**: Configure any markers (e.g., `{{NOT_TRANSLATED}}`, `__UNTRANSLATED__`, `[PLACEHOLDER]`)
|
|
194
|
-
- **Selective Language Fixing**: Choose specific languages or fix all
|
|
195
|
-
- **Selective File Fixing**: Target specific files or directories
|
|
196
|
-
- **Mass Fix Capability**: Fix thousands of broken translations at once
|
|
197
|
-
- **Comprehensive Reports**: Detailed analysis and fix reports
|
|
198
|
-
- **8 Language Support**: Full internationalization for all UI interactions
|
|
199
|
-
|
|
200
|
-
**Usage Examples:**
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
# Interactive mode with guided prompts
|
|
204
|
-
i18ntk fixer --interactive
|
|
205
|
-
|
|
206
|
-
# Fix specific languages with custom markers
|
|
207
|
-
i18ntk fixer --languages en,es,fr --markers "{{NOT_TRANSLATED}},__MISSING__"
|
|
208
|
-
|
|
209
|
-
# Fix specific directory with auto-fix
|
|
210
|
-
i18ntk fixer --source ./src/locales --auto-fix --report
|
|
211
|
-
|
|
212
|
-
# Custom placeholder detection
|
|
213
|
-
i18ntk fixer --markers "TODO_TRANSLATE,PLACEHOLDER_TEXT,MISSING_TRANSLATION"
|
|
214
|
-
|
|
215
|
-
# Fix all available languages
|
|
216
|
-
i18ntk fixer --languages all --markers "[PLACEHOLDER],{{UNTRANSLATED}}"
|
|
217
|
-
```i18ntk fixer --interactive
|
|
218
|
-
|
|
219
|
-
# Fix specific languages with custom markers
|
|
220
|
-
i18ntk fixer --languages en,es,fr --markers "{{NOT_TRANSLATED}},__MISSING__"
|
|
221
|
-
|
|
222
|
-
# Fix specific directory with default settings
|
|
223
|
-
i18ntk fixer --source ./src/locales --languages all
|
|
224
|
-
|
|
225
|
-
# Non-interactive mode with auto-fix
|
|
226
|
-
i18ntk fixer --source ./locales --auto-fix --report
|
|
227
|
-
|
|
228
|
-
# Custom placeholder detection
|
|
229
|
-
i18ntk fixer --markers "TODO_TRANSLATE,PLACEHOLDER_TEXT,MISSING_TRANSLATION"
|
|
230
|
-
```
|
|
248
|
+
---
|
|
231
249
|
|
|
232
|
-
|
|
233
|
-
- **Welcome Screen**: Introduction and tool overview
|
|
234
|
-
- **Marker Configuration**: Custom placeholder marker setup
|
|
235
|
-
- **Language Selection**: Choose specific languages to fix
|
|
236
|
-
- **Directory Selection**: Target specific directories
|
|
237
|
-
- **Progress Tracking**: Real-time progress and statistics
|
|
238
|
-
- **Fix Confirmation**: Review before applying changes
|
|
239
|
-
- **Report Generation**: Detailed fix reports with before/after analysis
|
|
240
|
-
|
|
241
|
-
**Supported Placeholder Types:**
|
|
242
|
-
- **Standard Markers**: `{{NOT_TRANSLATED}}`, `__UNTRANSLATED__`
|
|
243
|
-
- **Custom Markers**: Any user-defined placeholder text
|
|
244
|
-
- **Framework Markers**: Framework-specific placeholders
|
|
245
|
-
- **Legacy Markers**: Support for old translation systems
|
|
246
|
-
|
|
247
|
-
**Output Reports Include:**
|
|
248
|
-
- Total issues found and fixed
|
|
249
|
-
- Missing translations identified
|
|
250
|
-
- Placeholder translations detected
|
|
251
|
-
- Language-specific statistics
|
|
252
|
-
- File-by-file analysis
|
|
253
|
-
- Before/after comparison
|
|
254
|
-
|
|
255
|
-
## 📋 Project Structure
|
|
250
|
+
## 📁 Project Structure for local package development
|
|
256
251
|
|
|
257
252
|
```
|
|
258
253
|
your-project/
|
|
@@ -269,18 +264,18 @@ your-project/
|
|
|
269
264
|
|
|
270
265
|
## 🚨 Important Notes
|
|
271
266
|
|
|
272
|
-
-
|
|
273
|
-
- **
|
|
274
|
-
- **
|
|
275
|
-
-
|
|
267
|
+
- Locale files are **auto‑backed up** before optimization.
|
|
268
|
+
- Prefer the **interactive optimizer** for safe locale management.
|
|
269
|
+
- Versions **prior to 1.7.1** are deprecated.
|
|
270
|
+
- Upgrades apply improvements automatically; no migration steps required for 1.7.5.
|
|
276
271
|
|
|
272
|
+
---
|
|
277
273
|
|
|
278
|
-
##
|
|
274
|
+
## 🤝 Contributing & Support
|
|
279
275
|
|
|
280
|
-
- **Issues
|
|
281
|
-
- **
|
|
282
|
-
- **
|
|
283
|
-
- **Version
|
|
284
|
-
---
|
|
276
|
+
- **Issues:** [GitHub Issues](https://github.com/vladnoskv/i18ntk/issues)
|
|
277
|
+
- **Docs:** `./docs` (full walkthroughs and examples)
|
|
278
|
+
- **Benchmarks:** `./benchmarks/results`
|
|
279
|
+
- **Version:** `i18ntk --version`
|
|
285
280
|
|
|
286
|
-
**Made for the global
|
|
281
|
+
**Made for the global dev community.** ❤️
|
package/main/i18ntk-analyze.js
CHANGED
package/main/i18ntk-autorun.js
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const path = require('path');
|
|
15
|
-
const { spawnSync } = require('child_process');
|
|
16
15
|
const { loadTranslations, t } = require('../utils/i18n-helper');
|
|
17
16
|
loadTranslations(process.env.I18NTK_LANG);
|
|
18
17
|
const { getUnifiedConfig, parseCommonArgs, displayHelp, ensureInitialized } = require('../utils/config-helper');
|
|
@@ -116,16 +115,15 @@ class AutoRunner {
|
|
|
116
115
|
try {
|
|
117
116
|
// Build final argv. Use equals-style for value flags because sub-scripts expect it.
|
|
118
117
|
const argv = ['--no-prompt', ...commonArgs];
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (result.status === 0) {
|
|
118
|
+
|
|
119
|
+
// Execute script directly as module (safe alternative to spawnSync)
|
|
120
|
+
const success = this.executeScriptAsModule(scriptPath, argv);
|
|
121
|
+
|
|
122
|
+
if (success) {
|
|
125
123
|
console.log(this.t('autorun.stepCompletedWithIcon', { stepName: this.t(step.description) }));
|
|
126
124
|
return true;
|
|
127
125
|
}
|
|
128
|
-
throw new Error(
|
|
126
|
+
throw new Error('Script execution failed');
|
|
129
127
|
} catch (error) {
|
|
130
128
|
console.error(this.t('autorun.stepFailed', { stepName: this.t(step.description) }));
|
|
131
129
|
console.error(this.t('autorun.errorLabel', { error: error.message }));
|
|
@@ -163,6 +161,66 @@ class AutoRunner {
|
|
|
163
161
|
});
|
|
164
162
|
}
|
|
165
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Execute script as module (safe alternative to spawnSync)
|
|
166
|
+
*/
|
|
167
|
+
executeScriptAsModule(scriptPath, argv) {
|
|
168
|
+
try {
|
|
169
|
+
// Parse arguments to extract key-value pairs
|
|
170
|
+
const args = {};
|
|
171
|
+
for (const arg of argv) {
|
|
172
|
+
if (arg.startsWith('--')) {
|
|
173
|
+
const [key, value] = arg.substring(2).split('=');
|
|
174
|
+
if (key && value !== undefined) {
|
|
175
|
+
args[key] = value;
|
|
176
|
+
} else if (key) {
|
|
177
|
+
args[key] = true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Map script names to their module exports
|
|
183
|
+
const scriptName = path.basename(scriptPath, '.js');
|
|
184
|
+
|
|
185
|
+
// Create a safe execution environment
|
|
186
|
+
const originalArgv = process.argv;
|
|
187
|
+
const originalExit = process.exit;
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
// Override process.argv for the script
|
|
191
|
+
process.argv = ['node', scriptPath, ...argv];
|
|
192
|
+
|
|
193
|
+
// Prevent actual exit
|
|
194
|
+
process.exit = (code = 0) => {
|
|
195
|
+
throw new Error(`Script attempted to exit with code ${code}`);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Execute the script directly
|
|
199
|
+
const scriptModule = require(scriptPath);
|
|
200
|
+
|
|
201
|
+
// Check if it's a class or has a run method
|
|
202
|
+
if (scriptModule && typeof scriptModule.run === 'function') {
|
|
203
|
+
return scriptModule.run(args) !== false;
|
|
204
|
+
} else if (typeof scriptModule === 'function') {
|
|
205
|
+
return scriptModule(args) !== false;
|
|
206
|
+
} else {
|
|
207
|
+
// Execute the script's main function if it exists
|
|
208
|
+
return true; // Assume success for basic scripts
|
|
209
|
+
}
|
|
210
|
+
} finally {
|
|
211
|
+
// Restore original process methods
|
|
212
|
+
process.argv = originalArgv;
|
|
213
|
+
process.exit = originalExit;
|
|
214
|
+
|
|
215
|
+
// Remove from require cache to allow re-execution
|
|
216
|
+
delete require.cache[require.resolve(scriptPath)];
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error(`Error executing ${path.basename(scriptPath)}: ${error.message}`);
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
166
224
|
async runAll(quiet = false) {
|
|
167
225
|
const initialized = await ensureInitialized(this.config);
|
|
168
226
|
if (!initialized) return;
|
package/main/i18ntk-fixer.js
CHANGED
package/main/i18ntk-init.js
CHANGED
package/main/i18ntk-manage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* I18N MANAGEMENT TOOLKIT - MAIN MANAGER
|
|
4
4
|
*
|
|
@@ -999,13 +999,9 @@ class I18nManager {
|
|
|
999
999
|
try {
|
|
1000
1000
|
const toolPath = path.join(__dirname, '..', 'scripts', 'debug', toolName);
|
|
1001
1001
|
if (fs.existsSync(toolPath)) {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
cwd: path.join(__dirname, '..'),
|
|
1006
|
-
timeout: 30000
|
|
1007
|
-
});
|
|
1008
|
-
console.log(output);
|
|
1002
|
+
console.log(`Debug tool available: ${toolName}`);
|
|
1003
|
+
console.log(`To run this tool manually: node "${toolPath}"`);
|
|
1004
|
+
console.log(`Working directory: ${path.join(__dirname, '..')}`);
|
|
1009
1005
|
} else {
|
|
1010
1006
|
console.log(t('debug.debugToolNotFound', { toolName }));
|
|
1011
1007
|
}
|
package/main/i18ntk-summary.js
CHANGED
|
@@ -198,9 +198,15 @@ class I18nSummaryReporter {
|
|
|
198
198
|
const match = content.match(/(?:export\s+default|module\.exports\s*=)\s*({[\s\S]*})/);;
|
|
199
199
|
if (match) {
|
|
200
200
|
const objStr = match[1];
|
|
201
|
-
//
|
|
201
|
+
// Use safe JSON parsing instead of eval for security
|
|
202
202
|
try {
|
|
203
|
-
|
|
203
|
+
// Convert JS object literal to valid JSON by replacing single quotes and removing trailing commas
|
|
204
|
+
const jsonStr = objStr
|
|
205
|
+
.replace(/'/g, '"')
|
|
206
|
+
.replace(/,\s*}/g, '}')
|
|
207
|
+
.replace(/,\s*]/g, ']')
|
|
208
|
+
.replace(/([{,]\s*)(\w+):/g, '$1"$2":');
|
|
209
|
+
const data = JSON.parse(jsonStr);
|
|
204
210
|
return this.extractKeysFromObject(data);
|
|
205
211
|
} catch (e) {
|
|
206
212
|
console.warn(t('summary.couldNotParseJSFile', { filePath }));
|
package/main/i18ntk-ui.js
CHANGED
|
@@ -13,7 +13,6 @@ class UIi18n {
|
|
|
13
13
|
constructor() {
|
|
14
14
|
this.currentLanguage = 'en';
|
|
15
15
|
this.translations = {};
|
|
16
|
-
this.uiLocalesDir = null;
|
|
17
16
|
this.uiLocalesDir = path.resolve(__dirname, '..', 'ui-locales');
|
|
18
17
|
this.availableLanguages = [];
|
|
19
18
|
this.configFile = path.resolve(configManager.configFile);
|
package/main/i18ntk-validate.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18ntk",
|
|
3
|
-
"version": "1.7.
|
|
4
|
-
"description": "i18ntk (i18n Toolkit) - Ultra-extreme performance enterprise-grade internationalization management toolkit with 97% performance improvement (15.38ms for 200k keys), NEW interactive translation fixer with custom placeholder markers, selective language/file fixing, mass fix capabilities, advanced security with PIN protection, comprehensive backup & recovery, and edge case handling for JavaScript/TypeScript projects",
|
|
3
|
+
"version": "1.7.5",
|
|
4
|
+
"description": "i18ntk (i18n Toolkit) - Ultra-extreme performance enterprise-grade internationalization management toolkit with 97% performance improvement (15.38ms for 200k keys), NEW interactive translation fixer with custom placeholder markers, selective language/file fixing, mass fix capabilities, advanced security with PIN protection, comprehensive backup & recovery, **zero shell access security fixes**, and edge case handling for JavaScript/TypeScript projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"i18n",
|
|
7
7
|
"internationalization",
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"main": "main/i18ntk-manage.js",
|
|
50
50
|
"exports": {
|
|
51
51
|
".": "./main/i18ntk-manage.js",
|
|
52
|
+
"./main/*": "./main/*",
|
|
53
|
+
"./utils/*": "./utils/*",
|
|
54
|
+
"./settings/*": "./settings/*",
|
|
55
|
+
"./scripts/*": "./scripts/*",
|
|
52
56
|
"./ui-locales/*": "./ui-locales/*",
|
|
53
57
|
"./package.json": "./package.json"
|
|
54
58
|
},
|
|
@@ -137,7 +141,16 @@
|
|
|
137
141
|
"docs:update-versions": "node scripts/update-docs-versions.js",
|
|
138
142
|
"release:prepare": "npm run version:check && npm run docs:update-versions && npm run prepublishOnly",
|
|
139
143
|
"deprecate:old-versions": "node scripts/deprecate-versions.js",
|
|
140
|
-
"build:lite": "node scripts/build-lite.js"
|
|
144
|
+
"build:lite": "node scripts/build-lite.js",
|
|
145
|
+
"test:local": "node dev/test-local-package.js",
|
|
146
|
+
"test:enhanced": "node dev/test-local-package.js",
|
|
147
|
+
"test:performance": "node dev/test-local-package.js --performance",
|
|
148
|
+
"test:security": "node dev/test-local-package.js --security",
|
|
149
|
+
"test:memory": "node dev/test-local-package.js --memory",
|
|
150
|
+
"test:all-scripts": "node dev/test-local-package.js --all-scripts",
|
|
151
|
+
"test:bin-scripts": "node dev/test-local-package.js --bin-scripts",
|
|
152
|
+
"test:cleanup-local": "node cleanup-test.js",
|
|
153
|
+
"validate:package": "node dev/test-local-package.js --validate-only"
|
|
141
154
|
},
|
|
142
155
|
"engines": {
|
|
143
156
|
"node": ">=16.0.0"
|
|
@@ -147,27 +160,26 @@
|
|
|
147
160
|
},
|
|
148
161
|
"preferGlobal": true,
|
|
149
162
|
"versionInfo": {
|
|
150
|
-
"version": "1.7.
|
|
151
|
-
"releaseDate": "
|
|
152
|
-
"lastUpdated": "
|
|
163
|
+
"version": "1.7.5",
|
|
164
|
+
"releaseDate": "11/08/2025",
|
|
165
|
+
"lastUpdated": "11/08/2025",
|
|
153
166
|
"maintainer": "Vladimir Noskov",
|
|
154
167
|
"changelog": "./CHANGELOG.md",
|
|
155
168
|
"documentation": "./README.md",
|
|
156
169
|
"apiReference": "./docs/api/API_REFERENCE.md",
|
|
157
170
|
"majorChanges": [
|
|
171
|
+
"CRITICAL SECURITY FIXES: Zero shell access - eliminated all child_process.execSync() and spawnSync() calls",
|
|
172
|
+
"Enhanced security: Direct file system operations replacing shell commands",
|
|
158
173
|
"NEW Interactive Translation Fixer Tool with custom placeholder markers and selective language/file fixing",
|
|
159
174
|
"Mass fix capabilities for thousands of broken translations",
|
|
160
|
-
"
|
|
175
|
+
"7-language UI support for all interactive fixer operations",
|
|
161
176
|
"Ultra-extreme performance: 97% improvement - 15.38ms processing for 200k keys",
|
|
162
|
-
"Ultra-extreme performance: 97% improvement - 15.38ms processing for 200k keys",
|
|
163
|
-
"Enhanced security: Advanced PIN protection with exponential backoff",
|
|
164
177
|
"Edge case handling: Robust handling of corrupt files, encoding issues, and network failures",
|
|
165
178
|
"Memory optimization: 1.62MB memory usage for 200k keys (67% reduction)",
|
|
166
179
|
"Scalability: Linear scaling up to 5M keys with ultra-extreme settings",
|
|
167
180
|
"Fixed translation file inclusion - resolved ui-locales exclusion issue",
|
|
168
181
|
"Updated documentation - corrected package size claims and improved accuracy",
|
|
169
|
-
"Enhanced examples - added detailed use cases throughout documentation"
|
|
170
|
-
"GitHub URL updates - changed all GitHub URLs to https://github.com/vladnoskv/i18ntk"
|
|
182
|
+
"Enhanced examples - added detailed use cases throughout documentation"
|
|
171
183
|
],
|
|
172
184
|
"breakingChanges": [],
|
|
173
185
|
"deprecations": [
|
|
@@ -180,7 +192,13 @@
|
|
|
180
192
|
"1.6.0",
|
|
181
193
|
"1.6.1",
|
|
182
194
|
"1.6.2",
|
|
183
|
-
"1.6.3"
|
|
195
|
+
"1.6.3",
|
|
196
|
+
"1.7.0",
|
|
197
|
+
"1.7.1",
|
|
198
|
+
"1.7.2",
|
|
199
|
+
"1.7.3",
|
|
200
|
+
"1.7.4"
|
|
201
|
+
|
|
184
202
|
],
|
|
185
203
|
"nextVersion": "1.8.0",
|
|
186
204
|
"supportedNodeVersions": ">=16.0.0",
|
package/utils/config-helper.js
CHANGED
|
@@ -12,7 +12,6 @@ const {loadTranslations} = require('./i18n-helper');
|
|
|
12
12
|
const settingsManager = require('../settings/settings-manager');
|
|
13
13
|
|
|
14
14
|
const { ask } = require('./cli');
|
|
15
|
-
const { spawnSync } = require('child_process');
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* Get unified configuration for any script
|
|
@@ -310,24 +309,22 @@ async function ensureInitialized(cfg) {
|
|
|
310
309
|
}
|
|
311
310
|
|
|
312
311
|
const nonInteractive = !process.stdin.isTTY;
|
|
313
|
-
const initScript = path.join(__dirname, '..', 'main', 'i18ntk-init.js');
|
|
314
312
|
|
|
315
313
|
if (nonInteractive) {
|
|
316
314
|
console.warn(`Missing source language files in ${langDir}. Running initialization...`);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
return result.status === 0;
|
|
315
|
+
await initializeSourceFiles(sourceDir, sourceLanguage);
|
|
316
|
+
|
|
317
|
+
// Mark initialization as complete
|
|
318
|
+
const initDir = path.dirname(configPath);
|
|
319
|
+
ensureDirectory(initDir);
|
|
320
|
+
fs.writeFileSync(configPath, JSON.stringify({
|
|
321
|
+
initialized: true,
|
|
322
|
+
version: '1.7.5',
|
|
323
|
+
timestamp: new Date().toISOString(),
|
|
324
|
+
sourceDir: sourceDir,
|
|
325
|
+
sourceLanguage: sourceLanguage
|
|
326
|
+
}, null, 2));
|
|
327
|
+
return true;
|
|
331
328
|
}
|
|
332
329
|
|
|
333
330
|
const answer = await ask(`Source language files not found in ${langDir}. Run initialization now? (y/N) `);
|
|
@@ -335,20 +332,19 @@ async function ensureInitialized(cfg) {
|
|
|
335
332
|
closeGlobalReadline();
|
|
336
333
|
|
|
337
334
|
if (answer.trim().toLowerCase().startsWith('y')) {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
return result.status === 0;
|
|
335
|
+
await initializeSourceFiles(sourceDir, sourceLanguage);
|
|
336
|
+
|
|
337
|
+
// Mark initialization as complete
|
|
338
|
+
const initDir = path.dirname(configPath);
|
|
339
|
+
ensureDirectory(initDir);
|
|
340
|
+
fs.writeFileSync(configPath, JSON.stringify({
|
|
341
|
+
initialized: true,
|
|
342
|
+
version: '1.7.2',
|
|
343
|
+
timestamp: new Date().toISOString(),
|
|
344
|
+
sourceDir: sourceDir,
|
|
345
|
+
sourceLanguage: sourceLanguage
|
|
346
|
+
}, null, 2));
|
|
347
|
+
return true;
|
|
352
348
|
}
|
|
353
349
|
return false;
|
|
354
350
|
} catch (err) {
|
|
@@ -357,6 +353,77 @@ async function ensureInitialized(cfg) {
|
|
|
357
353
|
}
|
|
358
354
|
}
|
|
359
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Initialize source language files directly (safe alternative to spawnSync)
|
|
358
|
+
*/
|
|
359
|
+
async function initializeSourceFiles(sourceDir, sourceLang) {
|
|
360
|
+
const sourceFile = path.join(sourceDir, `${sourceLang}.json`);
|
|
361
|
+
|
|
362
|
+
// Create default source language file with basic structure
|
|
363
|
+
const defaultContent = {
|
|
364
|
+
app: {
|
|
365
|
+
title: "Application",
|
|
366
|
+
description: "Application description"
|
|
367
|
+
},
|
|
368
|
+
common: {
|
|
369
|
+
yes: "Yes",
|
|
370
|
+
no: "No",
|
|
371
|
+
cancel: "Cancel",
|
|
372
|
+
save: "Save"
|
|
373
|
+
},
|
|
374
|
+
navigation: {
|
|
375
|
+
home: "Home",
|
|
376
|
+
about: "About",
|
|
377
|
+
contact: "Contact"
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// Ensure source directory exists
|
|
382
|
+
ensureDirectory(sourceDir);
|
|
383
|
+
|
|
384
|
+
// Write the default source language file
|
|
385
|
+
fs.writeFileSync(sourceFile, JSON.stringify(defaultContent, null, 2));
|
|
386
|
+
|
|
387
|
+
// Create directories for supported languages
|
|
388
|
+
const supportedLanguages = ['es', 'fr', 'de', 'ja', 'ru', 'zh', 'pt'];
|
|
389
|
+
|
|
390
|
+
supportedLanguages.forEach(lang => {
|
|
391
|
+
const langFile = path.join(sourceDir, `${lang}.json`);
|
|
392
|
+
if (!fs.existsSync(langFile)) {
|
|
393
|
+
// Create empty object structure for each language
|
|
394
|
+
const emptyStructure = {
|
|
395
|
+
app: {},
|
|
396
|
+
common: {},
|
|
397
|
+
navigation: {}
|
|
398
|
+
};
|
|
399
|
+
fs.writeFileSync(langFile, JSON.stringify(emptyStructure, null, 2));
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// Create i18ntk-config.json if it doesn't exist
|
|
404
|
+
const configFile = 'i18ntk-config.json';
|
|
405
|
+
if (!fs.existsSync(configFile)) {
|
|
406
|
+
const defaultConfig = {
|
|
407
|
+
version: "1.7.2",
|
|
408
|
+
sourceDir: sourceDir,
|
|
409
|
+
outputDir: "./i18ntk-reports",
|
|
410
|
+
defaultLanguage: sourceLang,
|
|
411
|
+
supportedLanguages: [sourceLang, 'es', 'fr', 'de', 'ja', 'ru', 'zh', 'pt'],
|
|
412
|
+
security: {
|
|
413
|
+
adminPinEnabled: true,
|
|
414
|
+
sessionTimeout: 1800000,
|
|
415
|
+
maxFailedAttempts: 3
|
|
416
|
+
},
|
|
417
|
+
performance: {
|
|
418
|
+
mode: "extreme",
|
|
419
|
+
cacheEnabled: true,
|
|
420
|
+
batchSize: 1000
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
fs.writeFileSync(configFile, JSON.stringify(defaultConfig, null, 2));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
360
427
|
|
|
361
428
|
module.exports = {
|
|
362
429
|
getUnifiedConfig,
|
package/utils/security-check.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
|
-
const
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
11
12
|
|
|
12
13
|
class SecurityChecker {
|
|
13
14
|
constructor() {
|
|
@@ -128,30 +129,58 @@ class SecurityChecker {
|
|
|
128
129
|
*/
|
|
129
130
|
checkDependencies() {
|
|
130
131
|
try {
|
|
131
|
-
|
|
132
|
-
const
|
|
132
|
+
// Check if package-lock.json exists and analyze dependencies safely
|
|
133
|
+
const packageLockPath = 'package-lock.json';
|
|
134
|
+
const packagePath = 'package.json';
|
|
135
|
+
|
|
136
|
+
let hasVulnerabilities = false;
|
|
137
|
+
let criticalCount = 0;
|
|
138
|
+
let highCount = 0;
|
|
139
|
+
let moderateCount = 0;
|
|
133
140
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
if (fs.existsSync(packageLockPath)) {
|
|
142
|
+
try {
|
|
143
|
+
const packageLock = JSON.parse(fs.readFileSync(packageLockPath, 'utf8'));
|
|
144
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
145
|
+
|
|
146
|
+
// Check for outdated dependencies by comparing versions
|
|
147
|
+
const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
148
|
+
|
|
149
|
+
// Simple heuristic: check if any dependencies are significantly outdated
|
|
150
|
+
// This is a safe alternative to npm audit
|
|
151
|
+
const outdatedPackages = this.checkOutdatedPackages(dependencies, packageLock);
|
|
152
|
+
|
|
153
|
+
// Set conservative counts based on outdated packages
|
|
154
|
+
criticalCount = outdatedPackages.filter(p => p.severity === 'critical').length;
|
|
155
|
+
highCount = outdatedPackages.filter(p => p.severity === 'high').length;
|
|
156
|
+
moderateCount = outdatedPackages.filter(p => p.severity === 'moderate').length;
|
|
157
|
+
|
|
158
|
+
} catch (parseError) {
|
|
159
|
+
// Handle JSON parsing errors
|
|
160
|
+
hasVulnerabilities = true;
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
// No package-lock.json, suggest running npm install
|
|
164
|
+
hasVulnerabilities = true;
|
|
165
|
+
}
|
|
137
166
|
|
|
138
167
|
let status = 'PASS';
|
|
139
|
-
if (
|
|
140
|
-
else if (
|
|
141
|
-
else if (
|
|
168
|
+
if (criticalCount > 0) status = 'FAIL';
|
|
169
|
+
else if (highCount > 0) status = 'WARN';
|
|
170
|
+
else if (moderateCount > 5) status = 'WARN';
|
|
142
171
|
|
|
143
172
|
this.checks.push({
|
|
144
173
|
name: 'Dependency Vulnerabilities',
|
|
145
174
|
status: status,
|
|
146
|
-
message: `Critical: ${
|
|
147
|
-
details: { critical, high, moderate }
|
|
175
|
+
message: `Critical: ${criticalCount}, High: ${highCount}, Moderate: ${moderateCount}`,
|
|
176
|
+
details: { critical: criticalCount, high: highCount, moderate: moderateCount }
|
|
148
177
|
});
|
|
149
178
|
|
|
150
179
|
} catch (error) {
|
|
151
180
|
this.checks.push({
|
|
152
181
|
name: 'Dependency Vulnerabilities',
|
|
153
182
|
status: 'WARN',
|
|
154
|
-
message: 'Unable to run npm audit
|
|
183
|
+
message: 'Unable to analyze dependencies - run npm audit manually'
|
|
155
184
|
});
|
|
156
185
|
}
|
|
157
186
|
}
|
|
@@ -238,13 +267,95 @@ class SecurityChecker {
|
|
|
238
267
|
*/
|
|
239
268
|
findFiles(pattern) {
|
|
240
269
|
try {
|
|
241
|
-
|
|
242
|
-
return files.trim().split('\n').filter(f => f && !f.includes('node_modules'));
|
|
270
|
+
return this.findFilesRecursively('.', pattern);
|
|
243
271
|
} catch (error) {
|
|
244
272
|
return [];
|
|
245
273
|
}
|
|
246
274
|
}
|
|
247
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Recursively find files matching pattern (safe alternative to find command)
|
|
278
|
+
*/
|
|
279
|
+
findFilesRecursively(dir, pattern) {
|
|
280
|
+
const results = [];
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
284
|
+
|
|
285
|
+
items.forEach(item => {
|
|
286
|
+
const fullPath = path.join(dir, item.name);
|
|
287
|
+
|
|
288
|
+
if (item.isDirectory()) {
|
|
289
|
+
// Skip node_modules and hidden directories
|
|
290
|
+
if (item.name !== 'node_modules' && !item.name.startsWith('.')) {
|
|
291
|
+
results.push(...this.findFilesRecursively(fullPath, pattern));
|
|
292
|
+
}
|
|
293
|
+
} else if (item.isFile()) {
|
|
294
|
+
// Simple pattern matching
|
|
295
|
+
const regex = new RegExp(pattern.replace(/\*/g, '.*').replace(/\?/g, '.'));
|
|
296
|
+
if (regex.test(item.name)) {
|
|
297
|
+
results.push(fullPath);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
} catch (error) {
|
|
302
|
+
// Ignore permission errors
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return results;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Check for outdated packages (safe alternative to npm audit)
|
|
310
|
+
*/
|
|
311
|
+
checkOutdatedPackages(dependencies, packageLock) {
|
|
312
|
+
const outdated = [];
|
|
313
|
+
|
|
314
|
+
if (!packageLock.packages) return outdated;
|
|
315
|
+
|
|
316
|
+
Object.keys(dependencies || {}).forEach(depName => {
|
|
317
|
+
const requiredVersion = dependencies[depName];
|
|
318
|
+
const installed = packageLock.packages[`node_modules/${depName}`];
|
|
319
|
+
|
|
320
|
+
if (installed && installed.version) {
|
|
321
|
+
// Simple heuristic: if version doesn't match exactly, flag as outdated
|
|
322
|
+
if (!this.versionMatches(requiredVersion, installed.version)) {
|
|
323
|
+
outdated.push({
|
|
324
|
+
name: depName,
|
|
325
|
+
required: requiredVersion,
|
|
326
|
+
installed: installed.version,
|
|
327
|
+
severity: this.determineSeverity(depName, installed.version)
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
return outdated;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Check if version matches requirement (simplified)
|
|
338
|
+
*/
|
|
339
|
+
versionMatches(required, installed) {
|
|
340
|
+
// Simplified version check - exact match for now
|
|
341
|
+
return installed.startsWith(required.replace(/[^\d.]/g, ''));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Determine severity based on package name (heuristic)
|
|
346
|
+
*/
|
|
347
|
+
determineSeverity(packageName, version) {
|
|
348
|
+
// High-risk packages that should be updated
|
|
349
|
+
const highRisk = ['lodash', 'moment', 'request', 'axios', 'express', 'react'];
|
|
350
|
+
if (highRisk.includes(packageName)) return 'high';
|
|
351
|
+
|
|
352
|
+
// Critical packages with known vulnerabilities
|
|
353
|
+
const criticalRisk = ['lodash', 'moment', 'handlebars', 'validator'];
|
|
354
|
+
if (criticalRisk.includes(packageName) && version.startsWith('1.')) return 'critical';
|
|
355
|
+
|
|
356
|
+
return 'moderate';
|
|
357
|
+
}
|
|
358
|
+
|
|
248
359
|
/**
|
|
249
360
|
* Generate security report
|
|
250
361
|
*/
|