i18ntk 1.0.0

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 (86) hide show
  1. package/CHANGELOG.md +401 -0
  2. package/LICENSE +21 -0
  3. package/README.md +507 -0
  4. package/dev/README.md +37 -0
  5. package/dev/debug/README.md +30 -0
  6. package/dev/debug/complete-console-translations.js +295 -0
  7. package/dev/debug/console-key-checker.js +408 -0
  8. package/dev/debug/console-translations.js +335 -0
  9. package/dev/debug/debugger.js +408 -0
  10. package/dev/debug/export-missing-keys.js +432 -0
  11. package/dev/debug/final-normalize.js +236 -0
  12. package/dev/debug/find-extra-keys.js +68 -0
  13. package/dev/debug/normalize-locales.js +153 -0
  14. package/dev/debug/refactor-locales.js +240 -0
  15. package/dev/debug/reorder-locales.js +85 -0
  16. package/dev/debug/replace-hardcoded-console.js +378 -0
  17. package/docs/INSTALLATION.md +449 -0
  18. package/docs/README.md +222 -0
  19. package/docs/TODO_ROADMAP.md +279 -0
  20. package/docs/api/API_REFERENCE.md +377 -0
  21. package/docs/api/COMPONENTS.md +492 -0
  22. package/docs/api/CONFIGURATION.md +651 -0
  23. package/docs/api/NPM_PUBLISHING_GUIDE.md +434 -0
  24. package/docs/debug/DEBUG_README.md +30 -0
  25. package/docs/debug/DEBUG_TOOLS.md +494 -0
  26. package/docs/development/AGENTS.md +351 -0
  27. package/docs/development/DEVELOPMENT_RULES.md +165 -0
  28. package/docs/development/DEV_README.md +37 -0
  29. package/docs/release-notes/RELEASE_NOTES_v1.0.0.md +173 -0
  30. package/docs/release-notes/RELEASE_NOTES_v1.6.0.md +141 -0
  31. package/docs/release-notes/RELEASE_NOTES_v1.6.1.md +185 -0
  32. package/docs/release-notes/RELEASE_NOTES_v1.6.3.md +199 -0
  33. package/docs/reports/ANALYSIS_README.md +17 -0
  34. package/docs/reports/CONSOLE_MISMATCH_BUG_REPORT_v1.5.0.md +181 -0
  35. package/docs/reports/SIZING_README.md +18 -0
  36. package/docs/reports/SUMMARY_README.md +18 -0
  37. package/docs/reports/TRANSLATION_BUG_REPORT_v1.5.0.md +129 -0
  38. package/docs/reports/USAGE_README.md +18 -0
  39. package/docs/reports/VALIDATION_README.md +18 -0
  40. package/locales/de/auth.json +3 -0
  41. package/locales/de/common.json +16 -0
  42. package/locales/de/pagination.json +6 -0
  43. package/locales/en/auth.json +3 -0
  44. package/locales/en/common.json +16 -0
  45. package/locales/en/pagination.json +6 -0
  46. package/locales/es/auth.json +3 -0
  47. package/locales/es/common.json +16 -0
  48. package/locales/es/pagination.json +6 -0
  49. package/locales/fr/auth.json +3 -0
  50. package/locales/fr/common.json +16 -0
  51. package/locales/fr/pagination.json +6 -0
  52. package/locales/ru/auth.json +3 -0
  53. package/locales/ru/common.json +16 -0
  54. package/locales/ru/pagination.json +6 -0
  55. package/main/i18ntk-analyze.js +625 -0
  56. package/main/i18ntk-autorun.js +461 -0
  57. package/main/i18ntk-complete.js +494 -0
  58. package/main/i18ntk-init.js +686 -0
  59. package/main/i18ntk-manage.js +848 -0
  60. package/main/i18ntk-sizing.js +557 -0
  61. package/main/i18ntk-summary.js +671 -0
  62. package/main/i18ntk-usage.js +1282 -0
  63. package/main/i18ntk-validate.js +762 -0
  64. package/main/ui-i18n.js +332 -0
  65. package/package.json +152 -0
  66. package/scripts/fix-missing-translation-keys.js +214 -0
  67. package/scripts/verify-package.js +168 -0
  68. package/ui-locales/de.json +637 -0
  69. package/ui-locales/en.json +688 -0
  70. package/ui-locales/es.json +637 -0
  71. package/ui-locales/fr.json +637 -0
  72. package/ui-locales/ja.json +637 -0
  73. package/ui-locales/ru.json +637 -0
  74. package/ui-locales/zh.json +637 -0
  75. package/utils/admin-auth.js +317 -0
  76. package/utils/admin-cli.js +353 -0
  77. package/utils/admin-pin.js +409 -0
  78. package/utils/detect-language-mismatches.js +454 -0
  79. package/utils/i18n-helper.js +128 -0
  80. package/utils/maintain-language-purity.js +433 -0
  81. package/utils/native-translations.js +478 -0
  82. package/utils/security.js +384 -0
  83. package/utils/test-complete-system.js +356 -0
  84. package/utils/test-console-i18n.js +402 -0
  85. package/utils/translate-mismatches.js +571 -0
  86. package/utils/validate-language-purity.js +531 -0
@@ -0,0 +1,317 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const crypto = require('crypto');
4
+ const SecurityUtils = require('./security');
5
+ const SettingsManager = require('../settings/settings-manager');
6
+
7
+ /**
8
+ * Admin Authentication Module
9
+ * Provides secure PIN-based authentication for administrative operations
10
+ */
11
+ class AdminAuth {
12
+ constructor() {
13
+ this.configPath = path.join(process.cwd(), '.i18n-admin-config.json');
14
+ this.settingsManager = SettingsManager;
15
+
16
+ // Get settings from SettingsManager
17
+ const securitySettings = this.settingsManager.getSecurity();
18
+ this.sessionTimeout = (securitySettings.sessionTimeout || 30) * 60 * 1000; // Convert minutes to milliseconds
19
+ this.maxAttempts = securitySettings.maxFailedAttempts || 3;
20
+ this.lockoutDuration = (securitySettings.lockoutDuration || 15) * 60 * 1000; // Convert minutes to milliseconds
21
+ this.keepAuthenticatedUntilExit = securitySettings.keepAuthenticatedUntilExit !== false;
22
+
23
+ this.activeSessions = new Map();
24
+ this.failedAttempts = new Map();
25
+ this.lockouts = new Map();
26
+
27
+ // Clean up expired sessions every 5 minutes
28
+ this.cleanupInterval = setInterval(this.cleanupExpiredSessions.bind(this), 5 * 60 * 1000);
29
+ }
30
+
31
+ /**
32
+ * Initialize admin authentication system
33
+ */
34
+ async initialize() {
35
+ try {
36
+ if (!fs.existsSync(this.configPath)) {
37
+ // Create default config if it doesn't exist
38
+ const defaultConfig = {
39
+ enabled: false,
40
+ pinHash: null,
41
+ salt: null,
42
+ createdAt: new Date().toISOString(),
43
+ lastModified: new Date().toISOString()
44
+ };
45
+ await this.saveConfig(defaultConfig);
46
+ }
47
+
48
+ SecurityUtils.logSecurityEvent('admin_auth_initialized', 'info', 'Admin authentication system initialized');
49
+ return true;
50
+ } catch (error) {
51
+ SecurityUtils.logSecurityEvent('admin_auth_init_error', 'error', `Failed to initialize admin auth: ${error.message}`);
52
+ return false;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Load admin configuration
58
+ */
59
+ async loadConfig() {
60
+ try {
61
+ if (!fs.existsSync(this.configPath)) {
62
+ return null;
63
+ }
64
+
65
+ const content = await fs.promises.readFile(this.configPath, 'utf8');
66
+ return SecurityUtils.safeParseJSON(content);
67
+ } catch (error) {
68
+ SecurityUtils.logSecurityEvent('admin_config_load_error', 'error', `Failed to load admin config: ${error.message}`);
69
+ return null;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Save admin configuration
75
+ */
76
+ async saveConfig(config) {
77
+ try {
78
+ const content = JSON.stringify(config, null, 2);
79
+ await fs.promises.writeFile(this.configPath, content, { mode: 0o600 }); // Restrict permissions
80
+ SecurityUtils.logSecurityEvent('admin_config_saved', 'info', 'Admin configuration saved');
81
+ return true;
82
+ } catch (error) {
83
+ SecurityUtils.logSecurityEvent('admin_config_save_error', 'error', `Failed to save admin config: ${error.message}`);
84
+ return false;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Set up admin PIN
90
+ */
91
+ async setupPin(pin) {
92
+ try {
93
+ // Validate PIN format (4 digits)
94
+ if (!/^\d{4}$/.test(pin)) {
95
+ throw new Error('PIN must be exactly 4 digits');
96
+ }
97
+
98
+ // Generate salt and hash
99
+ const salt = crypto.randomBytes(32).toString('hex');
100
+ const pinHash = this.hashPin(pin, salt);
101
+
102
+ const config = {
103
+ enabled: true,
104
+ pinHash,
105
+ salt,
106
+ createdAt: new Date().toISOString(),
107
+ lastModified: new Date().toISOString()
108
+ };
109
+
110
+ const success = await this.saveConfig(config);
111
+ if (success) {
112
+ SecurityUtils.logSecurityEvent('admin_pin_setup', 'info', 'Admin PIN configured successfully');
113
+ }
114
+ return success;
115
+ } catch (error) {
116
+ SecurityUtils.logSecurityEvent('admin_pin_setup_error', 'error', `Failed to setup PIN: ${error.message}`);
117
+ return false;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Hash PIN with salt
123
+ */
124
+ hashPin(pin, salt) {
125
+ return crypto.pbkdf2Sync(pin, salt, 100000, 64, 'sha512').toString('hex');
126
+ }
127
+
128
+ /**
129
+ * Verify PIN
130
+ */
131
+ async verifyPin(pin) {
132
+ try {
133
+ const config = await this.loadConfig();
134
+ if (!config || !config.enabled) {
135
+ return true; // No authentication required if not enabled
136
+ }
137
+
138
+ // Check for lockout
139
+ const clientId = 'local'; // In a real app, this would be client IP or session ID
140
+ if (this.isLockedOut(clientId)) {
141
+ SecurityUtils.logSecurityEvent('admin_auth_lockout', 'warning', 'Authentication attempt during lockout period');
142
+ return false;
143
+ }
144
+
145
+ // Validate PIN format
146
+ if (!/^\d{4}$/.test(pin)) {
147
+ this.recordFailedAttempt(clientId);
148
+ SecurityUtils.logSecurityEvent('admin_auth_invalid_format', 'warning', 'Invalid PIN format attempted');
149
+ return false;
150
+ }
151
+
152
+ // Verify PIN
153
+ const pinHash = this.hashPin(pin, config.salt);
154
+ const isValid = pinHash === config.pinHash;
155
+
156
+ if (isValid) {
157
+ this.clearFailedAttempts(clientId);
158
+ SecurityUtils.logSecurityEvent('admin_auth_success', 'info', 'Admin authentication successful');
159
+ return true;
160
+ } else {
161
+ this.recordFailedAttempt(clientId);
162
+ SecurityUtils.logSecurityEvent('admin_auth_failure', 'warning', 'Admin authentication failed');
163
+ return false;
164
+ }
165
+ } catch (error) {
166
+ SecurityUtils.logSecurityEvent('admin_auth_error', 'error', `Authentication error: ${error.message}`);
167
+ return false;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Check if authentication is required
173
+ */
174
+ async isAuthRequired() {
175
+ // Check if admin PIN is enabled in settings
176
+ if (!this.settingsManager.isAdminPinEnabled()) {
177
+ return false;
178
+ }
179
+
180
+ const config = await this.loadConfig();
181
+ return config && config.enabled;
182
+ }
183
+
184
+ /**
185
+ * Disable admin authentication
186
+ */
187
+ async disableAuth() {
188
+ try {
189
+ const config = await this.loadConfig();
190
+ if (config) {
191
+ config.enabled = false;
192
+ config.lastModified = new Date().toISOString();
193
+ const success = await this.saveConfig(config);
194
+ if (success) {
195
+ SecurityUtils.logSecurityEvent('admin_auth_disabled', 'info', 'Admin authentication disabled');
196
+ }
197
+ return success;
198
+ }
199
+ return true;
200
+ } catch (error) {
201
+ SecurityUtils.logSecurityEvent('admin_auth_disable_error', 'error', `Failed to disable auth: ${error.message}`);
202
+ return false;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Record failed authentication attempt
208
+ */
209
+ recordFailedAttempt(clientId) {
210
+ const now = Date.now();
211
+ const attempts = this.failedAttempts.get(clientId) || [];
212
+
213
+ // Remove old attempts (older than lockout duration)
214
+ const recentAttempts = attempts.filter(time => now - time < this.lockoutDuration);
215
+ recentAttempts.push(now);
216
+
217
+ this.failedAttempts.set(clientId, recentAttempts);
218
+ }
219
+
220
+ /**
221
+ * Clear failed attempts for client
222
+ */
223
+ clearFailedAttempts(clientId) {
224
+ this.failedAttempts.delete(clientId);
225
+ }
226
+
227
+ /**
228
+ * Check if client is locked out
229
+ */
230
+ isLockedOut(clientId) {
231
+ const attempts = this.failedAttempts.get(clientId) || [];
232
+ const now = Date.now();
233
+
234
+ // Remove old attempts
235
+ const recentAttempts = attempts.filter(time => now - time < this.lockoutDuration);
236
+ this.failedAttempts.set(clientId, recentAttempts);
237
+
238
+ return recentAttempts.length >= this.maxAttempts;
239
+ }
240
+
241
+ /**
242
+ * Create authenticated session
243
+ */
244
+ createSession() {
245
+ const sessionId = crypto.randomBytes(32).toString('hex');
246
+ const expiresAt = Date.now() + this.sessionTimeout;
247
+
248
+ this.activeSessions.set(sessionId, {
249
+ createdAt: Date.now(),
250
+ expiresAt,
251
+ lastActivity: Date.now()
252
+ });
253
+
254
+ SecurityUtils.logSecurityEvent('admin_session_created', 'info', 'Admin session created');
255
+ return sessionId;
256
+ }
257
+
258
+ /**
259
+ * Validate session
260
+ */
261
+ validateSession(sessionId) {
262
+ const session = this.activeSessions.get(sessionId);
263
+ if (!session) {
264
+ return false;
265
+ }
266
+
267
+ const now = Date.now();
268
+ if (now > session.expiresAt) {
269
+ this.activeSessions.delete(sessionId);
270
+ SecurityUtils.logSecurityEvent('admin_session_expired', 'info', 'Admin session expired');
271
+ return false;
272
+ }
273
+
274
+ // Update last activity
275
+ session.lastActivity = now;
276
+ return true;
277
+ }
278
+
279
+ /**
280
+ * Destroy session
281
+ */
282
+ destroySession(sessionId) {
283
+ const deleted = this.activeSessions.delete(sessionId);
284
+ if (deleted) {
285
+ SecurityUtils.logSecurityEvent('admin_session_destroyed', 'info', 'Admin session destroyed');
286
+ }
287
+ return deleted;
288
+ }
289
+
290
+ /**
291
+ * Clean up expired sessions
292
+ */
293
+ cleanupExpiredSessions() {
294
+ const now = Date.now();
295
+ let cleaned = 0;
296
+
297
+ for (const [sessionId, session] of this.activeSessions.entries()) {
298
+ if (now > session.expiresAt) {
299
+ this.activeSessions.delete(sessionId);
300
+ cleaned++;
301
+ }
302
+ }
303
+
304
+ if (cleaned > 0) {
305
+ SecurityUtils.logSecurityEvent('admin_sessions_cleaned', 'info', `Cleaned up ${cleaned} expired sessions`);
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Clean up expired sessions (alias for backward compatibility)
311
+ */
312
+ cleanupSessions() {
313
+ return this.cleanupExpiredSessions();
314
+ }
315
+ }
316
+
317
+ module.exports = AdminAuth;
@@ -0,0 +1,353 @@
1
+ const readline = require('readline');
2
+ const AdminAuth = require('./admin-auth');
3
+ const SecurityUtils = require('./security');
4
+
5
+ /**
6
+ * CLI Helper for Admin Authentication
7
+ */
8
+ class AdminCLI {
9
+ constructor() {
10
+ this.adminAuth = new AdminAuth();
11
+ this.rl = null;
12
+ }
13
+
14
+ /**
15
+ * Initialize readline interface
16
+ */
17
+ initReadline() {
18
+ if (!this.rl) {
19
+ this.rl = readline.createInterface({
20
+ input: process.stdin,
21
+ output: process.stdout,
22
+ terminal: true,
23
+ historySize: 0
24
+ });
25
+ }
26
+ return this.rl;
27
+ }
28
+
29
+ /**
30
+ * Close readline interface
31
+ */
32
+ closeReadline() {
33
+ if (this.rl) {
34
+ this.rl.close();
35
+ this.rl = null;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Prompt for PIN input (hidden)
41
+ */
42
+ async promptPin(message = 'Enter admin PIN: ') {
43
+ return new Promise((resolve) => {
44
+ const rl = this.initReadline();
45
+
46
+ // Check if stdin is a TTY (interactive terminal)
47
+ const stdin = process.stdin;
48
+ const isTTY = stdin.isTTY;
49
+
50
+ if (isTTY) {
51
+ // Hide input for PIN in interactive mode
52
+ stdin.setRawMode(true);
53
+ stdin.resume();
54
+ stdin.setEncoding('utf8');
55
+ }
56
+
57
+ if (isTTY) {
58
+ // Interactive mode with hidden input
59
+ let pin = '';
60
+ process.stdout.write(message);
61
+
62
+ const onData = (char) => {
63
+ switch (char) {
64
+ case '\n':
65
+ case '\r':
66
+ case '\u0004': // Ctrl+D
67
+ stdin.setRawMode(false);
68
+ stdin.pause();
69
+ stdin.removeListener('data', onData);
70
+ process.stdout.write('\n');
71
+ resolve(pin);
72
+ break;
73
+ case '\u0003': // Ctrl+C
74
+ stdin.setRawMode(false);
75
+ stdin.pause();
76
+ stdin.removeListener('data', onData);
77
+ process.stdout.write('\n');
78
+ process.exit(1);
79
+ break;
80
+ case '\u007f': // Backspace
81
+ if (pin.length > 0) {
82
+ pin = pin.slice(0, -1);
83
+ process.stdout.write('\b \b');
84
+ }
85
+ break;
86
+ default:
87
+ if (char >= '0' && char <= '9' && pin.length < 4) {
88
+ pin += char;
89
+ process.stdout.write('*');
90
+ }
91
+ break;
92
+ }
93
+ };
94
+
95
+ stdin.on('data', onData);
96
+ } else {
97
+ // Non-interactive mode (piped input)
98
+ rl.question(message, (answer) => {
99
+ resolve(answer.trim());
100
+ });
101
+ }
102
+ });
103
+ }
104
+
105
+ /**
106
+ * Prompt for yes/no confirmation
107
+ */
108
+ async promptConfirm(message) {
109
+ return new Promise((resolve) => {
110
+ const rl = this.initReadline();
111
+ rl.question(`${message} (y/N): `, (answer) => {
112
+ resolve(answer.toLowerCase().startsWith('y'));
113
+ });
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Setup admin PIN
119
+ */
120
+ async setupAdminPin() {
121
+ try {
122
+ console.log('\nšŸ” Setting up Admin PIN Protection');
123
+ console.log('This will require a 4-digit PIN for administrative operations.');
124
+
125
+ const confirm = await this.promptConfirm('Do you want to enable admin PIN protection?');
126
+ if (!confirm) {
127
+ console.log('Admin PIN protection setup cancelled.');
128
+ this.closeReadline();
129
+ return false;
130
+ }
131
+
132
+ let pin1, pin2;
133
+ do {
134
+ pin1 = await this.promptPin('Enter a 4-digit PIN: ');
135
+
136
+ if (!/^\d{4}$/.test(pin1)) {
137
+ console.log('āŒ PIN must be exactly 4 digits. Please try again.');
138
+ continue;
139
+ }
140
+
141
+ pin2 = await this.promptPin('Confirm PIN: ');
142
+
143
+ if (pin1 !== pin2) {
144
+ console.log('āŒ PINs do not match. Please try again.');
145
+ }
146
+ } while (pin1 !== pin2 || !/^\d{4}$/.test(pin1));
147
+
148
+ await this.adminAuth.initialize();
149
+ const success = await this.adminAuth.setupPin(pin1);
150
+
151
+ if (success) {
152
+ console.log('āœ… Admin PIN protection enabled successfully!');
153
+ console.log('āš ļø Remember your PIN - it cannot be recovered if lost.');
154
+ SecurityUtils.logSecurityEvent('admin_pin_setup_cli', 'info', 'Admin PIN setup completed via CLI');
155
+ } else {
156
+ console.log('āŒ Failed to setup admin PIN protection.');
157
+ }
158
+
159
+ this.closeReadline();
160
+ return success;
161
+ } catch (error) {
162
+ console.error('āŒ Error setting up admin PIN:', error.message);
163
+ this.closeReadline();
164
+ return false;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Authenticate admin user
170
+ */
171
+ async authenticateAdmin(operation = 'administrative operation') {
172
+ try {
173
+ await this.adminAuth.initialize();
174
+
175
+ const authRequired = await this.adminAuth.isAuthRequired();
176
+ if (!authRequired) {
177
+ return true; // No authentication required
178
+ }
179
+
180
+ console.log(`\nšŸ” Admin authentication required for: ${operation}`);
181
+
182
+ let attempts = 0;
183
+ const maxAttempts = 3;
184
+
185
+ while (attempts < maxAttempts) {
186
+ const pin = await this.promptPin('Enter admin PIN: ');
187
+
188
+ if (!/^\d{4}$/.test(pin)) {
189
+ console.log('āŒ Invalid PIN format. PIN must be 4 digits.');
190
+ attempts++;
191
+ continue;
192
+ }
193
+
194
+ const isValid = await this.adminAuth.verifyPin(pin);
195
+
196
+ if (isValid) {
197
+ console.log('āœ… Authentication successful!');
198
+ this.closeReadline();
199
+ return true;
200
+ } else {
201
+ attempts++;
202
+ const remaining = maxAttempts - attempts;
203
+ if (remaining > 0) {
204
+ console.log(`āŒ Invalid PIN. ${remaining} attempts remaining.`);
205
+ }
206
+ }
207
+ }
208
+
209
+ console.log('āŒ Authentication failed. Access denied.');
210
+ SecurityUtils.logSecurityEvent('admin_auth_failed_cli', 'warning', `Admin authentication failed after ${maxAttempts} attempts`);
211
+ this.closeReadline();
212
+ return false;
213
+ } catch (error) {
214
+ console.error('āŒ Authentication error:', error.message);
215
+ this.closeReadline();
216
+ return false;
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Disable admin authentication
222
+ */
223
+ async disableAdminAuth() {
224
+ try {
225
+ await this.adminAuth.initialize();
226
+
227
+ const authRequired = await this.adminAuth.isAuthRequired();
228
+ if (!authRequired) {
229
+ console.log('Admin PIN protection is not currently enabled.');
230
+ return true;
231
+ }
232
+
233
+ console.log('\nšŸ”“ Disabling Admin PIN Protection');
234
+
235
+ // Require authentication to disable
236
+ const authenticated = await this.authenticateAdmin('disable admin protection');
237
+ if (!authenticated) {
238
+ return false;
239
+ }
240
+
241
+ const confirm = await this.promptConfirm('Are you sure you want to disable admin PIN protection?');
242
+ if (!confirm) {
243
+ console.log('Operation cancelled.');
244
+ this.closeReadline();
245
+ return false;
246
+ }
247
+
248
+ const success = await this.adminAuth.disableAuth();
249
+
250
+ if (success) {
251
+ console.log('āœ… Admin PIN protection disabled.');
252
+ SecurityUtils.logSecurityEvent('admin_auth_disabled_cli', 'info', 'Admin PIN protection disabled via CLI');
253
+ } else {
254
+ console.log('āŒ Failed to disable admin PIN protection.');
255
+ }
256
+
257
+ this.closeReadline();
258
+ return success;
259
+ } catch (error) {
260
+ console.error('āŒ Error disabling admin protection:', error.message);
261
+ this.closeReadline();
262
+ return false;
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Show admin status
268
+ */
269
+ async showAdminStatus() {
270
+ try {
271
+ await this.adminAuth.initialize();
272
+
273
+ const authRequired = await this.adminAuth.isAuthRequired();
274
+
275
+ console.log('\nšŸ” Admin Protection Status');
276
+ console.log('=' .repeat(30));
277
+
278
+ if (authRequired) {
279
+ console.log('Status: āœ… ENABLED');
280
+ console.log('Protection: 4-digit PIN required for admin operations');
281
+ console.log('Lockout: 3 failed attempts = 15 minute lockout');
282
+ } else {
283
+ console.log('Status: āŒ DISABLED');
284
+ console.log('Protection: No authentication required');
285
+ console.log('Risk: Administrative operations are unprotected');
286
+ }
287
+
288
+ return authRequired;
289
+ } catch (error) {
290
+ console.error('āŒ Error checking admin status:', error.message);
291
+ return false;
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Check if operation requires admin authentication
297
+ */
298
+ static requiresAdminAuth(operation) {
299
+ const adminOperations = [
300
+ 'complete',
301
+ 'manage',
302
+ 'init',
303
+ 'bulk-update',
304
+ 'delete-language',
305
+ 'reset-translations',
306
+ 'delete',
307
+ 'workflow'
308
+ ];
309
+
310
+ return adminOperations.includes(operation);
311
+ }
312
+
313
+ /**
314
+ * Static method to check if operation requires auth (alias)
315
+ */
316
+ static requiresAuth(operation) {
317
+ return AdminCLI.requiresAdminAuth(operation);
318
+ }
319
+
320
+ /**
321
+ * Static method to authenticate
322
+ */
323
+ static async authenticate(operation = 'administrative operation') {
324
+ const cli = new AdminCLI();
325
+ return await cli.authenticateAdmin(operation);
326
+ }
327
+
328
+ /**
329
+ * Static method to setup admin
330
+ */
331
+ static async setupAdmin() {
332
+ const cli = new AdminCLI();
333
+ return await cli.setupAdminPin();
334
+ }
335
+
336
+ /**
337
+ * Static method to disable admin
338
+ */
339
+ static async disableAdmin() {
340
+ const cli = new AdminCLI();
341
+ return await cli.disableAdminAuth();
342
+ }
343
+
344
+ /**
345
+ * Static method to show status
346
+ */
347
+ static async showStatus() {
348
+ const cli = new AdminCLI();
349
+ return await cli.showAdminStatus();
350
+ }
351
+ }
352
+
353
+ module.exports = AdminCLI;