natureco-cli 5.42.0 → 5.43.1
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/CHANGELOG.md +22 -0
- package/README.md +578 -609
- package/SECURITY_AUDIT_SUMMARY.md +40 -0
- package/package.json +2 -1
- package/src/commands/admin-rpc.js +84 -10
- package/src/commands/gateway-server.js +47 -5
- package/src/tools/cron_create.js +36 -34
- package/src/tools/document_extract.js +4 -2
- package/src/tools/phone_control_enhanced.js +13 -3
- package/src/tools/shell_command.js +19 -0
- package/src/tools/skills_autoload.js +7 -1
- package/src/tools/skills_download.js +51 -6
- package/src/tools/social_open.js +2 -2
- package/src/tools/youtube_ac.js +2 -2
- package/src/utils/approvals.js +15 -4
- package/src/utils/config.js +17 -4
- package/src/utils/tool-runner.js +3 -1
package/src/tools/social_open.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { spawn,
|
|
1
|
+
const { spawn, execFileSync } = require("child_process");
|
|
2
2
|
const os = require("os");
|
|
3
3
|
|
|
4
4
|
const IS_MAC = os.platform() === "darwin";
|
|
@@ -63,7 +63,7 @@ function getOpenBrowser() {
|
|
|
63
63
|
];
|
|
64
64
|
for (const browser of browsers) {
|
|
65
65
|
try {
|
|
66
|
-
const result =
|
|
66
|
+
const result = execFileSync("pgrep", ["-x", browser.name], { encoding: "utf8" }); // v5.43: shell yok
|
|
67
67
|
if (result.trim()) return browser.cmd;
|
|
68
68
|
} catch (e) {}
|
|
69
69
|
}
|
package/src/tools/youtube_ac.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* youtube_ac - YouTube videosunu mevcut tarayıcıda yeni sekmede açar
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const { spawn,
|
|
5
|
+
const { spawn, execFileSync } = require("child_process");
|
|
6
6
|
const os = require("os");
|
|
7
7
|
|
|
8
8
|
const IS_MAC = os.platform() === "darwin";
|
|
@@ -16,7 +16,7 @@ function getOpenBrowser() {
|
|
|
16
16
|
|
|
17
17
|
for (const browser of browsers) {
|
|
18
18
|
try {
|
|
19
|
-
const result =
|
|
19
|
+
const result = execFileSync("pgrep", ["-x", browser.name], { encoding: "utf8" }); // v5.43: shell yok
|
|
20
20
|
if (result.trim()) {
|
|
21
21
|
return browser.cmd;
|
|
22
22
|
}
|
package/src/utils/approvals.js
CHANGED
|
@@ -118,16 +118,27 @@ function requiresApproval({ command, agentId, security, ask }) {
|
|
|
118
118
|
return { required: true, reason: 'unknown' };
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
// Built-in safe commands that never need approval
|
|
121
|
+
// Built-in safe commands that never need approval.
|
|
122
|
+
// v5.43 GÜVENLİK: 'node -e' KALDIRILDI — inline eval (`node -e "require('fs').rmSync..."`)
|
|
123
|
+
// keyfi kod çalıştırır, asla "safe" olamaz. Sadece salt-okunur/versiyon komutları kalır.
|
|
122
124
|
const SAFE_COMMANDS = new Set([
|
|
123
125
|
'ls', 'cat', 'head', 'tail', 'echo', 'pwd', 'date', 'whoami',
|
|
124
|
-
'node -
|
|
126
|
+
'node -v', 'npm -v', 'git status', 'git diff', 'git log',
|
|
125
127
|
]);
|
|
126
128
|
|
|
129
|
+
// Shell metakarakterleri: komut zincirleme / substitution / yönlendirme.
|
|
130
|
+
// Bunlardan biri varsa komut ASLA "safe" sayılmaz (ör. "echo hi; rm -rf ~").
|
|
131
|
+
const SHELL_METACHARS = /[;&|`$(){}<>\n\r]|\|\||&&/;
|
|
132
|
+
|
|
127
133
|
function isSafeCommand(command) {
|
|
128
|
-
|
|
134
|
+
const trimmed = (command || '').trim();
|
|
135
|
+
if (!trimmed) return false;
|
|
136
|
+
// v5.43 GÜVENLİK: metakarakter içeren hiçbir komut safe değil — prefix bypass'ı kapatır.
|
|
137
|
+
if (SHELL_METACHARS.test(trimmed)) return false;
|
|
138
|
+
if (SAFE_COMMANDS.has(trimmed)) return true;
|
|
139
|
+
// Prefix eşleşmesi ama SADECE kelime sınırında: "echo" → "echo hi" evet, "echoevil" hayır.
|
|
129
140
|
for (const safe of SAFE_COMMANDS) {
|
|
130
|
-
if (
|
|
141
|
+
if (trimmed === safe || trimmed.startsWith(safe + ' ')) return true;
|
|
131
142
|
}
|
|
132
143
|
return false;
|
|
133
144
|
}
|
package/src/utils/config.js
CHANGED
|
@@ -34,9 +34,13 @@ function getProfileDir() {
|
|
|
34
34
|
const ACTIVE_CONFIG_DIR = getProfileDir();
|
|
35
35
|
const ACTIVE_CONFIG_FILE = path.join(ACTIVE_CONFIG_DIR, 'config.json');
|
|
36
36
|
|
|
37
|
+
// v5.43 GÜVENLİK: config.json API anahtarları tutar; dizin/dosya dünya-okunabilir
|
|
38
|
+
// (0755/0644) olmamalı — ssh anahtarları gibi 0700/0600. chmod fallback eski kurulumlar için.
|
|
37
39
|
function ensureConfigDir() {
|
|
38
40
|
if (!fs.existsSync(ACTIVE_CONFIG_DIR)) {
|
|
39
|
-
fs.mkdirSync(ACTIVE_CONFIG_DIR, { recursive: true });
|
|
41
|
+
fs.mkdirSync(ACTIVE_CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
42
|
+
} else {
|
|
43
|
+
try { fs.chmodSync(ACTIVE_CONFIG_DIR, 0o700); } catch { /* best-effort */ }
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
46
|
|
|
@@ -48,11 +52,15 @@ function createBackup() {
|
|
|
48
52
|
if (!fs.existsSync(ACTIVE_CONFIG_FILE)) return;
|
|
49
53
|
ensureConfigDir();
|
|
50
54
|
if (!fs.existsSync(CONFIG_BACKUP_DIR)) {
|
|
51
|
-
fs.mkdirSync(CONFIG_BACKUP_DIR, { recursive: true });
|
|
55
|
+
fs.mkdirSync(CONFIG_BACKUP_DIR, { recursive: true, mode: 0o700 });
|
|
56
|
+
} else {
|
|
57
|
+
try { fs.chmodSync(CONFIG_BACKUP_DIR, 0o700); } catch { /* best-effort */ }
|
|
52
58
|
}
|
|
53
59
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
54
60
|
const backupFile = path.join(CONFIG_BACKUP_DIR, `config-${timestamp}.json`);
|
|
55
61
|
fs.copyFileSync(ACTIVE_CONFIG_FILE, backupFile);
|
|
62
|
+
// Yedek de API anahtarları içerir → 0600.
|
|
63
|
+
try { fs.chmodSync(backupFile, 0o600); } catch { /* best-effort */ }
|
|
56
64
|
const backups = fs.readdirSync(CONFIG_BACKUP_DIR)
|
|
57
65
|
.filter(f => f.startsWith('config-') && f.endsWith('.json'))
|
|
58
66
|
.sort()
|
|
@@ -91,7 +99,9 @@ function saveConfig(data, options = {}) {
|
|
|
91
99
|
if (!skipValidation) validateConfig(data);
|
|
92
100
|
if (!skipBackup) createBackup();
|
|
93
101
|
const content = JSON.stringify(data, null, 2);
|
|
94
|
-
fs.writeFileSync(ACTIVE_CONFIG_FILE, content, 'utf8');
|
|
102
|
+
fs.writeFileSync(ACTIVE_CONFIG_FILE, content, { encoding: 'utf8', mode: 0o600 });
|
|
103
|
+
// mode yalnızca dosya YENİ oluşturulunca uygulanır; mevcut dosya için chmod şart.
|
|
104
|
+
try { fs.chmodSync(ACTIVE_CONFIG_FILE, 0o600); } catch { /* best-effort */ }
|
|
95
105
|
_configCache = data;
|
|
96
106
|
_configHash = computeHash(data);
|
|
97
107
|
}
|
|
@@ -203,7 +213,10 @@ function restoreConfig(backupFile) {
|
|
|
203
213
|
const data = parseConfigContent(content);
|
|
204
214
|
validateConfig(data);
|
|
205
215
|
createBackup();
|
|
206
|
-
|
|
216
|
+
// v5.43.1 GÜVENLİK: saveConfig gibi 0600 — restore, API key'li config.json'ı
|
|
217
|
+
// dünya-okunabilir hale getirmemeli. mode yalnızca yeni dosyaya uygulanır; chmod şart.
|
|
218
|
+
fs.writeFileSync(ACTIVE_CONFIG_FILE, JSON.stringify(data, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
219
|
+
try { fs.chmodSync(ACTIVE_CONFIG_FILE, 0o600); } catch { /* best-effort */ }
|
|
207
220
|
_configCache = data;
|
|
208
221
|
_configHash = computeHash(data);
|
|
209
222
|
return { path: backupPath, timestamp: path.basename(backupPath).replace(/^config-|\.json$/g, '') };
|
package/src/utils/tool-runner.js
CHANGED
|
@@ -99,9 +99,11 @@ async function executeTool(toolName, params, opts = {}) {
|
|
|
99
99
|
|
|
100
100
|
// ── Onay mekanizması (write_file ve tehlikeli bash) ───────────────────────
|
|
101
101
|
if (agentMode) {
|
|
102
|
+
// v5.43 GÜVENLİK: shell_command da bash gibi onay tetikler (aksi halde onay/güvenlik
|
|
103
|
+
// akışını atlayan ikinci bir arbitrary-shell yolu olurdu).
|
|
102
104
|
const needsConfirm =
|
|
103
105
|
toolName === 'write_file' ||
|
|
104
|
-
(toolName === 'bash' && /\b(rm|mv|cp|chmod|chown|dd|mkfs|truncate)\b/.test(safeParams.command || ''));
|
|
106
|
+
((toolName === 'bash' || toolName === 'shell_command') && /\b(rm|mv|cp|chmod|chown|dd|mkfs|truncate)\b/.test(safeParams.command || ''));
|
|
105
107
|
|
|
106
108
|
if (needsConfirm) {
|
|
107
109
|
if (toolName === 'write_file') {
|