@pcircle/footprint 1.2.1 → 1.3.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 +13 -25
- package/dist/src/cli/constants.d.ts +20 -0
- package/dist/src/cli/constants.d.ts.map +1 -0
- package/dist/src/cli/constants.js +25 -0
- package/dist/src/cli/constants.js.map +1 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +25 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/setup.d.ts +6 -0
- package/dist/src/cli/setup.d.ts.map +1 -0
- package/dist/src/cli/setup.js +334 -0
- package/dist/src/cli/setup.js.map +1 -0
- package/dist/src/cli/types.d.ts +38 -0
- package/dist/src/cli/types.d.ts.map +1 -0
- package/dist/src/cli/types.js +5 -0
- package/dist/src/cli/types.js.map +1 -0
- package/dist/src/cli/utils/config.d.ts +19 -0
- package/dist/src/cli/utils/config.d.ts.map +1 -0
- package/dist/src/cli/utils/config.js +86 -0
- package/dist/src/cli/utils/config.js.map +1 -0
- package/dist/src/cli/utils/detect.d.ts +14 -0
- package/dist/src/cli/utils/detect.d.ts.map +1 -0
- package/dist/src/cli/utils/detect.js +57 -0
- package/dist/src/cli/utils/detect.js.map +1 -0
- package/dist/src/cli/utils/env.d.ts +10 -0
- package/dist/src/cli/utils/env.d.ts.map +1 -0
- package/dist/src/cli/utils/env.js +54 -0
- package/dist/src/cli/utils/env.js.map +1 -0
- package/dist/src/cli/utils/validation.d.ts +17 -0
- package/dist/src/cli/utils/validation.d.ts.map +1 -0
- package/dist/src/cli/utils/validation.js +77 -0
- package/dist/src/cli/utils/validation.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -3
- package/dist/src/index.js.map +1 -1
- package/package.json +11 -4
- package/dist/tests/error-handling.test.d.ts +0 -2
- package/dist/tests/error-handling.test.d.ts.map +0 -1
- package/dist/tests/error-handling.test.js +0 -114
- package/dist/tests/error-handling.test.js.map +0 -1
- package/dist/tests/fixtures.d.ts +0 -87
- package/dist/tests/fixtures.d.ts.map +0 -1
- package/dist/tests/fixtures.js +0 -130
- package/dist/tests/fixtures.js.map +0 -1
- package/dist/tests/integration.test.d.ts +0 -2
- package/dist/tests/integration.test.d.ts.map +0 -1
- package/dist/tests/integration.test.js +0 -115
- package/dist/tests/integration.test.js.map +0 -1
- package/dist/tests/resources.test.d.ts +0 -2
- package/dist/tests/resources.test.d.ts.map +0 -1
- package/dist/tests/resources.test.js +0 -73
- package/dist/tests/resources.test.js.map +0 -1
- package/dist/tests/setup.d.ts +0 -8
- package/dist/tests/setup.d.ts.map +0 -1
- package/dist/tests/setup.js +0 -8
- package/dist/tests/setup.js.map +0 -1
- package/dist/tests/tools.test.d.ts +0 -2
- package/dist/tests/tools.test.d.ts.map +0 -1
- package/dist/tests/tools.test.js +0 -224
- package/dist/tests/tools.test.js.map +0 -1
- package/dist/ui-tmp/ui/export.html +0 -409
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* global console, NodeJS */
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
/** Secure file permissions: owner read/write only */
|
|
5
|
+
const SECURE_FILE_MODE = 0o600;
|
|
6
|
+
/** Secure directory permissions: owner read/write/execute only */
|
|
7
|
+
const SECURE_DIR_MODE = 0o700;
|
|
8
|
+
/**
|
|
9
|
+
* Safely set file permissions with warning on failure
|
|
10
|
+
*/
|
|
11
|
+
function setSecurePermissions(filePath, showManualHint = false) {
|
|
12
|
+
try {
|
|
13
|
+
fs.chmodSync(filePath, SECURE_FILE_MODE);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
console.warn(`Warning: Could not set secure permissions on ${filePath}: ${message}`);
|
|
18
|
+
if (showManualHint) {
|
|
19
|
+
console.warn(" Please manually restrict access to this file (chmod 600 on Unix).");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read Claude Desktop config file
|
|
25
|
+
*/
|
|
26
|
+
export function readClaudeConfig(configPath) {
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(configPath)) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
return JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const nodeError = error;
|
|
35
|
+
if (nodeError.code === "ENOENT") {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
39
|
+
throw new Error(`Failed to read config at ${configPath}: ${message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Write Claude Desktop config file with secure permissions (0o600)
|
|
44
|
+
* CRITICAL: Config contains passphrase, must be owner-only readable
|
|
45
|
+
*/
|
|
46
|
+
export function writeClaudeConfig(configPath, config) {
|
|
47
|
+
const dir = path.dirname(configPath);
|
|
48
|
+
if (!fs.existsSync(dir)) {
|
|
49
|
+
fs.mkdirSync(dir, { recursive: true, mode: SECURE_DIR_MODE });
|
|
50
|
+
}
|
|
51
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
52
|
+
setSecurePermissions(configPath, true);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Backup existing config file with secure permissions (0o600)
|
|
56
|
+
*/
|
|
57
|
+
export function backupConfig(configPath) {
|
|
58
|
+
if (!fs.existsSync(configPath)) {
|
|
59
|
+
throw new Error("Config file does not exist");
|
|
60
|
+
}
|
|
61
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
62
|
+
const backupPath = `${configPath}.backup-${timestamp}`;
|
|
63
|
+
fs.copyFileSync(configPath, backupPath);
|
|
64
|
+
setSecurePermissions(backupPath);
|
|
65
|
+
return backupPath;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Add Footprint to Claude config
|
|
69
|
+
*/
|
|
70
|
+
export function addFootprintToConfig(config, dataDir, passphrase) {
|
|
71
|
+
return {
|
|
72
|
+
...config,
|
|
73
|
+
mcpServers: {
|
|
74
|
+
...config.mcpServers,
|
|
75
|
+
footprint: {
|
|
76
|
+
command: "npx",
|
|
77
|
+
args: ["@pcircle/footprint"],
|
|
78
|
+
env: {
|
|
79
|
+
FOOTPRINT_DATA_DIR: dataDir,
|
|
80
|
+
FOOTPRINT_PASSPHRASE: passphrase,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/cli/utils/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SystemInfo } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detect current operating system and environment
|
|
4
|
+
*/
|
|
5
|
+
export declare function detectSystem(): SystemInfo;
|
|
6
|
+
/**
|
|
7
|
+
* Detect user's default shell
|
|
8
|
+
*/
|
|
9
|
+
export declare function detectShell(): SystemInfo['shell'];
|
|
10
|
+
/**
|
|
11
|
+
* Find Claude Desktop config file path
|
|
12
|
+
*/
|
|
13
|
+
export declare function findClaudeConfig(): string | null;
|
|
14
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/detect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C;;GAEG;AACH,wBAAgB,YAAY,IAAI,UAAU,CAczC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,UAAU,CAAC,OAAO,CAAC,CASjD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAOhD"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { CLAUDE_CONFIG_PATHS, SHELL_RC_FILES } from '../constants.js';
|
|
5
|
+
/**
|
|
6
|
+
* Detect current operating system and environment
|
|
7
|
+
*/
|
|
8
|
+
export function detectSystem() {
|
|
9
|
+
const platform = os.platform();
|
|
10
|
+
const shell = detectShell();
|
|
11
|
+
const homeDir = os.homedir();
|
|
12
|
+
const claudeConfigPath = findClaudeConfig();
|
|
13
|
+
const shellRcPath = findShellRcPath(shell, homeDir);
|
|
14
|
+
return {
|
|
15
|
+
platform,
|
|
16
|
+
shell,
|
|
17
|
+
claudeConfigPath,
|
|
18
|
+
homeDir,
|
|
19
|
+
shellRcPath,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Detect user's default shell
|
|
24
|
+
*/
|
|
25
|
+
export function detectShell() {
|
|
26
|
+
const shellEnv = process.env.SHELL || '';
|
|
27
|
+
if (shellEnv.includes('zsh'))
|
|
28
|
+
return 'zsh';
|
|
29
|
+
if (shellEnv.includes('bash'))
|
|
30
|
+
return 'bash';
|
|
31
|
+
if (shellEnv.includes('fish'))
|
|
32
|
+
return 'fish';
|
|
33
|
+
if (process.platform === 'win32')
|
|
34
|
+
return 'powershell';
|
|
35
|
+
return 'bash'; // Default fallback
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Find Claude Desktop config file path
|
|
39
|
+
*/
|
|
40
|
+
export function findClaudeConfig() {
|
|
41
|
+
const platform = os.platform();
|
|
42
|
+
const configPath = CLAUDE_CONFIG_PATHS[platform];
|
|
43
|
+
if (!configPath)
|
|
44
|
+
return null;
|
|
45
|
+
return fs.existsSync(configPath) ? configPath : null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Find shell RC file path
|
|
49
|
+
*/
|
|
50
|
+
function findShellRcPath(shell, homeDir) {
|
|
51
|
+
const rcFile = SHELL_RC_FILES[shell];
|
|
52
|
+
if (!rcFile)
|
|
53
|
+
return null;
|
|
54
|
+
const rcPath = path.join(homeDir, rcFile);
|
|
55
|
+
return fs.existsSync(rcPath) ? rcPath : null;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../../../src/cli/utils/detect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtE;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAA4B,CAAC;IACzD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,MAAM,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;IAC5C,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAEpD,OAAO;QACL,QAAQ;QACR,KAAK;QACL,gBAAgB;QAChB,OAAO;QACP,WAAW;KACZ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IAEzC,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC7C,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC7C,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,YAAY,CAAC;IAEtD,OAAO,MAAM,CAAC,CAAC,mBAAmB;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAsC,CAAC;IACnE,MAAM,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAEjD,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,OAAO,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,KAAa,EAAE,OAAe;IACrD,MAAM,MAAM,GAAG,cAAc,CAAC,KAAoC,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate environment variable export statement with proper escaping
|
|
3
|
+
* Note: _shell parameter reserved for future shell-specific syntax (e.g., fish)
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateEnvExport(_shell: string, dataDir: string, passphrase: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Append environment variables to shell RC file with secure permissions (0o600)
|
|
8
|
+
*/
|
|
9
|
+
export declare function appendToShellRc(rcPath: string, content: string): void;
|
|
10
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/env.ts"],"names":[],"mappings":"AAcA;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,MAAM,CAQR;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA8BrE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* global console */
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
/**
|
|
4
|
+
* Escape string for safe use in shell single quotes
|
|
5
|
+
* Prevents shell injection attacks by properly escaping special characters
|
|
6
|
+
*/
|
|
7
|
+
function escapeShellString(str) {
|
|
8
|
+
// In single quotes, only single quote needs escaping
|
|
9
|
+
// We escape it by ending the quote, adding an escaped quote, and starting a new quote
|
|
10
|
+
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate environment variable export statement with proper escaping
|
|
14
|
+
* Note: _shell parameter reserved for future shell-specific syntax (e.g., fish)
|
|
15
|
+
*/
|
|
16
|
+
export function generateEnvExport(_shell, dataDir, passphrase) {
|
|
17
|
+
return [
|
|
18
|
+
"",
|
|
19
|
+
"# Footprint MCP Server Environment Variables",
|
|
20
|
+
`export FOOTPRINT_DATA_DIR=${escapeShellString(dataDir)}`,
|
|
21
|
+
`export FOOTPRINT_PASSPHRASE=${escapeShellString(passphrase)}`,
|
|
22
|
+
"",
|
|
23
|
+
].join("\n");
|
|
24
|
+
}
|
|
25
|
+
const FOOTPRINT_HEADER = "# Footprint MCP Server";
|
|
26
|
+
const FOOTPRINT_BLOCK_REGEX = /# Footprint MCP Server[\s\S]*?export FOOTPRINT_PASSPHRASE/;
|
|
27
|
+
/**
|
|
28
|
+
* Append environment variables to shell RC file with secure permissions (0o600)
|
|
29
|
+
*/
|
|
30
|
+
export function appendToShellRc(rcPath, content) {
|
|
31
|
+
if (!fs.existsSync(rcPath)) {
|
|
32
|
+
throw new Error(`Shell RC file not found: ${rcPath}`);
|
|
33
|
+
}
|
|
34
|
+
const existing = fs.readFileSync(rcPath, "utf-8");
|
|
35
|
+
if (FOOTPRINT_BLOCK_REGEX.test(existing)) {
|
|
36
|
+
throw new Error("Footprint already configured in shell RC file. " +
|
|
37
|
+
"Please remove existing configuration before re-running setup, " +
|
|
38
|
+
"or manually update the existing configuration.");
|
|
39
|
+
}
|
|
40
|
+
// Add header if content doesn't already include it (defensive)
|
|
41
|
+
const wrappedContent = content.includes(FOOTPRINT_HEADER)
|
|
42
|
+
? content
|
|
43
|
+
: `\n${FOOTPRINT_HEADER}\n${content}`;
|
|
44
|
+
fs.appendFileSync(rcPath, wrappedContent, "utf-8");
|
|
45
|
+
// Set restrictive permissions (owner read/write only)
|
|
46
|
+
try {
|
|
47
|
+
fs.chmodSync(rcPath, 0o600);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
51
|
+
console.warn(`Warning: Could not set secure permissions on ${rcPath}: ${message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../../../src/cli/utils/env.ts"],"names":[],"mappings":"AAAA,oBAAoB;AAEpB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;GAGG;AACH,SAAS,iBAAiB,CAAC,GAAW;IACpC,qDAAqD;IACrD,sFAAsF;IACtF,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,OAAe,EACf,UAAkB;IAElB,OAAO;QACL,EAAE;QACF,8CAA8C;QAC9C,6BAA6B,iBAAiB,CAAC,OAAO,CAAC,EAAE;QACzD,+BAA+B,iBAAiB,CAAC,UAAU,CAAC,EAAE;QAC9D,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAClD,MAAM,qBAAqB,GACzB,2DAA2D,CAAC;AAE9D;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,OAAe;IAC7D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClD,IAAI,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,iDAAiD;YAC/C,gEAAgE;YAChE,gDAAgD,CACnD,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QACvD,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,KAAK,gBAAgB,KAAK,OAAO,EAAE,CAAC;IAExC,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAEnD,sDAAsD;IACtD,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CACV,gDAAgD,MAAM,KAAK,OAAO,EAAE,CACrE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ValidationResult } from "../types.js";
|
|
2
|
+
export type PathValidationResult = ValidationResult & {
|
|
3
|
+
normalizedPath?: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Validate password strength using zxcvbn
|
|
7
|
+
*/
|
|
8
|
+
export declare function validatePassword(password: string): ValidationResult;
|
|
9
|
+
/**
|
|
10
|
+
* Validate and normalize file path with security checks:
|
|
11
|
+
* - Rejects dangerous shell characters
|
|
12
|
+
* - Expands tilde (~) to home directory
|
|
13
|
+
* - Ensures path is absolute and within home directory
|
|
14
|
+
* - Rejects symbolic links (could point outside allowed directories)
|
|
15
|
+
*/
|
|
16
|
+
export declare function validatePath(inputPath: string): PathValidationResult;
|
|
17
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../src/cli/utils/validation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAkBnE;AASD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,CA+CpE"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import zxcvbn from "zxcvbn";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import { MIN_PASSWORD_SCORE, MIN_PASSWORD_LENGTH } from "../constants.js";
|
|
6
|
+
/** Characters not allowed in paths (shell injection prevention) */
|
|
7
|
+
const DANGEROUS_PATH_CHARS = /[;&|`$()]/g;
|
|
8
|
+
/**
|
|
9
|
+
* Validate password strength using zxcvbn
|
|
10
|
+
*/
|
|
11
|
+
export function validatePassword(password) {
|
|
12
|
+
if (password.length < MIN_PASSWORD_LENGTH) {
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
message: `Password must be at least ${MIN_PASSWORD_LENGTH} characters`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const result = zxcvbn(password);
|
|
19
|
+
if (result.score < MIN_PASSWORD_SCORE) {
|
|
20
|
+
return {
|
|
21
|
+
valid: false,
|
|
22
|
+
message: `Password is too weak. ${result.feedback.suggestions.join(" ")}`,
|
|
23
|
+
score: result.score,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return { valid: true, score: result.score };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Helper to create invalid result
|
|
30
|
+
*/
|
|
31
|
+
function invalid(message) {
|
|
32
|
+
return { valid: false, message };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Validate and normalize file path with security checks:
|
|
36
|
+
* - Rejects dangerous shell characters
|
|
37
|
+
* - Expands tilde (~) to home directory
|
|
38
|
+
* - Ensures path is absolute and within home directory
|
|
39
|
+
* - Rejects symbolic links (could point outside allowed directories)
|
|
40
|
+
*/
|
|
41
|
+
export function validatePath(inputPath) {
|
|
42
|
+
if (!inputPath || typeof inputPath !== "string") {
|
|
43
|
+
return invalid("Path must be a non-empty string");
|
|
44
|
+
}
|
|
45
|
+
// Security: Reject dangerous shell characters
|
|
46
|
+
if (DANGEROUS_PATH_CHARS.test(inputPath)) {
|
|
47
|
+
return invalid("Path contains invalid characters. Special shell characters are not allowed.");
|
|
48
|
+
}
|
|
49
|
+
// Expand tilde to home directory
|
|
50
|
+
const homeDir = os.homedir();
|
|
51
|
+
const expanded = inputPath.startsWith("~")
|
|
52
|
+
? path.join(homeDir, inputPath.slice(1))
|
|
53
|
+
: inputPath;
|
|
54
|
+
if (!path.isAbsolute(expanded)) {
|
|
55
|
+
return invalid("Path must be absolute (e.g., /Users/name/data or ~/.footprint)");
|
|
56
|
+
}
|
|
57
|
+
// Normalize to prevent path traversal attacks (../)
|
|
58
|
+
const normalized = path.resolve(path.normalize(expanded));
|
|
59
|
+
// Security: Ensure path is within user's home directory
|
|
60
|
+
if (!normalized.startsWith(homeDir)) {
|
|
61
|
+
return invalid(`Path must be within your home directory (${homeDir})`);
|
|
62
|
+
}
|
|
63
|
+
// Security: Reject symbolic links (could point outside allowed directories)
|
|
64
|
+
if (fs.existsSync(normalized)) {
|
|
65
|
+
try {
|
|
66
|
+
if (fs.lstatSync(normalized).isSymbolicLink()) {
|
|
67
|
+
return invalid("Symbolic links are not allowed for security reasons. Please use a real directory path.");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
return invalid(`Failed to validate path: ${message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { valid: true, normalizedPath: normalized };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../../src/cli/utils/validation.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAiBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAuC/C;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,oBAAoB,CAAoC;gBAEpD,MAAM,EAAE,YAAY;IAuBhC;;;;;;;OAOG;YACW,aAAa;IAsC3B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,aAAa;IA2HrB,OAAO,CAAC,iBAAiB;IAqCnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B;;;OAGG;IACH,KAAK,IAAI,IAAI;CAId;AAGD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA4C1C;AAeD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* global console, process */
|
|
2
3
|
import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
5
|
import { EvidenceDatabase, storeSalt, retrieveSalt, } from "./lib/storage/index.js";
|
|
@@ -193,7 +194,8 @@ export class FootprintServer {
|
|
|
193
194
|
this.db.close();
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
|
-
|
|
197
|
+
// Export main as named function
|
|
198
|
+
export async function main() {
|
|
197
199
|
const config = {
|
|
198
200
|
dbPath: process.env.FOOTPRINT_DB_PATH || "./evidence.db",
|
|
199
201
|
password: process.env.FOOTPRINT_PASSWORD || "",
|
|
@@ -229,11 +231,11 @@ async function main() {
|
|
|
229
231
|
process.on("exit", cleanup);
|
|
230
232
|
await server.start();
|
|
231
233
|
}
|
|
232
|
-
//
|
|
234
|
+
// Only run if this is the main module (not imported by CLI)
|
|
233
235
|
const isMainModule = import.meta.url === `file://${process.argv[1]}` ||
|
|
234
236
|
process.argv[1]?.endsWith("/footprint") ||
|
|
235
237
|
process.argv[1]?.endsWith("/dist/index.js");
|
|
236
|
-
if (isMainModule) {
|
|
238
|
+
if (isMainModule && !process.argv.includes("setup")) {
|
|
237
239
|
main().catch((error) => {
|
|
238
240
|
console.error("Server error:", error);
|
|
239
241
|
process.exit(1);
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pcircle/footprint",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "MCP server for Footprint - automatic audit trails and encrypted evidence for AI conversations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
"main": "./dist/src/index.js",
|
|
22
22
|
"types": "./dist/src/index.d.ts",
|
|
23
23
|
"bin": {
|
|
24
|
-
"footprint": "./dist/src/index.js"
|
|
24
|
+
"footprint": "./dist/src/cli/index.js"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
|
-
"dist",
|
|
27
|
+
"dist/src",
|
|
28
|
+
"dist/ui",
|
|
28
29
|
"SKILL.md",
|
|
29
30
|
"README.md",
|
|
30
31
|
"LICENSE"
|
|
@@ -55,15 +56,21 @@
|
|
|
55
56
|
"@noble/ciphers": "^0.5.2",
|
|
56
57
|
"@noble/hashes": "^1.3.3",
|
|
57
58
|
"better-sqlite3": "^12.6.2",
|
|
59
|
+
"chalk": "^5.6.2",
|
|
58
60
|
"isomorphic-git": "^1.36.2",
|
|
59
61
|
"jszip": "^3.10.1",
|
|
60
|
-
"
|
|
62
|
+
"ora": "^9.1.0",
|
|
63
|
+
"prompts": "^2.4.2",
|
|
64
|
+
"zod": "^3.23.8",
|
|
65
|
+
"zxcvbn": "^4.4.2"
|
|
61
66
|
},
|
|
62
67
|
"devDependencies": {
|
|
63
68
|
"@types/better-sqlite3": "^7.6.9",
|
|
64
69
|
"@types/cors": "^2.8.19",
|
|
65
70
|
"@types/express": "^5.0.6",
|
|
66
71
|
"@types/node": "^22.10.5",
|
|
72
|
+
"@types/prompts": "^2.4.9",
|
|
73
|
+
"@types/zxcvbn": "^4.4.5",
|
|
67
74
|
"concurrently": "^9.2.1",
|
|
68
75
|
"cross-env": "^10.1.0",
|
|
69
76
|
"tsx": "^4.21.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error-handling.test.d.ts","sourceRoot":"","sources":["../../tests/error-handling.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { FootprintServer, FootprintTestHelpers } from '../src/index.js';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
describe('Error Handling & Edge Cases', () => {
|
|
6
|
-
let server;
|
|
7
|
-
let helpers;
|
|
8
|
-
const testDbPath = path.join(process.cwd(), `test-edge-cases-${Date.now()}-${Math.random().toString(36).substring(7)}.db`);
|
|
9
|
-
const testPassword = 'edge-case-password';
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
if (fs.existsSync(testDbPath)) {
|
|
12
|
-
fs.unlinkSync(testDbPath);
|
|
13
|
-
}
|
|
14
|
-
const config = {
|
|
15
|
-
dbPath: testDbPath,
|
|
16
|
-
password: testPassword
|
|
17
|
-
};
|
|
18
|
-
server = new FootprintServer(config);
|
|
19
|
-
helpers = new FootprintTestHelpers(server);
|
|
20
|
-
});
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
if (fs.existsSync(testDbPath)) {
|
|
23
|
-
fs.unlinkSync(testDbPath);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
describe('Input Validation', () => {
|
|
27
|
-
it('should reject empty conversation content', async () => {
|
|
28
|
-
await expect(helpers.callTool('capture-footprint', {
|
|
29
|
-
conversationId: 'conv-1',
|
|
30
|
-
llmProvider: 'Claude',
|
|
31
|
-
content: '',
|
|
32
|
-
messageCount: 0
|
|
33
|
-
})).rejects.toThrow();
|
|
34
|
-
});
|
|
35
|
-
it('should reject negative message count', async () => {
|
|
36
|
-
await expect(helpers.callTool('capture-footprint', {
|
|
37
|
-
conversationId: 'conv-1',
|
|
38
|
-
llmProvider: 'Claude',
|
|
39
|
-
content: 'test',
|
|
40
|
-
messageCount: -1
|
|
41
|
-
})).rejects.toThrow();
|
|
42
|
-
});
|
|
43
|
-
it('should reject invalid pagination parameters', async () => {
|
|
44
|
-
await expect(helpers.callTool('list-footprints', { limit: -1 })).rejects.toThrow();
|
|
45
|
-
await expect(helpers.callTool('list-footprints', { offset: -5 })).rejects.toThrow();
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('Large Content Handling', () => {
|
|
49
|
-
it('should handle large conversation content (>1MB)', async () => {
|
|
50
|
-
const largeContent = 'x'.repeat(2 * 1024 * 1024); // 2MB
|
|
51
|
-
const result = await helpers.callTool('capture-footprint', {
|
|
52
|
-
conversationId: 'large-conv',
|
|
53
|
-
llmProvider: 'Claude',
|
|
54
|
-
content: largeContent,
|
|
55
|
-
messageCount: 100
|
|
56
|
-
});
|
|
57
|
-
expect(result.structuredContent.success).toBe(true);
|
|
58
|
-
// Verify retrieval
|
|
59
|
-
const retrieved = await helpers.callTool('get-footprint', {
|
|
60
|
-
id: result.structuredContent.id
|
|
61
|
-
});
|
|
62
|
-
expect(retrieved.structuredContent.content).toBe(largeContent);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe('Special Characters', () => {
|
|
66
|
-
it('should handle UTF-8, emoji, and special characters', async () => {
|
|
67
|
-
const specialContent = '你好 🔐 测试 \n\t Special: <>&"\'';
|
|
68
|
-
const result = await helpers.callTool('capture-footprint', {
|
|
69
|
-
conversationId: 'special-conv',
|
|
70
|
-
llmProvider: 'Claude Sonnet 4.5',
|
|
71
|
-
content: specialContent,
|
|
72
|
-
messageCount: 1,
|
|
73
|
-
tags: 'emoji-✨,中文-测试'
|
|
74
|
-
});
|
|
75
|
-
const retrieved = await helpers.callTool('get-footprint', {
|
|
76
|
-
id: result.structuredContent.id
|
|
77
|
-
});
|
|
78
|
-
expect(retrieved.structuredContent.content).toBe(specialContent);
|
|
79
|
-
expect(retrieved.structuredContent.tags).toBe('emoji-✨,中文-测试');
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
describe('Database Errors', () => {
|
|
83
|
-
it('should handle database corruption gracefully', async () => {
|
|
84
|
-
// Corrupt database by writing garbage
|
|
85
|
-
fs.writeFileSync(testDbPath, 'CORRUPTED_DATA');
|
|
86
|
-
// Also remove WAL files if they exist (WAL mode creates these)
|
|
87
|
-
const walPath = `${testDbPath}-wal`;
|
|
88
|
-
const shmPath = `${testDbPath}-shm`;
|
|
89
|
-
if (fs.existsSync(walPath))
|
|
90
|
-
fs.unlinkSync(walPath);
|
|
91
|
-
if (fs.existsSync(shmPath))
|
|
92
|
-
fs.unlinkSync(shmPath);
|
|
93
|
-
// Create new server instance (should fail gracefully)
|
|
94
|
-
expect(() => {
|
|
95
|
-
new FootprintServer({
|
|
96
|
-
dbPath: testDbPath,
|
|
97
|
-
password: testPassword
|
|
98
|
-
});
|
|
99
|
-
}).toThrow();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
describe('Empty Database', () => {
|
|
103
|
-
it('should handle empty database correctly', async () => {
|
|
104
|
-
const result = await helpers.callTool('list-footprints', {});
|
|
105
|
-
expect(result.structuredContent.total).toBe(0);
|
|
106
|
-
expect(result.structuredContent.evidences).toEqual([]);
|
|
107
|
-
});
|
|
108
|
-
it('should handle export of empty database', async () => {
|
|
109
|
-
const result = await helpers.callTool('export-footprints', {});
|
|
110
|
-
expect(result.structuredContent.evidenceCount).toBe(0);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
//# sourceMappingURL=error-handling.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error-handling.test.js","sourceRoot":"","sources":["../../tests/error-handling.test.ts"],"names":[],"mappings":"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"}
|