crawlforge-mcp-server 3.0.11 → 3.0.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crawlforge-mcp-server",
3
- "version": "3.0.11",
3
+ "version": "3.0.12",
4
4
  "description": "CrawlForge MCP Server - Professional Model Context Protocol server with 19 comprehensive web scraping, crawling, and content processing tools.",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -8,20 +8,33 @@ import dotenv from 'dotenv';
8
8
  // Load .env file early to check for creator secret
9
9
  dotenv.config({ path: '.env', quiet: true });
10
10
 
11
+ // SECURITY: Clear any externally-set creator mode env var to prevent bypass
12
+ delete process.env.CRAWLFORGE_CREATOR_MODE;
13
+
11
14
  const CREATOR_SECRET_HASH = 'cfef62e5068d48e7dd6a39c9e16f0be2615510c6b68274fc8abe3156feb5050b';
12
15
 
16
+ // Module-scoped flag - cannot be set externally
17
+ let _creatorModeVerified = false;
18
+
13
19
  if (process.env.CRAWLFORGE_CREATOR_SECRET) {
14
20
  const providedHash = crypto
15
21
  .createHash('sha256')
16
22
  .update(process.env.CRAWLFORGE_CREATOR_SECRET)
17
23
  .digest('hex');
18
24
 
19
- if (providedHash === CREATOR_SECRET_HASH) {
20
- process.env.CRAWLFORGE_CREATOR_MODE = 'true';
25
+ if (crypto.timingSafeEqual(Buffer.from(providedHash, 'hex'), Buffer.from(CREATOR_SECRET_HASH, 'hex'))) {
26
+ _creatorModeVerified = true;
21
27
  console.log('🔓 Creator Mode Enabled - Unlimited Access');
22
28
  } else {
23
29
  console.warn('⚠️ Invalid creator secret provided');
24
30
  }
31
+ // Clean up the secret from environment
32
+ delete process.env.CRAWLFORGE_CREATOR_SECRET;
33
+ }
34
+
35
+ // Export getter for AuthManager to use
36
+ export function isCreatorModeVerified() {
37
+ return _creatorModeVerified;
25
38
  }
26
39
 
27
40
  // Now import everything else
@@ -6,6 +6,7 @@
6
6
  // Using native fetch (Node.js 18+)
7
7
  import fs from 'fs/promises';
8
8
  import path from 'path';
9
+ import { isCreatorModeVerified } from '../../server.js';
9
10
 
10
11
  class AuthManager {
11
12
  constructor() {
@@ -21,10 +22,10 @@ class AuthManager {
21
22
 
22
23
  /**
23
24
  * Check if running in creator mode (unlimited access, no API required)
24
- * Reads from environment variable dynamically to ensure proper initialization order
25
+ * Uses module-scoped verified flag from server.js - cannot be bypassed via env vars
25
26
  */
26
27
  isCreatorMode() {
27
- return process.env.CRAWLFORGE_CREATOR_MODE === 'true';
28
+ return isCreatorModeVerified();
28
29
  }
29
30
 
30
31
  /**
@@ -83,8 +84,8 @@ class AuthManager {
83
84
  const configDir = path.dirname(this.configPath);
84
85
  await fs.mkdir(configDir, { recursive: true });
85
86
 
86
- // Save config
87
- await fs.writeFile(this.configPath, JSON.stringify(config, null, 2));
87
+ // Save config with owner-only permissions (contains API key)
88
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), { mode: 0o600 });
88
89
  this.config = config;
89
90
  }
90
91
 
@@ -183,7 +184,8 @@ class AuthManager {
183
184
  const response = await fetch(`${this.apiEndpoint}/api/v1/credits`, {
184
185
  headers: {
185
186
  'X-API-Key': this.config.apiKey
186
- }
187
+ },
188
+ signal: AbortSignal.timeout(5000)
187
189
  });
188
190
 
189
191
  if (response.ok) {
@@ -193,11 +195,19 @@ class AuthManager {
193
195
  return data.creditsRemaining >= estimatedCredits;
194
196
  }
195
197
  } catch (error) {
196
- // If can't check, allow operation but log error
197
198
  console.error('Failed to check credits:', error.message);
198
- }
199
199
 
200
- return true; // Allow operation if can't verify
200
+ // Grace period: allow stale cached credits during transient network failures
201
+ // This prevents outages from blocking authenticated users while still
202
+ // failing closed when there's no cached data (no free usage bypass)
203
+ const cached = this.creditCache.get(this.config.userId);
204
+ if (cached !== undefined && cached >= estimatedCredits) {
205
+ console.warn('Using cached credits due to network error — will re-verify on next call');
206
+ return true;
207
+ }
208
+
209
+ throw new Error('Unable to verify credits. Please check your connection and try again.');
210
+ }
201
211
  }
202
212
 
203
213
  /**
@@ -5,6 +5,7 @@ import { QueryExpander } from './queryExpander.js';
5
5
  import { ResultRanker } from './ranking/ResultRanker.js';
6
6
  import { ResultDeduplicator } from './ranking/ResultDeduplicator.js';
7
7
  import LocalizationManager from '../../core/LocalizationManager.js';
8
+ import { isCreatorModeVerified } from '../../../server.js';
8
9
 
9
10
  const SearchWebSchema = z.object({
10
11
  query: z.string().min(1),
@@ -73,7 +74,7 @@ export class SearchWebTool {
73
74
  } = options;
74
75
 
75
76
  // Check for Creator Mode - allows search without API key for development/testing
76
- const isCreatorMode = process.env.CRAWLFORGE_CREATOR_MODE === 'true';
77
+ const isCreatorMode = isCreatorModeVerified();
77
78
 
78
79
  if (!apiKey && !isCreatorMode) {
79
80
  throw new Error('CrawlForge API key is required for search functionality');