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
@@ -39,7 +39,7 @@ class AdminAuth {
39
39
  */
40
40
  async initialize() {
41
41
  try {
42
- if (!fs.existsSync(this.configPath)) {
42
+ if (!SecurityUtils.safeExistsSync(this.configPath)) {
43
43
  // Create default config if it doesn't exist
44
44
  const defaultConfig = {
45
45
  enabled: false,
@@ -82,7 +82,7 @@ class AdminAuth {
82
82
  */
83
83
  async loadConfig() {
84
84
  try {
85
- if (!fs.existsSync(this.configPath)) {
85
+ if (!SecurityUtils.safeExistsSync(this.configPath)) {
86
86
  return null;
87
87
  }
88
88
 
@@ -1,298 +1,298 @@
1
- const i18n = require('./i18n-helper');
2
- const AdminAuth = require('./admin-auth');
3
- const SecurityUtils = require('./security');
4
- const { getGlobalReadline, closeGlobalReadline, askHidden, ask } = require('./cli');
5
-
6
- /**
7
- * CLI Helper for Admin Authentication
8
- */
9
- class AdminCLI {
10
- constructor() {
11
- this.adminAuth = new AdminAuth();
12
- this.rl = null;
13
- }
14
-
15
- /**
16
- * Initialize readline interface
17
- */
18
- initReadline() {
19
- if (!this.rl) {
20
- this.rl = getGlobalReadline();
21
- }
22
- return this.rl;
23
- }
24
-
25
- /**
26
- * Close readline interface
27
- */
28
- closeReadline() {
29
- if (this.rl) {
30
- closeGlobalReadline();
31
- this.rl = null;
32
- }
33
- }
34
-
35
- /**
36
- * Prompt for PIN input (hidden)
37
- */
38
- async promptPin(message = null) {
39
- if (!message) message = i18n.t('adminCli.enterPin');
40
- return askHidden(message);
41
- }
42
-
43
- /**
44
- * Prompt for yes/no confirmation
45
- */
46
- async promptConfirm(message) {
47
- return ask(`${message} (y/N): `).then(answer => answer.toLowerCase().startsWith('y'));
48
- }
49
-
50
- /**
51
- * Setup admin PIN
52
- */
53
- async setupAdminPin() {
54
- try {
55
- console.log(i18n.t('adminCli.setupPinProtectionTitle'));
56
- console.log(i18n.t('adminCli.setupPinProtectionDescription'));
57
-
58
- const confirm = await this.promptConfirm(i18n.t('adminCli.enablePinProtectionPrompt'));
59
- if (!confirm) {
60
- console.log(i18n.t('adminCli.setupCancelled'));
61
- this.closeReadline();
62
- return false;
63
- }
64
-
65
- let pin1, pin2;
66
- do {
67
- pin1 = await this.promptPin(i18n.t('adminCli.enterPinPrompt'));
68
-
69
- if (!/^\d{4,6}$/.test(pin1)) {
70
- console.log(i18n.t('adminCli.pinFormatError'));
71
- continue;
72
- }
73
-
74
- pin2 = await this.promptPin(i18n.t('adminCli.confirmPinPrompt'));
75
-
76
- if (pin1 !== pin2) {
77
- console.log(i18n.t('adminCli.pinMismatchError'));
78
- }
79
- } while (pin1 !== pin2 || !/^\d{4,6}$/.test(pin1));
80
-
81
- await this.adminAuth.initialize();
82
- const success = await this.adminAuth.setupPin(pin1);
83
-
84
- if (success) {
85
- console.log(i18n.t('adminCli.pinProtectionEnabledSuccess'));
86
- console.log(i18n.t('adminCli.pinRecoveryWarning'));
87
- SecurityUtils.logSecurityEvent(
88
- i18n.t('adminCli.adminPinSetupCli'),
89
- 'info',
90
- { message: 'Admin PIN setup completed via CLI' }
91
- );
92
- } else {
93
- console.log(i18n.t('adminCli.setupPinProtectionFailed'));
94
- }
95
-
96
- this.closeReadline();
97
- return success;
98
- } catch (error) {
99
- console.error(i18n.t('adminCli.errorSettingUpPin', { message: error.message }));
100
- this.closeReadline();
101
- return false;
102
- }
103
- }
104
-
105
- /**
106
- * Authenticate admin user
107
- */
108
- async authenticateAdmin(operation = 'administrative operation') {
109
- try {
110
- await this.adminAuth.initialize();
111
-
112
- const authRequired = await this.adminAuth.isAuthRequired();
113
- if (!authRequired) {
114
- return true; // No authentication required
115
- }
116
-
117
- console.log(i18n.t('adminCli.authRequiredForOperation', { operation }));
118
-
119
- let attempts = 0;
120
- const maxAttempts = 3;
121
-
122
- while (attempts < maxAttempts) {
123
- const pin = await this.promptPin();
124
-
125
- if (!/^\d{4,6}$/.test(pin)) {
126
- console.log(i18n.t('adminCli.invalidPinFormat'));
127
- attempts++;
128
- continue;
129
- }
130
-
131
- const isValid = await this.adminAuth.verifyPin(pin);
132
-
133
- if (isValid) {
134
- console.log(i18n.t('adminCli.authenticationSuccess'));
135
- this.closeReadline();
136
- return true;
137
- } else {
138
- attempts++;
139
- const remaining = maxAttempts - attempts;
140
- if (remaining > 0) {
141
- console.log(i18n.t('adminCli.invalidPinAttemptsRemaining', { remaining }));
142
- }
143
- }
144
- }
145
-
146
- console.log(i18n.t('adminCli.authenticationFailedAccessDenied'));
147
- SecurityUtils.logSecurityEvent(
148
- i18n.t('adminCli.adminAuthFailedCli'),
149
- 'warning',
150
- { message: `Admin authentication failed after ${maxAttempts} attempts` }
151
- );
152
- this.closeReadline();
153
- return false;
154
- } catch (error) {
155
- console.error(i18n.t('adminCli.authenticationError', { message: error.message }));
156
- this.closeReadline();
157
- return false;
158
- }
159
- }
160
-
161
- /**
162
- * Disable admin authentication
163
- */
164
- async disableAdminAuth() {
165
- try {
166
- await this.adminAuth.initialize();
167
-
168
- const authRequired = await this.adminAuth.isAuthRequired();
169
- if (!authRequired) {
170
- console.log(i18n.t('adminCli.pinProtectionNotEnabled'));
171
- return true;
172
- }
173
-
174
- console.log(i18n.t('adminCli.disablingPinProtectionTitle'));
175
-
176
- // Require authentication to disable
177
- const authenticated = await this.authenticateAdmin('disable admin protection');
178
- if (!authenticated) {
179
- return false;
180
- }
181
-
182
- const confirm = await this.promptConfirm(i18n.t('adminCli.confirmDisablePinProtection'));
183
- if (!confirm) {
184
- console.log(i18n.t('adminCli.operationCancelled'));
185
- this.closeReadline();
186
- return false;
187
- }
188
-
189
- const success = await this.adminAuth.disableAuth();
190
-
191
- if (success) {
192
- console.log(i18n.t('adminCli.pinProtectionDisabledSuccess'));
193
- SecurityUtils.logSecurityEvent(
194
- i18n.t('adminCli.adminAuthDisabledCli'),
195
- 'info',
196
- { message: 'Admin PIN protection disabled via CLI' }
197
- );
198
- } else {
199
- console.log(i18n.t('adminCli.disablePinProtectionFailed'));
200
- }
201
-
202
- this.closeReadline();
203
- return success;
204
- } catch (error) {
205
- console.error(i18n.t('adminCli.errorDisablingPinProtection', { message: error.message }));
206
- this.closeReadline();
207
- return false;
208
- }
209
- }
210
-
211
- /**
212
- * Show admin status
213
- */
214
- async showAdminStatus() {
215
- try {
216
- await this.adminAuth.initialize();
217
-
218
- const authRequired = await this.adminAuth.isAuthRequired();
219
-
220
- console.log(i18n.t('adminCli.adminProtectionStatusTitle'));
221
- console.log('='.repeat(30));
222
-
223
- if (authRequired) {
224
- console.log(i18n.t('adminCli.statusEnabled'));
225
- console.log(i18n.t('adminCli.protectionDetails'));
226
- console.log(i18n.t('adminCli.lockoutDetails'));
227
- } else {
228
- console.log(i18n.t('adminCli.statusDisabled'));
229
- console.log(i18n.t('adminCli.noAuthRequired'));
230
- console.log(i18n.t('adminCli.unprotectedRisk'));
231
- }
232
-
233
- return authRequired;
234
- } catch (error) {
235
- console.error(i18n.t('adminCli.errorCheckingAdminStatus', { message: error.message }));
236
- return false;
237
- }
238
- }
239
-
240
- /**
241
- * Check if operation requires admin authentication
242
- */
243
- static requiresAdminAuth(operation) {
244
- const adminOperations = [
245
- 'complete',
246
- 'manage',
247
- 'init',
248
- 'bulk-update',
249
- 'delete-language',
250
- 'reset-translations',
251
- 'delete',
252
- 'workflow'
253
- ];
254
-
255
- return adminOperations.includes(operation);
256
- }
257
-
258
- /**
259
- * Static method to check if operation requires auth (alias)
260
- */
261
- static requiresAuth(operation) {
262
- return AdminCLI.requiresAdminAuth(operation);
263
- }
264
-
265
- /**
266
- * Static method to authenticate
267
- */
268
- static async authenticate(operation = 'administrative operation') {
269
- const cli = new AdminCLI();
270
- return await cli.authenticateAdmin(operation);
271
- }
272
-
273
- /**
274
- * Static method to setup admin
275
- */
276
- static async setupAdmin() {
277
- const cli = new AdminCLI();
278
- return await cli.setupAdminPin();
279
- }
280
-
281
- /**
282
- * Static method to disable admin
283
- */
284
- static async disableAdmin() {
285
- const cli = new AdminCLI();
286
- return await cli.disableAdminAuth();
287
- }
288
-
289
- /**
290
- * Static method to show status
291
- */
292
- static async showStatus() {
293
- const cli = new AdminCLI();
294
- return await cli.showAdminStatus();
295
- }
296
- }
297
-
1
+ const i18n = require('./i18n-helper');
2
+ const AdminAuth = require('./admin-auth');
3
+ const SecurityUtils = require('./security');
4
+ const { getGlobalReadline, closeGlobalReadline, askHidden, ask } = require('./cli');
5
+
6
+ /**
7
+ * CLI Helper for Admin Authentication
8
+ */
9
+ class AdminCLI {
10
+ constructor() {
11
+ this.adminAuth = new AdminAuth();
12
+ this.rl = null;
13
+ }
14
+
15
+ /**
16
+ * Initialize readline interface
17
+ */
18
+ initReadline() {
19
+ if (!this.rl) {
20
+ this.rl = getGlobalReadline();
21
+ }
22
+ return this.rl;
23
+ }
24
+
25
+ /**
26
+ * Close readline interface
27
+ */
28
+ closeReadline() {
29
+ if (this.rl) {
30
+ closeGlobalReadline();
31
+ this.rl = null;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Prompt for PIN input (hidden)
37
+ */
38
+ async promptPin(message = null) {
39
+ if (!message) message = i18n.t('adminCli.enterPin');
40
+ return askHidden(message);
41
+ }
42
+
43
+ /**
44
+ * Prompt for yes/no confirmation
45
+ */
46
+ async promptConfirm(message) {
47
+ return ask(`${message} (y/N): `).then(answer => answer.toLowerCase().startsWith('y'));
48
+ }
49
+
50
+ /**
51
+ * Setup admin PIN
52
+ */
53
+ async setupAdminPin() {
54
+ try {
55
+ console.log(i18n.t('adminCli.setupPinProtectionTitle'));
56
+ console.log(i18n.t('adminCli.setupPinProtectionDescription'));
57
+
58
+ const confirm = await this.promptConfirm(i18n.t('adminCli.enablePinProtectionPrompt'));
59
+ if (!confirm) {
60
+ console.log(i18n.t('adminCli.setupCancelled'));
61
+ this.closeReadline();
62
+ return false;
63
+ }
64
+
65
+ let pin1, pin2;
66
+ do {
67
+ pin1 = await this.promptPin(i18n.t('adminCli.enterPinPrompt'));
68
+
69
+ if (!/^\d{4,6}$/.test(pin1)) {
70
+ console.log(i18n.t('adminCli.pinFormatError'));
71
+ continue;
72
+ }
73
+
74
+ pin2 = await this.promptPin(i18n.t('adminCli.confirmPinPrompt'));
75
+
76
+ if (pin1 !== pin2) {
77
+ console.log(i18n.t('adminCli.pinMismatchError'));
78
+ }
79
+ } while (pin1 !== pin2 || !/^\d{4,6}$/.test(pin1));
80
+
81
+ await this.adminAuth.initialize();
82
+ const success = await this.adminAuth.setupPin(pin1);
83
+
84
+ if (success) {
85
+ console.log(i18n.t('adminCli.pinProtectionEnabledSuccess'));
86
+ console.log(i18n.t('adminCli.pinRecoveryWarning'));
87
+ SecurityUtils.logSecurityEvent(
88
+ i18n.t('adminCli.adminPinSetupCli'),
89
+ 'info',
90
+ { message: 'Admin PIN setup completed via CLI' }
91
+ );
92
+ } else {
93
+ console.log(i18n.t('adminCli.setupPinProtectionFailed'));
94
+ }
95
+
96
+ this.closeReadline();
97
+ return success;
98
+ } catch (error) {
99
+ console.error(i18n.t('adminCli.errorSettingUpPin', { message: error.message }));
100
+ this.closeReadline();
101
+ return false;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Authenticate admin user
107
+ */
108
+ async authenticateAdmin(operation = 'administrative operation') {
109
+ try {
110
+ await this.adminAuth.initialize();
111
+
112
+ const authRequired = await this.adminAuth.isAuthRequired();
113
+ if (!authRequired) {
114
+ return true; // No authentication required
115
+ }
116
+
117
+ console.log(i18n.t('adminCli.authRequiredForOperation', { operation }));
118
+
119
+ let attempts = 0;
120
+ const maxAttempts = 3;
121
+
122
+ while (attempts < maxAttempts) {
123
+ const pin = await this.promptPin();
124
+
125
+ if (!/^\d{4,6}$/.test(pin)) {
126
+ console.log(i18n.t('adminCli.invalidPinFormat'));
127
+ attempts++;
128
+ continue;
129
+ }
130
+
131
+ const isValid = await this.adminAuth.verifyPin(pin);
132
+
133
+ if (isValid) {
134
+ console.log(i18n.t('adminCli.authenticationSuccess'));
135
+ this.closeReadline();
136
+ return true;
137
+ } else {
138
+ attempts++;
139
+ const remaining = maxAttempts - attempts;
140
+ if (remaining > 0) {
141
+ console.log(i18n.t('adminCli.invalidPinAttemptsRemaining', { remaining }));
142
+ }
143
+ }
144
+ }
145
+
146
+ console.log(i18n.t('adminCli.authenticationFailedAccessDenied'));
147
+ SecurityUtils.logSecurityEvent(
148
+ i18n.t('adminCli.adminAuthFailedCli'),
149
+ 'warning',
150
+ { message: `Admin authentication failed after ${maxAttempts} attempts` }
151
+ );
152
+ this.closeReadline();
153
+ return false;
154
+ } catch (error) {
155
+ console.error(i18n.t('adminCli.authenticationError', { message: error.message }));
156
+ this.closeReadline();
157
+ return false;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Disable admin authentication
163
+ */
164
+ async disableAdminAuth() {
165
+ try {
166
+ await this.adminAuth.initialize();
167
+
168
+ const authRequired = await this.adminAuth.isAuthRequired();
169
+ if (!authRequired) {
170
+ console.log(i18n.t('adminCli.pinProtectionNotEnabled'));
171
+ return true;
172
+ }
173
+
174
+ console.log(i18n.t('adminCli.disablingPinProtectionTitle'));
175
+
176
+ // Require authentication to disable
177
+ const authenticated = await this.authenticateAdmin('disable admin protection');
178
+ if (!authenticated) {
179
+ return false;
180
+ }
181
+
182
+ const confirm = await this.promptConfirm(i18n.t('adminCli.confirmDisablePinProtection'));
183
+ if (!confirm) {
184
+ console.log(i18n.t('adminCli.operationCancelled'));
185
+ this.closeReadline();
186
+ return false;
187
+ }
188
+
189
+ const success = await this.adminAuth.disableAuth();
190
+
191
+ if (success) {
192
+ console.log(i18n.t('adminCli.pinProtectionDisabledSuccess'));
193
+ SecurityUtils.logSecurityEvent(
194
+ i18n.t('adminCli.adminAuthDisabledCli'),
195
+ 'info',
196
+ { message: 'Admin PIN protection disabled via CLI' }
197
+ );
198
+ } else {
199
+ console.log(i18n.t('adminCli.disablePinProtectionFailed'));
200
+ }
201
+
202
+ this.closeReadline();
203
+ return success;
204
+ } catch (error) {
205
+ console.error(i18n.t('adminCli.errorDisablingPinProtection', { message: error.message }));
206
+ this.closeReadline();
207
+ return false;
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Show admin status
213
+ */
214
+ async showAdminStatus() {
215
+ try {
216
+ await this.adminAuth.initialize();
217
+
218
+ const authRequired = await this.adminAuth.isAuthRequired();
219
+
220
+ console.log(i18n.t('adminCli.adminProtectionStatusTitle'));
221
+ console.log('='.repeat(30));
222
+
223
+ if (authRequired) {
224
+ console.log(i18n.t('adminCli.statusEnabled'));
225
+ console.log(i18n.t('adminCli.protectionDetails'));
226
+ console.log(i18n.t('adminCli.lockoutDetails'));
227
+ } else {
228
+ console.log(i18n.t('adminCli.statusDisabled'));
229
+ console.log(i18n.t('adminCli.noAuthRequired'));
230
+ console.log(i18n.t('adminCli.unprotectedRisk'));
231
+ }
232
+
233
+ return authRequired;
234
+ } catch (error) {
235
+ console.error(i18n.t('adminCli.errorCheckingAdminStatus', { message: error.message }));
236
+ return false;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Check if operation requires admin authentication
242
+ */
243
+ static requiresAdminAuth(operation) {
244
+ const adminOperations = [
245
+ 'complete',
246
+ 'manage',
247
+ 'init',
248
+ 'bulk-update',
249
+ 'delete-language',
250
+ 'reset-translations',
251
+ 'delete',
252
+ 'workflow'
253
+ ];
254
+
255
+ return adminOperations.includes(operation);
256
+ }
257
+
258
+ /**
259
+ * Static method to check if operation requires auth (alias)
260
+ */
261
+ static requiresAuth(operation) {
262
+ return AdminCLI.requiresAdminAuth(operation);
263
+ }
264
+
265
+ /**
266
+ * Static method to authenticate
267
+ */
268
+ static async authenticate(operation = 'administrative operation') {
269
+ const cli = new AdminCLI();
270
+ return await cli.authenticateAdmin(operation);
271
+ }
272
+
273
+ /**
274
+ * Static method to setup admin
275
+ */
276
+ static async setupAdmin() {
277
+ const cli = new AdminCLI();
278
+ return await cli.setupAdminPin();
279
+ }
280
+
281
+ /**
282
+ * Static method to disable admin
283
+ */
284
+ static async disableAdmin() {
285
+ const cli = new AdminCLI();
286
+ return await cli.disableAdminAuth();
287
+ }
288
+
289
+ /**
290
+ * Static method to show status
291
+ */
292
+ static async showStatus() {
293
+ const cli = new AdminCLI();
294
+ return await cli.showAdminStatus();
295
+ }
296
+ }
297
+
298
298
  module.exports = AdminCLI;
@@ -215,11 +215,11 @@ class AdminPinManager {
215
215
 
216
216
  // Ensure settings directory exists
217
217
  const settingsDir = path.dirname(this.pinFile);
218
- if (!fs.existsSync(settingsDir)) {
218
+ if (!SecurityUtils.safeExistsSync(settingsDir)) {
219
219
  fs.mkdirSync(settingsDir, { recursive: true });
220
220
  }
221
221
 
222
- fs.writeFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
222
+ SecurityUtils.safeWriteFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
223
223
 
224
224
  const i18n = getI18n();
225
225
  console.log(i18n.t('adminPin.setup_success'));
@@ -254,7 +254,7 @@ class AdminPinManager {
254
254
  * Check if PIN is set
255
255
  */
256
256
  isPinSet() {
257
- return fs.existsSync(this.pinFile);
257
+ return SecurityUtils.safeExistsSync(this.pinFile);
258
258
  }
259
259
 
260
260
  /**
@@ -373,7 +373,7 @@ class AdminPinManager {
373
373
  const shouldCloseRL = !externalRl && !hadGlobal;
374
374
 
375
375
  try {
376
- const pinData = JSON.parse(fs.readFileSync(this.pinFile, 'utf8'));
376
+ const pinData = JSON.parse(SecurityUtils.safeReadFileSync(this.pinFile, path.dirname(this.pinFile), 'utf8'));
377
377
 
378
378
  if (pinData.locked) {
379
379
  const i18n = getI18n();
@@ -405,7 +405,7 @@ class AdminPinManager {
405
405
  if (this.constantTimeCompare(computedHashHex, pinData.hash)) {
406
406
  // Reset attempts on successful login
407
407
  pinData.attempts = 0;
408
- fs.writeFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
408
+ SecurityUtils.safeWriteFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
409
409
 
410
410
  const i18n = getI18n();
411
411
  console.log(i18n.t('adminPin.access_granted'));
@@ -419,11 +419,11 @@ class AdminPinManager {
419
419
  setTimeout(() => {
420
420
  pinData.locked = false;
421
421
  pinData.attempts = 0;
422
- fs.writeFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
422
+ SecurityUtils.safeWriteFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
423
423
  }, 5 * 60 * 1000); // 5 minutes
424
424
  }
425
425
 
426
- fs.writeFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
426
+ SecurityUtils.safeWriteFileSync(this.pinFile, JSON.stringify(pinData, null, 2));
427
427
 
428
428
  const i18n = getI18n();
429
429
  console.log(i18n.t('adminPin.incorrect_pin', { attempts: 3 - pinData.attempts }));
@@ -492,7 +492,7 @@ class AdminPinManager {
492
492
  }
493
493
 
494
494
  try {
495
- const pinData = JSON.parse(fs.readFileSync(this.pinFile, 'utf8'));
495
+ const pinData = JSON.parse(SecurityUtils.safeReadFileSync(this.pinFile, path.dirname(this.pinFile), 'utf8'));
496
496
  const key = Buffer.from(pinData.key, 'hex');
497
497
  const decryptedPin = this.decryptPin(pinData.encrypted, key);
498
498
 
@@ -510,7 +510,7 @@ class AdminPinManager {
510
510
  * Reset PIN
511
511
  */
512
512
  async resetPin() {
513
- if (fs.existsSync(this.pinFile)) {
513
+ if (SecurityUtils.safeExistsSync(this.pinFile)) {
514
514
  fs.unlinkSync(this.pinFile);
515
515
  }
516
516
  return await this.setupPin();