@solongate/proxy 0.6.2 → 0.6.4
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/dist/index.js +19 -15
- package/dist/init.js +19 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -985,17 +985,13 @@ function matchGlob(str, pattern) {
|
|
|
985
985
|
|
|
986
986
|
// \u2500\u2500 Path Glob (supports **) \u2500\u2500
|
|
987
987
|
function matchPathGlob(path, pattern) {
|
|
988
|
-
const p = path.replace(
|
|
989
|
-
const g = pattern.replace(
|
|
988
|
+
const p = path.replace(/\\\\/g, '/').toLowerCase();
|
|
989
|
+
const g = pattern.replace(/\\\\/g, '/').toLowerCase();
|
|
990
990
|
if (p === g) return true;
|
|
991
991
|
if (g.includes('**')) {
|
|
992
|
-
const parts = g.split('**');
|
|
993
|
-
if (parts.length ===
|
|
994
|
-
|
|
995
|
-
const matchPre = !pre || p.startsWith(pre) || p.includes(pre);
|
|
996
|
-
const matchSuf = !suf || p.endsWith(suf) || p.includes(suf.slice(1));
|
|
997
|
-
return matchPre && matchSuf;
|
|
998
|
-
}
|
|
992
|
+
const parts = g.split('**').filter(s => s.length > 0);
|
|
993
|
+
if (parts.length === 0) return true; // just ** or ****
|
|
994
|
+
return parts.every(segment => p.includes(segment));
|
|
999
995
|
}
|
|
1000
996
|
return matchGlob(p, g);
|
|
1001
997
|
}
|
|
@@ -1024,14 +1020,14 @@ function extractFilenames(args) {
|
|
|
1024
1020
|
for (const s of scanStrings(args)) {
|
|
1025
1021
|
if (/^https?:\\/\\//i.test(s)) continue;
|
|
1026
1022
|
if (s.includes('/') || s.includes('\\\\')) {
|
|
1027
|
-
const base = s.replace(
|
|
1023
|
+
const base = s.replace(/\\\\/g, '/').split('/').pop();
|
|
1028
1024
|
if (base) names.add(base);
|
|
1029
1025
|
continue;
|
|
1030
1026
|
}
|
|
1031
1027
|
if (s.includes(' ')) {
|
|
1032
1028
|
for (const tok of s.split(/\\s+/)) {
|
|
1033
1029
|
if (tok.includes('/') || tok.includes('\\\\')) {
|
|
1034
|
-
const b = tok.replace(
|
|
1030
|
+
const b = tok.replace(/\\\\/g, '/').split('/').pop();
|
|
1035
1031
|
if (b && looksLikeFilename(b)) names.add(b);
|
|
1036
1032
|
} else if (looksLikeFilename(tok)) names.add(tok);
|
|
1037
1033
|
}
|
|
@@ -1060,7 +1056,13 @@ function extractCommands(args) {
|
|
|
1060
1056
|
const fields = ['command', 'cmd', 'function', 'script', 'shell'];
|
|
1061
1057
|
if (typeof args === 'object' && args) {
|
|
1062
1058
|
for (const [k, v] of Object.entries(args)) {
|
|
1063
|
-
if (fields.includes(k.toLowerCase()) && typeof v === 'string')
|
|
1059
|
+
if (fields.includes(k.toLowerCase()) && typeof v === 'string') {
|
|
1060
|
+
// Split chained commands: cd /path && npm install \u2192 [cd /path, npm install]
|
|
1061
|
+
for (const part of v.split(/\\s*(?:&&|\\|\\||;|\\|)\\s*/)) {
|
|
1062
|
+
const trimmed = part.trim();
|
|
1063
|
+
if (trimmed) cmds.push(trimmed);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1064
1066
|
}
|
|
1065
1067
|
}
|
|
1066
1068
|
return cmds;
|
|
@@ -1132,7 +1134,7 @@ process.stdin.on('end', async () => {
|
|
|
1132
1134
|
const args = data.tool_input || {};
|
|
1133
1135
|
|
|
1134
1136
|
// \u2500\u2500 Self-protection: block access to hook files and settings \u2500\u2500
|
|
1135
|
-
const allStrings = scanStrings(args).map(s => s.replace(
|
|
1137
|
+
const allStrings = scanStrings(args).map(s => s.replace(/\\\\/g, '/').toLowerCase());
|
|
1136
1138
|
const protectedPaths = ['.solongate', '.claude/settings.json', '.cursor/settings.json', 'policy.json'];
|
|
1137
1139
|
for (const s of allStrings) {
|
|
1138
1140
|
for (const p of protectedPaths) {
|
|
@@ -1144,10 +1146,12 @@ process.stdin.on('end', async () => {
|
|
|
1144
1146
|
}
|
|
1145
1147
|
}
|
|
1146
1148
|
|
|
1147
|
-
// Load policy
|
|
1149
|
+
// Load policy (use cwd from hook data if available)
|
|
1150
|
+
const hookCwd = data.cwd || process.cwd();
|
|
1148
1151
|
let policy;
|
|
1149
1152
|
try {
|
|
1150
|
-
|
|
1153
|
+
const policyPath = resolve(hookCwd, 'policy.json');
|
|
1154
|
+
policy = JSON.parse(readFileSync(policyPath, 'utf-8'));
|
|
1151
1155
|
} catch {
|
|
1152
1156
|
process.exit(0); // No policy = allow all
|
|
1153
1157
|
}
|
package/dist/init.js
CHANGED
|
@@ -174,17 +174,13 @@ function matchGlob(str, pattern) {
|
|
|
174
174
|
|
|
175
175
|
// \u2500\u2500 Path Glob (supports **) \u2500\u2500
|
|
176
176
|
function matchPathGlob(path, pattern) {
|
|
177
|
-
const p = path.replace(
|
|
178
|
-
const g = pattern.replace(
|
|
177
|
+
const p = path.replace(/\\\\/g, '/').toLowerCase();
|
|
178
|
+
const g = pattern.replace(/\\\\/g, '/').toLowerCase();
|
|
179
179
|
if (p === g) return true;
|
|
180
180
|
if (g.includes('**')) {
|
|
181
|
-
const parts = g.split('**');
|
|
182
|
-
if (parts.length ===
|
|
183
|
-
|
|
184
|
-
const matchPre = !pre || p.startsWith(pre) || p.includes(pre);
|
|
185
|
-
const matchSuf = !suf || p.endsWith(suf) || p.includes(suf.slice(1));
|
|
186
|
-
return matchPre && matchSuf;
|
|
187
|
-
}
|
|
181
|
+
const parts = g.split('**').filter(s => s.length > 0);
|
|
182
|
+
if (parts.length === 0) return true; // just ** or ****
|
|
183
|
+
return parts.every(segment => p.includes(segment));
|
|
188
184
|
}
|
|
189
185
|
return matchGlob(p, g);
|
|
190
186
|
}
|
|
@@ -213,14 +209,14 @@ function extractFilenames(args) {
|
|
|
213
209
|
for (const s of scanStrings(args)) {
|
|
214
210
|
if (/^https?:\\/\\//i.test(s)) continue;
|
|
215
211
|
if (s.includes('/') || s.includes('\\\\')) {
|
|
216
|
-
const base = s.replace(
|
|
212
|
+
const base = s.replace(/\\\\/g, '/').split('/').pop();
|
|
217
213
|
if (base) names.add(base);
|
|
218
214
|
continue;
|
|
219
215
|
}
|
|
220
216
|
if (s.includes(' ')) {
|
|
221
217
|
for (const tok of s.split(/\\s+/)) {
|
|
222
218
|
if (tok.includes('/') || tok.includes('\\\\')) {
|
|
223
|
-
const b = tok.replace(
|
|
219
|
+
const b = tok.replace(/\\\\/g, '/').split('/').pop();
|
|
224
220
|
if (b && looksLikeFilename(b)) names.add(b);
|
|
225
221
|
} else if (looksLikeFilename(tok)) names.add(tok);
|
|
226
222
|
}
|
|
@@ -249,7 +245,13 @@ function extractCommands(args) {
|
|
|
249
245
|
const fields = ['command', 'cmd', 'function', 'script', 'shell'];
|
|
250
246
|
if (typeof args === 'object' && args) {
|
|
251
247
|
for (const [k, v] of Object.entries(args)) {
|
|
252
|
-
if (fields.includes(k.toLowerCase()) && typeof v === 'string')
|
|
248
|
+
if (fields.includes(k.toLowerCase()) && typeof v === 'string') {
|
|
249
|
+
// Split chained commands: cd /path && npm install \u2192 [cd /path, npm install]
|
|
250
|
+
for (const part of v.split(/\\s*(?:&&|\\|\\||;|\\|)\\s*/)) {
|
|
251
|
+
const trimmed = part.trim();
|
|
252
|
+
if (trimmed) cmds.push(trimmed);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
253
255
|
}
|
|
254
256
|
}
|
|
255
257
|
return cmds;
|
|
@@ -321,7 +323,7 @@ process.stdin.on('end', async () => {
|
|
|
321
323
|
const args = data.tool_input || {};
|
|
322
324
|
|
|
323
325
|
// \u2500\u2500 Self-protection: block access to hook files and settings \u2500\u2500
|
|
324
|
-
const allStrings = scanStrings(args).map(s => s.replace(
|
|
326
|
+
const allStrings = scanStrings(args).map(s => s.replace(/\\\\/g, '/').toLowerCase());
|
|
325
327
|
const protectedPaths = ['.solongate', '.claude/settings.json', '.cursor/settings.json', 'policy.json'];
|
|
326
328
|
for (const s of allStrings) {
|
|
327
329
|
for (const p of protectedPaths) {
|
|
@@ -333,10 +335,12 @@ process.stdin.on('end', async () => {
|
|
|
333
335
|
}
|
|
334
336
|
}
|
|
335
337
|
|
|
336
|
-
// Load policy
|
|
338
|
+
// Load policy (use cwd from hook data if available)
|
|
339
|
+
const hookCwd = data.cwd || process.cwd();
|
|
337
340
|
let policy;
|
|
338
341
|
try {
|
|
339
|
-
|
|
342
|
+
const policyPath = resolve(hookCwd, 'policy.json');
|
|
343
|
+
policy = JSON.parse(readFileSync(policyPath, 'utf-8'));
|
|
340
344
|
} catch {
|
|
341
345
|
process.exit(0); // No policy = allow all
|
|
342
346
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "MCP security proxy — protect any MCP server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|