fa-mcp-sdk 0.3.16 → 0.3.17

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 (47) hide show
  1. package/README.md +1 -1
  2. package/cli-template/.claude/agents/architect.md +99 -99
  3. package/cli-template/.claude/agents/auditor.md +92 -92
  4. package/cli-template/.claude/agents/fa-mcp-sdk.md +1 -1
  5. package/cli-template/.claude/agents/planner.md +122 -122
  6. package/cli-template/.claude/agents/prd-writer.md +88 -88
  7. package/cli-template/.claude/agents/refactor.md +74 -74
  8. package/cli-template/.claude/agents/worker.md +132 -132
  9. package/cli-template/CLAUDE.md +1 -1
  10. package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +3 -0
  11. package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +41 -0
  12. package/cli-template/README.md +105 -105
  13. package/cli-template/package.json +1 -1
  14. package/cli-template/prompt-example-new-MCP.md +2 -1
  15. package/cli-template/r/TEST HTTP.xml +9 -9
  16. package/cli-template/r/TEST SSE.xml +5 -5
  17. package/cli-template/r/TEST STDIO.xml +5 -5
  18. package/cli-template/r/generate-token.xml +13 -13
  19. package/cli-template/r/lint-fix-build.xml +12 -12
  20. package/cli-template/r/remove-nul.xml +11 -11
  21. package/config/custom-environment-variables.yaml +1 -0
  22. package/config/default.yaml +3 -0
  23. package/config/development.yaml +4 -4
  24. package/config/production.yaml +4 -4
  25. package/dist/core/_types_/config.d.ts +1 -0
  26. package/dist/core/_types_/config.d.ts.map +1 -1
  27. package/dist/core/auth/ip-check.d.ts +18 -0
  28. package/dist/core/auth/ip-check.d.ts.map +1 -0
  29. package/dist/core/auth/ip-check.js +148 -0
  30. package/dist/core/auth/ip-check.js.map +1 -0
  31. package/dist/core/auth/jwt.d.ts +1 -0
  32. package/dist/core/auth/jwt.d.ts.map +1 -1
  33. package/dist/core/auth/jwt.js +15 -1
  34. package/dist/core/auth/jwt.js.map +1 -1
  35. package/dist/core/auth/multi-auth.d.ts.map +1 -1
  36. package/dist/core/auth/multi-auth.js +4 -1
  37. package/dist/core/auth/multi-auth.js.map +1 -1
  38. package/dist/core/auth/token-generator/ntlm/ntlm-templates.js +221 -221
  39. package/dist/core/web/static/token-gen/index.html +9 -0
  40. package/dist/core/web/static/token-gen/logout.svg +4 -4
  41. package/dist/core/web/static/token-gen/script.js +7 -1
  42. package/dist/core/web/static/token-gen/user.svg +4 -4
  43. package/package.json +1 -1
  44. package/scripts/publish.sh +78 -78
  45. package/scripts/update-doc.js +18 -18
  46. package/config/local-2.yaml +0 -20
  47. package/config/local.yaml +0 -101
@@ -1,105 +1,105 @@
1
- # {{project.productName}}
2
-
3
- {{project.description}}
4
-
5
- ## Install & Run
6
-
7
- ### Quick Start
8
- ```bash
9
- # Install
10
- npm install
11
-
12
- # Configure (copy config/local.yaml from config/_local.yaml)
13
- # Add database credentials
14
-
15
- # Build
16
- npm run build
17
-
18
- # Run (STDIO mode for Claude Desktop)
19
- npm start
20
- ```
21
-
22
- ### Test Run
23
- ```bash
24
- # Unit tests
25
- npm test
26
-
27
- # MCP protocol tests
28
- npm run test:mcp # STDIO mode
29
- npm run test:mcp-http # HTTP mode
30
- npm run test:mcp-simple # Simple test
31
- ```
32
-
33
- ### Dual Transport System
34
-
35
- **STDIO Mode** (default for Claude Desktop):
36
- - Direct stdin/stdout communication
37
- - Optimal for Claude Desktop integration
38
- - No network ports required
39
-
40
- **HTTP Mode** (web integration):
41
- - HTTP server with Server-Sent Events (SSE)
42
- - Home page with server status at `http://localhost:{{port}}/`
43
- - Health check endpoint at `/health`
44
- - Direct JSON-RPC 2.0 endpoint at `/mcp`
45
-
46
-
47
- ## Features
48
-
49
-
50
-
51
- ## MCP Tools
52
-
53
-
54
-
55
- ## MCP Prompts
56
-
57
- ### `agent_brief`
58
- Brief description of agent capabilities for agent selection.
59
-
60
- ### `agent_prompt`
61
- Complete prompt with instructions.
62
-
63
- ## MCP Resources
64
-
65
- ### `staff://agent/brief`
66
- Same as `agent_brief` prompt. **MIME:** text/plain
67
-
68
- ### `staff://agent/prompt`
69
- Same as `agent_prompt` prompt. **MIME:** text/plain
70
-
71
-
72
- ## 2. Configuration
73
-
74
- **Option A: Configuration File**
75
-
76
- **Option B: Environment Variables**
77
-
78
-
79
- ## Claude Desktop Setup
80
-
81
- Add to `claude_desktop_config.json`:
82
-
83
- ```json
84
- {
85
- "mcpServers": {
86
- "{{project.name}}": {
87
- "command": "node",
88
- "args": [
89
- "<path-to-project>/mcp-staff-db/dist/src/index.js"
90
- ],
91
- "env": {
92
- }
93
- }
94
- }
95
- }
96
- ```
97
-
98
- ## HTTP Mode Endpoints
99
-
100
- - **/** - Home page
101
- - **/health** - Health check
102
- - **/sse** - Server-Sent Events
103
- - **/mcp** - JSON-RPC 2.0
104
-
105
- ## Security
1
+ # {{project.productName}}
2
+
3
+ {{project.description}}
4
+
5
+ ## Install & Run
6
+
7
+ ### Quick Start
8
+ ```bash
9
+ # Install
10
+ npm install
11
+
12
+ # Configure (copy config/local.yaml from config/_local.yaml)
13
+ # Add database credentials
14
+
15
+ # Build
16
+ npm run build
17
+
18
+ # Run (STDIO mode for Claude Desktop)
19
+ npm start
20
+ ```
21
+
22
+ ### Test Run
23
+ ```bash
24
+ # Unit tests
25
+ npm test
26
+
27
+ # MCP protocol tests
28
+ npm run test:mcp # STDIO mode
29
+ npm run test:mcp-http # HTTP mode
30
+ npm run test:mcp-simple # Simple test
31
+ ```
32
+
33
+ ### Dual Transport System
34
+
35
+ **STDIO Mode** (default for Claude Desktop):
36
+ - Direct stdin/stdout communication
37
+ - Optimal for Claude Desktop integration
38
+ - No network ports required
39
+
40
+ **HTTP Mode** (web integration):
41
+ - HTTP server with Server-Sent Events (SSE)
42
+ - Home page with server status at `http://localhost:{{port}}/`
43
+ - Health check endpoint at `/health`
44
+ - Direct JSON-RPC 2.0 endpoint at `/mcp`
45
+
46
+
47
+ ## Features
48
+
49
+
50
+
51
+ ## MCP Tools
52
+
53
+
54
+
55
+ ## MCP Prompts
56
+
57
+ ### `agent_brief`
58
+ Brief description of agent capabilities for agent selection.
59
+
60
+ ### `agent_prompt`
61
+ Complete prompt with instructions.
62
+
63
+ ## MCP Resources
64
+
65
+ ### `staff://agent/brief`
66
+ Same as `agent_brief` prompt. **MIME:** text/plain
67
+
68
+ ### `staff://agent/prompt`
69
+ Same as `agent_prompt` prompt. **MIME:** text/plain
70
+
71
+
72
+ ## 2. Configuration
73
+
74
+ **Option A: Configuration File**
75
+
76
+ **Option B: Environment Variables**
77
+
78
+
79
+ ## Claude Desktop Setup
80
+
81
+ Add to `claude_desktop_config.json`:
82
+
83
+ ```json
84
+ {
85
+ "mcpServers": {
86
+ "{{project.name}}": {
87
+ "command": "node",
88
+ "args": [
89
+ "<path-to-project>/mcp-staff-db/dist/src/index.js"
90
+ ],
91
+ "env": {
92
+ }
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## HTTP Mode Endpoints
99
+
100
+ - **/** - Home page
101
+ - **/health** - Health check
102
+ - **/sse** - Server-Sent Events
103
+ - **/mcp** - JSON-RPC 2.0
104
+
105
+ ## Security
@@ -50,7 +50,7 @@
50
50
  "dependencies": {
51
51
  "@modelcontextprotocol/sdk": "^1.26.0",
52
52
  "dotenv": "^17.2.4",
53
- "fa-mcp-sdk": "^0.3.16"
53
+ "fa-mcp-sdk": "^0.3.17"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/express": "^5.0.6",
@@ -18,7 +18,7 @@ Authorization: Bearer <appConfig.accessPoints.currencyService.token>
18
18
  Example:
19
19
 
20
20
  ```http request
21
- GET http://smart-trade-ml.com:5002/currency-service/?rate=THBRUB
21
+ GET http://smart-trade-ml.com:5001/currency-service/?rate=THBRUB
22
22
  Authorization: Bearer <appConfig.accessPoints.currencyService.token>
23
23
  ```
24
24
 
@@ -66,6 +66,7 @@ webServer:
66
66
  jwtToken:
67
67
  encryptKey: 'dbbe87db-90d0-4732-aae3-4089763ec392'
68
68
  checkMCPName: true
69
+ isCheckIP: false
69
70
  permanentServerTokens: ['psToken1']
70
71
 
71
72
  adminAuth:
@@ -1,9 +1,9 @@
1
- <component name="ProjectRunConfigurationManager">
2
- <configuration
3
- default="false"
4
- name="TEST HTTP"
5
- type="NodeJSConfigurationType"
6
- path-to-js-file="tests/mcp/test-http.js" working-dir="$PROJECT_DIR$/">
7
- <method v="2" />
8
- </configuration>
9
- </component>
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration
3
+ default="false"
4
+ name="TEST HTTP"
5
+ type="NodeJSConfigurationType"
6
+ path-to-js-file="tests/mcp/test-http.js" working-dir="$PROJECT_DIR$/">
7
+ <method v="2" />
8
+ </configuration>
9
+ </component>
@@ -1,5 +1,5 @@
1
- <component name="ProjectRunConfigurationManager">
2
- <configuration default="false" name="TEST SSE" type="NodeJSConfigurationType" path-to-js-file="tests/mcp/test-sse.js" working-dir="$PROJECT_DIR$/">
3
- <method v="2" />
4
- </configuration>
5
- </component>
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration default="false" name="TEST SSE" type="NodeJSConfigurationType" path-to-js-file="tests/mcp/test-sse.js" working-dir="$PROJECT_DIR$/">
3
+ <method v="2" />
4
+ </configuration>
5
+ </component>
@@ -1,5 +1,5 @@
1
- <component name="ProjectRunConfigurationManager">
2
- <configuration default="false" name="TEST STDIO" type="NodeJSConfigurationType" path-to-js-file="tests/mcp/test-stdio.js" working-dir="$PROJECT_DIR$">
3
- <method v="2" />
4
- </configuration>
5
- </component>
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration default="false" name="TEST STDIO" type="NodeJSConfigurationType" path-to-js-file="tests/mcp/test-stdio.js" working-dir="$PROJECT_DIR$">
3
+ <method v="2" />
4
+ </configuration>
5
+ </component>
@@ -1,14 +1,14 @@
1
- <component name="ProjectRunConfigurationManager">
2
- <configuration default="false" name="generate-token" type="js.build_tools.npm" nameIsGenerated="true">
3
- <package-json value="$PROJECT_DIR$/package.json" />
4
- <command value="run" />
5
- <scripts>
6
- <script value="generate-token" />
7
- </scripts>
8
- <node-interpreter value="project" />
9
- <envs>
10
- <env name="DEBUG" value="ntlm:auth-flow,ntlm:ldap-proxy,ntlm:ldap-proxy-id" />
11
- </envs>
12
- <method v="2" />
13
- </configuration>
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration default="false" name="generate-token" type="js.build_tools.npm" nameIsGenerated="true">
3
+ <package-json value="$PROJECT_DIR$/package.json" />
4
+ <command value="run" />
5
+ <scripts>
6
+ <script value="generate-token" />
7
+ </scripts>
8
+ <node-interpreter value="project" />
9
+ <envs>
10
+ <env name="DEBUG" value="ntlm:auth-flow,ntlm:ldap-proxy,ntlm:ldap-proxy-id" />
11
+ </envs>
12
+ <method v="2" />
13
+ </configuration>
14
14
  </component>
@@ -1,12 +1,12 @@
1
- <component name="ProjectRunConfigurationManager">
2
- <configuration default="false" name="lint-fix-build" type="js.build_tools.npm" nameIsGenerated="true">
3
- <package-json value="$PROJECT_DIR$/package.json" />
4
- <command value="run" />
5
- <scripts>
6
- <script value="lint-fix-build" />
7
- </scripts>
8
- <node-interpreter value="project" />
9
- <envs />
10
- <method v="2" />
11
- </configuration>
12
- </component>
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration default="false" name="lint-fix-build" type="js.build_tools.npm" nameIsGenerated="true">
3
+ <package-json value="$PROJECT_DIR$/package.json" />
4
+ <command value="run" />
5
+ <scripts>
6
+ <script value="lint-fix-build" />
7
+ </scripts>
8
+ <node-interpreter value="project" />
9
+ <envs />
10
+ <method v="2" />
11
+ </configuration>
12
+ </component>
@@ -1,11 +1,11 @@
1
- <component name="ProjectRunConfigurationManager">
2
- <configuration
3
- default="false"
4
- name="remove-nul.js"
5
- type="NodeJSConfigurationType"
6
- nameIsGenerated="true"
7
- path-to-js-file="scripts/remove-nul.js"
8
- working-dir="$PROJECT_DIR$">
9
- <method v="2"/>
10
- </configuration>
11
- </component>
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration
3
+ default="false"
4
+ name="remove-nul.js"
5
+ type="NodeJSConfigurationType"
6
+ nameIsGenerated="true"
7
+ path-to-js-file="scripts/remove-nul.js"
8
+ working-dir="$PROJECT_DIR$">
9
+ <method v="2"/>
10
+ </configuration>
11
+ </component>
@@ -44,6 +44,7 @@ webServer:
44
44
  jwtToken:
45
45
  encryptKey: WS_TOKEN_ENCRYPT_KEY
46
46
  checkMCPName: WS_CHECK_MC_NAME
47
+ isCheckIP: WS_JWT_CHECK_IP
47
48
  basic:
48
49
  username: WS_AUTH_BASIC_USERNAME
49
50
  password: WS_AUTH_BASIC_PASSWORD
@@ -176,6 +176,9 @@ webServer:
176
176
  encryptKey: '***'
177
177
  # If webServer.auth.enabled and the parameter true, the service name and the service specified in the token will be checked
178
178
  checkMCPName: true
179
+ # If true and JWT token contains non-empty 'ip' field,
180
+ # the client IP will be checked against the allowed list in the token
181
+ isCheckIP: false
179
182
 
180
183
  # ========================================================================
181
184
  # Basic Authentication - Base64 encoded username:password
@@ -1,4 +1,4 @@
1
- ---
2
-
3
-
4
-
1
+ ---
2
+
3
+
4
+
@@ -1,4 +1,4 @@
1
- ---
2
-
3
-
4
-
1
+ ---
2
+
3
+
4
+
@@ -16,6 +16,7 @@ interface IWebServerConfig {
16
16
  jwtToken: {
17
17
  encryptKey: string;
18
18
  checkMCPName: boolean;
19
+ isCheckIP: boolean;
19
20
  };
20
21
  permanentServerTokens: string[];
21
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/core/_types_/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAGzD,UAAU,gBAAgB;IACxB,SAAS,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,IAAI,EAAE;YACJ,OAAO,EAAE,OAAO,CAAC;YACjB,KAAK,CAAC,EAAE;gBACN,QAAQ,EAAE,MAAM,CAAC;gBACjB,QAAQ,EAAE,MAAM,CAAC;aAClB,CAAC;YACF,QAAQ,EAAE;gBACR,UAAU,EAAE,MAAM,CAAC;gBACnB,YAAY,EAAE,OAAO,CAAC;aACvB,CAAA;YACD,qBAAqB,EAAE,MAAM,EAAE,CAAC;SACjC,CAAC;QACF,SAAS,EAAE;YACT,OAAO,EAAE,OAAO,CAAC;YACjB,IAAI,EAAE,uBAAuB,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;SAC/D,CAAC;KACH,CAAA;CACF;AAGD,UAAU,aAAa;IACrB,MAAM,EAAE;QACN,KAAK,EAAE,aAAa,CAAC;QACrB,aAAa,EAAE,OAAO,CAAC;QACvB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAA;CACF;AAED,UAAU,UAAU;IAClB,GAAG,EAAE;QACH,SAAS,EAAE;YACT,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,YAAY,EAAE,MAAM,GAAG,mBAAmB,CAAA;QAC1C,aAAa,EAAE,OAAO,GAAG,MAAM,CAAC;KACjC,CAAA;CACF;AAED,UAAU,cAAc;IACtB,OAAO,EAAE;QACP,OAAO,CAAC,EAAE;YACR,GAAG,EAAE,MAAM,CAAC;YACZ,WAAW,EAAE,MAAM,CAAC;SACrB,EAAE,CAAC;KACL,CAAA;CACF;AAED,UAAU,kBAAkB;IAC1B,WAAW,CAAC,EAAE;QACZ,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE;YACP,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAA;CACF;AAED,UAAU,YAAY;IACpB,KAAK,EAAE;QACL,UAAU,EAAE,GAAG,CAAC;QAChB,QAAQ,EAAE,IAAI,CAAC;KAChB,CAAA;CACF;AAED,MAAM,WAAW,SAAU,SAAQ,SAAS,EAC1C,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,kBAAkB;IAElB,YAAY,EAAE,OAAO,CAAC;IAEtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IAEpB,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,eAAe,GAAG;QACxB,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;KACH,CAAC;IACF,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;KACjB,CAAA;CACF"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/core/_types_/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * IP address parsing and CIDR matching utilities for JWT IP checking.
3
+ * Pure TypeScript implementation — no external dependencies.
4
+ */
5
+ /**
6
+ * Parses IP string (comma/semicolon/space-separated) into array of trimmed non-empty entries.
7
+ * Each entry is either a plain IP or a CIDR notation (e.g., "10.0.0.0/24").
8
+ */
9
+ export declare function parseIpList(ipStr: string): string[];
10
+ /**
11
+ * Checks if clientIp matches any entry in allowedIps.
12
+ * Supports:
13
+ * - Exact match (IPv4 and IPv6)
14
+ * - CIDR subnet match (e.g., 10.0.0.0/24)
15
+ * - IPv4-mapped IPv6 normalization (::ffff:x.x.x.x → x.x.x.x)
16
+ */
17
+ export declare function isIpAllowed(clientIp: string, allowedIps: string[]): boolean;
18
+ //# sourceMappingURL=ip-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ip-check.d.ts","sourceRoot":"","sources":["../../../src/core/auth/ip-check.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,WAAW,CAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQpD;AAmID;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAK5E"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * IP address parsing and CIDR matching utilities for JWT IP checking.
3
+ * Pure TypeScript implementation — no external dependencies.
4
+ */
5
+ /**
6
+ * Parses IP string (comma/semicolon/space-separated) into array of trimmed non-empty entries.
7
+ * Each entry is either a plain IP or a CIDR notation (e.g., "10.0.0.0/24").
8
+ */
9
+ export function parseIpList(ipStr) {
10
+ if (!ipStr) {
11
+ return [];
12
+ }
13
+ return ipStr
14
+ .split(/[,;\s]+/)
15
+ .map((s) => s.trim())
16
+ .filter(Boolean);
17
+ }
18
+ /**
19
+ * Normalizes an IP address string:
20
+ * - Strips IPv4-mapped IPv6 prefix (::ffff:x.x.x.x → x.x.x.x)
21
+ * - Trims whitespace
22
+ */
23
+ function normalizeIp(ip) {
24
+ ip = ip.trim();
25
+ // Strip IPv4-mapped IPv6 prefix
26
+ const mapped = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(ip);
27
+ if (mapped?.[1]) {
28
+ return mapped[1];
29
+ }
30
+ return ip;
31
+ }
32
+ /**
33
+ * Parses an IPv4 address string into a 32-bit number.
34
+ * Returns null if the string is not a valid IPv4 address.
35
+ */
36
+ function parseIpv4(ip) {
37
+ const parts = ip.split('.');
38
+ if (parts.length !== 4) {
39
+ return null;
40
+ }
41
+ let result = 0;
42
+ for (const part of parts) {
43
+ const n = Number(part);
44
+ if (!Number.isInteger(n) || n < 0 || n > 255) {
45
+ return null;
46
+ }
47
+ result = (result << 8) | n;
48
+ }
49
+ return result >>> 0; // ensure unsigned
50
+ }
51
+ /**
52
+ * Parses an IPv6 address string into a BigInt (128-bit).
53
+ * Supports full and abbreviated (::) notation.
54
+ * Returns null if the string is not a valid IPv6 address.
55
+ */
56
+ function parseIpv6(ip) {
57
+ // Handle IPv4-mapped IPv6
58
+ const v4mapped = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(ip);
59
+ if (v4mapped?.[1]) {
60
+ const v4 = parseIpv4(v4mapped[1]);
61
+ if (v4 === null) {
62
+ return null;
63
+ }
64
+ return BigInt(0xffff00000000n) | BigInt(v4);
65
+ }
66
+ const halves = ip.split('::');
67
+ if (halves.length > 2) {
68
+ return null;
69
+ }
70
+ let groups = [];
71
+ if (halves.length === 2) {
72
+ const left = halves[0] ? halves[0].split(':') : [];
73
+ const right = halves[1] ? halves[1].split(':') : [];
74
+ const missing = 8 - left.length - right.length;
75
+ if (missing < 0) {
76
+ return null;
77
+ }
78
+ groups = [...left, ...Array(missing).fill('0'), ...right];
79
+ }
80
+ else {
81
+ groups = ip.split(':');
82
+ }
83
+ if (groups.length !== 8) {
84
+ return null;
85
+ }
86
+ let result = 0n;
87
+ for (const group of groups) {
88
+ if (!/^[0-9a-fA-F]{1,4}$/.test(group)) {
89
+ return null;
90
+ }
91
+ result = (result << 16n) | BigInt(parseInt(group, 16));
92
+ }
93
+ return result;
94
+ }
95
+ /**
96
+ * Checks if a client IP matches a single allowed entry (exact IP or CIDR).
97
+ */
98
+ function matchEntry(clientIp, entry) {
99
+ const cidrMatch = /^(.+)\/(\d+)$/.exec(entry);
100
+ if (cidrMatch?.[1] && cidrMatch[2]) {
101
+ const subnet = normalizeIp(cidrMatch[1]);
102
+ const prefixLen = Number(cidrMatch[2]);
103
+ const clientNorm = normalizeIp(clientIp);
104
+ // Try IPv4
105
+ const subnetV4 = parseIpv4(subnet);
106
+ const clientV4 = parseIpv4(clientNorm);
107
+ if (subnetV4 !== null && clientV4 !== null) {
108
+ if (prefixLen < 0 || prefixLen > 32) {
109
+ return false;
110
+ }
111
+ if (prefixLen === 0) {
112
+ return true;
113
+ }
114
+ const mask = (~0 << (32 - prefixLen)) >>> 0;
115
+ return (subnetV4 & mask) === (clientV4 & mask);
116
+ }
117
+ // Try IPv6
118
+ const subnetV6 = parseIpv6(subnet);
119
+ const clientV6 = parseIpv6(clientNorm);
120
+ if (subnetV6 !== null && clientV6 !== null) {
121
+ if (prefixLen < 0 || prefixLen > 128) {
122
+ return false;
123
+ }
124
+ if (prefixLen === 0) {
125
+ return true;
126
+ }
127
+ const shift = BigInt(128 - prefixLen);
128
+ return (subnetV6 >> shift) === (clientV6 >> shift);
129
+ }
130
+ return false;
131
+ }
132
+ // Exact match
133
+ return normalizeIp(clientIp) === normalizeIp(entry);
134
+ }
135
+ /**
136
+ * Checks if clientIp matches any entry in allowedIps.
137
+ * Supports:
138
+ * - Exact match (IPv4 and IPv6)
139
+ * - CIDR subnet match (e.g., 10.0.0.0/24)
140
+ * - IPv4-mapped IPv6 normalization (::ffff:x.x.x.x → x.x.x.x)
141
+ */
142
+ export function isIpAllowed(clientIp, allowedIps) {
143
+ if (!clientIp || !allowedIps.length) {
144
+ return false;
145
+ }
146
+ return allowedIps.some((entry) => matchEntry(clientIp, entry));
147
+ }
148
+ //# sourceMappingURL=ip-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ip-check.js","sourceRoot":"","sources":["../../../src/core/auth/ip-check.ts"],"names":[],"mappings":"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"}
@@ -25,5 +25,6 @@ export declare const checkJwtToken: (arg: {
25
25
  token: string;
26
26
  expectedUser?: string;
27
27
  expectedService?: string;
28
+ clientIp?: string;
28
29
  }) => ICheckTokenResult;
29
30
  //# sourceMappingURL=jwt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/core/auth/jwt.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,YAAY,CAAC;AAU9D,eAAO,MAAM,sBAAsB,IAAI,CAAC;AASxC,eAAO,MAAM,UAAU,QAAmC,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,MAStC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,cAAc,MAAM,WAW3C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,aAAa,MAAM,EAAE,UAAU,GAAG,KAAG,MAYhF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,KAAK;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,KAAG,iBAqEH,CAAC"}
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/core/auth/jwt.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,YAAY,CAAC;AAY9D,eAAO,MAAM,sBAAsB,IAAI,CAAC;AASxC,eAAO,MAAM,UAAU,QAAmC,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,MAStC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,cAAc,MAAM,WAW3C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,aAAa,MAAM,EAAE,UAAU,GAAG,KAAG,MAYhF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,KAAK;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,KAAG,iBAmFH,CAAC"}
@@ -3,10 +3,12 @@ import crypto from 'crypto';
3
3
  import { appConfig } from '../bootstrap/init-config.js';
4
4
  import { logger as lgr } from '../logger.js';
5
5
  import { isObject, trim } from '../utils/utils.js';
6
+ import { parseIpList, isIpAllowed } from './ip-check.js';
6
7
  import chalk from 'chalk';
7
8
  const logger = lgr.getSubLogger({ name: chalk.cyan('token-auth') });
8
9
  const { jwtToken } = appConfig.webServer?.auth || {};
9
10
  const checkMCPName = jwtToken?.checkMCPName || false;
11
+ const isCheckIP = jwtToken?.isCheckIP || false;
10
12
  export const MIN_ENCRYPT_KEY_LENGTH = 8;
11
13
  const ALGORITHM = 'aes-256-ctr';
12
14
  const KEY = crypto
@@ -68,7 +70,7 @@ export const generateToken = (user, liveTimeSec, payload) => {
68
70
  * - If a user is transferred, it must match
69
71
  */
70
72
  export const checkJwtToken = (arg) => {
71
- let { token, expectedUser, expectedService = appConfig.name } = arg;
73
+ let { token, expectedUser, expectedService = appConfig.name, clientIp } = arg;
72
74
  token = (token || '').trim();
73
75
  if (!token) {
74
76
  return {
@@ -130,6 +132,18 @@ export const checkJwtToken = (arg) => {
130
132
  errorReason: `JWT Token expired :: on ${expiredOn} mc`,
131
133
  };
132
134
  }
135
+ // IP check (after all other validations pass)
136
+ if (isCheckIP && payload.ip) {
137
+ if (clientIp) {
138
+ const allowedIps = parseIpList(payload.ip);
139
+ if (allowedIps.length > 0 && !isIpAllowed(clientIp, allowedIps)) {
140
+ return {
141
+ isTokenDecrypted: true,
142
+ errorReason: `JWT Token: client IP ${clientIp} is not in the allowed list`,
143
+ };
144
+ }
145
+ }
146
+ }
133
147
  // OK!
134
148
  return { payload };
135
149
  };