i18ntk 2.3.8 → 2.5.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.
- package/README.md +10 -6
- package/main/i18ntk-backup-class.js +35 -423
- package/main/manage/commands/BackupCommand.js +62 -62
- package/main/manage/commands/FixerCommand.js +97 -97
- package/main/manage/managers/DebugMenu.js +10 -9
- package/main/manage/services/SetupService.js +444 -462
- package/package.json +61 -32
- package/runtime/index.js +14 -8
- package/utils/admin-auth.js +594 -576
- package/utils/config-manager.js +72 -72
- package/utils/env-manager.js +117 -26
- package/utils/i18n-helper.js +50 -49
- package/utils/json-output.js +13 -12
- package/utils/logger.js +7 -6
- package/utils/npm-version-warning.js +12 -141
- package/utils/prompt-helper.js +44 -41
- package/utils/secure-errors.js +156 -154
- package/utils/security.js +235 -233
- package/utils/setup-enforcer.js +110 -109
- package/utils/terminal-icons.js +164 -163
- package/settings/i18ntk-config.json +0 -283
- package/utils/admin-pin.js +0 -520
- package/utils/arg-parser.js +0 -40
- package/utils/cli-args.js +0 -210
- package/utils/mini-commander.js +0 -179
- package/utils/missing-key-validator.js +0 -858
- package/utils/path-utils.js +0 -33
- package/utils/performance-optimizer.js +0 -246
- package/utils/prompt-new.js +0 -55
- package/utils/promptPin.js +0 -76
- package/utils/safe-json.js +0 -40
- package/utils/secure-backup.js +0 -340
- package/utils/security-check-improved.js +0 -393
- package/utils/security-config.js +0 -239
- package/utils/setup-validator.js +0 -717
- package/utils/ultra-performance-optimizer.js +0 -352
|
@@ -1,147 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
const { compareVersions } = require('./version-utils');
|
|
1
|
+
'use strict';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Update checks were intentionally removed to avoid outbound network access
|
|
5
|
+
* during CLI startup and to reduce scanner noise in restricted environments.
|
|
6
|
+
*
|
|
7
|
+
* We keep the same exported API for backwards compatibility.
|
|
8
|
+
*/
|
|
6
9
|
|
|
7
|
-
function
|
|
8
|
-
return
|
|
10
|
+
async function checkNpmOutdated() {
|
|
11
|
+
return null;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
const requestUrl = `${NPM_REGISTRY_BASE}/${safePackageName}`;
|
|
14
|
-
|
|
15
|
-
return new Promise((resolve) => {
|
|
16
|
-
let settled = false;
|
|
17
|
-
|
|
18
|
-
const finish = (value) => {
|
|
19
|
-
if (!settled) {
|
|
20
|
-
settled = true;
|
|
21
|
-
resolve(value);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const req = https.get(
|
|
26
|
-
requestUrl,
|
|
27
|
-
{
|
|
28
|
-
timeout: timeoutMs,
|
|
29
|
-
headers: {
|
|
30
|
-
Accept: 'application/json',
|
|
31
|
-
'User-Agent': 'i18ntk-version-check'
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
(res) => {
|
|
35
|
-
if (res.statusCode !== 200) {
|
|
36
|
-
res.resume();
|
|
37
|
-
finish(null);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let raw = '';
|
|
42
|
-
res.on('data', (chunk) => {
|
|
43
|
-
raw += chunk;
|
|
44
|
-
});
|
|
45
|
-
res.on('end', () => {
|
|
46
|
-
try {
|
|
47
|
-
finish(JSON.parse(raw));
|
|
48
|
-
} catch {
|
|
49
|
-
finish(null);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
req.on('timeout', () => {
|
|
56
|
-
req.destroy();
|
|
57
|
-
finish(null);
|
|
58
|
-
});
|
|
59
|
-
req.on('error', () => finish(null));
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function getOutdatedStatus(currentVersion, metadata) {
|
|
64
|
-
if (!isSemverLike(currentVersion) || !metadata || !metadata.versions) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const distTags = metadata['dist-tags'] || {};
|
|
69
|
-
const taggedLatest = distTags.latest;
|
|
70
|
-
const allPublishedVersions = Object.keys(metadata.versions).filter(isSemverLike);
|
|
71
|
-
|
|
72
|
-
if (allPublishedVersions.length === 0) {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const latestVersion = isSemverLike(taggedLatest)
|
|
77
|
-
? taggedLatest
|
|
78
|
-
: allPublishedVersions.sort(compareVersions).at(-1);
|
|
79
|
-
|
|
80
|
-
if (!latestVersion || !isSemverLike(latestVersion)) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const currentMeta = metadata.versions[currentVersion] || null;
|
|
85
|
-
const isCurrentDeprecated = Boolean(currentMeta && currentMeta.deprecated);
|
|
86
|
-
const isOutdated = compareVersions(currentVersion, latestVersion) < 0;
|
|
87
|
-
|
|
88
|
-
const newerStableVersions = allPublishedVersions.filter((version) => (
|
|
89
|
-
compareVersions(version, currentVersion) > 0 &&
|
|
90
|
-
compareVersions(version, latestVersion) <= 0
|
|
91
|
-
));
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
latestVersion,
|
|
95
|
-
isOutdated,
|
|
96
|
-
isCurrentDeprecated,
|
|
97
|
-
newerStableCount: newerStableVersions.length
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async function checkNpmOutdated({ packageName, currentVersion, timeoutMs = DEFAULT_TIMEOUT_MS }) {
|
|
102
|
-
const metadata = await fetchPackageMetadata(packageName, timeoutMs);
|
|
103
|
-
return getOutdatedStatus(currentVersion, metadata);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async function printUpgradeWarningIfOutdated({
|
|
107
|
-
packageName,
|
|
108
|
-
currentVersion,
|
|
109
|
-
timeoutMs = DEFAULT_TIMEOUT_MS
|
|
110
|
-
}) {
|
|
111
|
-
const enabled = String(process.env.I18NTK_ENABLE_UPDATE_CHECK || '').toLowerCase();
|
|
112
|
-
if (!(enabled === '1' || enabled === 'true' || enabled === 'yes')) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (process.env.I18NTK_DISABLE_UPDATE_CHECK === 'true') {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const status = await checkNpmOutdated({ packageName, currentVersion, timeoutMs });
|
|
121
|
-
if (!status) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (status.isCurrentDeprecated) {
|
|
126
|
-
console.warn(
|
|
127
|
-
`\n⚠️ Installed ${packageName}@${currentVersion} is deprecated on npm. ` +
|
|
128
|
-
`Upgrade to ${packageName}@${status.latestVersion}:\n` +
|
|
129
|
-
` npm install -g ${packageName}@latest`
|
|
130
|
-
);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (status.isOutdated) {
|
|
135
|
-
const suffix = status.newerStableCount === 1 ? '' : 's';
|
|
136
|
-
console.warn(
|
|
137
|
-
`\n⚠️ Update available for ${packageName}: ${currentVersion} -> ${status.latestVersion} ` +
|
|
138
|
-
`(${status.newerStableCount} newer release${suffix}).\n` +
|
|
139
|
-
` Run: npm install -g ${packageName}@latest`
|
|
140
|
-
);
|
|
141
|
-
}
|
|
14
|
+
async function printUpgradeWarningIfOutdated() {
|
|
15
|
+
return;
|
|
142
16
|
}
|
|
143
17
|
|
|
144
|
-
module.exports = {
|
|
145
|
-
checkNpmOutdated,
|
|
146
|
-
printUpgradeWarningIfOutdated
|
|
147
|
-
};
|
|
18
|
+
module.exports = { checkNpmOutdated, printUpgradeWarningIfOutdated };
|
package/utils/prompt-helper.js
CHANGED
|
@@ -1,41 +1,44 @@
|
|
|
1
|
-
const { getGlobalReadline, closeGlobalReadline, ask } = require('./cli');
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
1
|
+
const { getGlobalReadline, closeGlobalReadline, ask } = require('./cli');
|
|
2
|
+
const { envManager } = require('./env-manager');
|
|
3
|
+
|
|
4
|
+
function isInteractive(opts={}) {
|
|
5
|
+
const envSilent = envManager.getBoolean('CI') ||
|
|
6
|
+
envManager.getBoolean('I18NTK_SILENT') ||
|
|
7
|
+
envManager.get('npm_config_loglevel') === 'silent';
|
|
8
|
+
if (opts.noPrompt) return false;
|
|
9
|
+
if (envSilent) return false;
|
|
10
|
+
return process.stdin.isTTY === true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class NoopPrompt {
|
|
14
|
+
question(_q) { return Promise.resolve(''); }
|
|
15
|
+
close() {}
|
|
16
|
+
async pressEnterToContinue() { return; }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class RLPrompt {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.rl = getGlobalReadline();
|
|
22
|
+
this.closed = false;
|
|
23
|
+
}
|
|
24
|
+
question(q) {
|
|
25
|
+
if (this.closed) return Promise.resolve('');
|
|
26
|
+
return new Promise(res => this.rl.question(q, ans => res(ans)));
|
|
27
|
+
}
|
|
28
|
+
close() {
|
|
29
|
+
if (!this.closed) {
|
|
30
|
+
closeGlobalReadline();
|
|
31
|
+
this.closed = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async pressEnterToContinue(msg='\nPress Enter to continue...') {
|
|
35
|
+
if (this.closed) return;
|
|
36
|
+
await ask(msg);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createPrompt(opts={}) {
|
|
41
|
+
return isInteractive(opts) ? new RLPrompt() : new NoopPrompt();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { createPrompt, isInteractive };
|
package/utils/secure-errors.js
CHANGED
|
@@ -1,154 +1,156 @@
|
|
|
1
|
-
// Secure error handling utilities
|
|
2
|
-
const crypto = require('crypto');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
1
|
+
// Secure error handling utilities
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const SecurityUtils = require('./security');
|
|
6
|
+
const { envManager } = require('./env-manager');
|
|
7
|
+
|
|
8
|
+
class SecureError extends Error {
|
|
9
|
+
constructor(message, code = 'SECURE_ERROR', details = {}) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'SecureError';
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.details = details;
|
|
14
|
+
this.timestamp = new Date().toISOString();
|
|
15
|
+
this.errorId = crypto.randomBytes(8).toString('hex');
|
|
16
|
+
|
|
17
|
+
// Capture stack trace, excluding constructor call from it
|
|
18
|
+
Error.captureStackTrace(this, this.constructor);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
toJSON() {
|
|
22
|
+
return {
|
|
23
|
+
error: this.name,
|
|
24
|
+
message: this.message,
|
|
25
|
+
code: this.code,
|
|
26
|
+
errorId: this.errorId,
|
|
27
|
+
timestamp: this.timestamp
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static sanitizeError(error) {
|
|
32
|
+
if (error instanceof SecureError) {
|
|
33
|
+
return error.toJSON();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// For non-SecureError instances, return a sanitized version
|
|
37
|
+
return {
|
|
38
|
+
error: 'InternalError',
|
|
39
|
+
message: 'An internal error occurred',
|
|
40
|
+
code: 'INTERNAL_ERROR',
|
|
41
|
+
errorId: crypto.randomBytes(8).toString('hex'),
|
|
42
|
+
timestamp: new Date().toISOString()
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Common error types
|
|
48
|
+
class ValidationError extends SecureError {
|
|
49
|
+
constructor(message = 'Validation failed', details = {}) {
|
|
50
|
+
super(message, 'VALIDATION_ERROR', details);
|
|
51
|
+
this.name = 'ValidationError';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class SecurityError extends SecureError {
|
|
56
|
+
constructor(message = 'Security violation detected', details = {}) {
|
|
57
|
+
super(message, 'SECURITY_VIOLATION', details);
|
|
58
|
+
this.name = 'SecurityError';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
class EncryptionError extends SecureError {
|
|
63
|
+
constructor(message = 'Encryption/decryption failed', details = {}) {
|
|
64
|
+
super(message, 'ENCRYPTION_ERROR', details);
|
|
65
|
+
this.name = 'EncryptionError';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Secure error handler middleware
|
|
70
|
+
function secureErrorHandler(options = {}) {
|
|
71
|
+
const defaults = {
|
|
72
|
+
logErrors: envManager.get('NODE_ENV') !== 'production',
|
|
73
|
+
logFunction: console.error,
|
|
74
|
+
logFilePath: null,
|
|
75
|
+
sanitizeStack: true
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const config = { ...defaults, ...options };
|
|
79
|
+
|
|
80
|
+
// Ensure log directory exists
|
|
81
|
+
if (config.logFilePath && !SecurityUtils.safeExistsSync(path.dirname(config.logFilePath))) {
|
|
82
|
+
try {
|
|
83
|
+
fs.mkdirSync(path.dirname(config.logFilePath), { recursive: true });
|
|
84
|
+
} catch (e) {
|
|
85
|
+
console.error('Failed to create log directory:', e);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return function(error, req, res, next) {
|
|
90
|
+
// Handle specific error types
|
|
91
|
+
let statusCode = 500;
|
|
92
|
+
let response = {};
|
|
93
|
+
|
|
94
|
+
if (error instanceof ValidationError) {
|
|
95
|
+
statusCode = 400;
|
|
96
|
+
response = error.toJSON();
|
|
97
|
+
} else if (error instanceof SecurityError) {
|
|
98
|
+
statusCode = 403;
|
|
99
|
+
response = error.toJSON();
|
|
100
|
+
} else if (error instanceof EncryptionError) {
|
|
101
|
+
statusCode = 400;
|
|
102
|
+
response = error.toJSON();
|
|
103
|
+
} else {
|
|
104
|
+
// Generic error handling
|
|
105
|
+
response = SecureError.sanitizeError(error);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Log the error if enabled
|
|
109
|
+
if (config.logErrors) {
|
|
110
|
+
const logEntry = {
|
|
111
|
+
timestamp: new Date().toISOString(),
|
|
112
|
+
error: {
|
|
113
|
+
name: error.name,
|
|
114
|
+
message: error.message,
|
|
115
|
+
stack: config.sanitizeStack
|
|
116
|
+
? error.stack.split('\n').slice(0, 3).join('\n') + '\n ...'
|
|
117
|
+
: error.stack,
|
|
118
|
+
...(error.details && { details: error.details }),
|
|
119
|
+
errorId: response.errorId
|
|
120
|
+
},
|
|
121
|
+
request: req ? {
|
|
122
|
+
method: req.method,
|
|
123
|
+
url: req.originalUrl,
|
|
124
|
+
ip: req.ip,
|
|
125
|
+
userAgent: req.get('user-agent')
|
|
126
|
+
} : undefined
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Log to console
|
|
130
|
+
if (typeof config.logFunction === 'function') {
|
|
131
|
+
SecurityUtils.safeWriteFileSync(config.logFilePath, JSON.stringify(logEntry, null, 2));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Log to file if configured
|
|
135
|
+
if (config.logFilePath) {
|
|
136
|
+
SecurityUtils.safeWriteFileSync(
|
|
137
|
+
config.logFilePath,
|
|
138
|
+
JSON.stringify(logEntry) + '\n',
|
|
139
|
+
'utf8'
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Send response
|
|
145
|
+
res.status(statusCode).json(response);
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = {
|
|
150
|
+
SecureError,
|
|
151
|
+
ValidationError,
|
|
152
|
+
SecurityError,
|
|
153
|
+
EncryptionError,
|
|
154
|
+
secureErrorHandler,
|
|
155
|
+
createError: (message, code, details) => new SecureError(message, code, details)
|
|
156
|
+
};
|