WebMCP
by jasonjmcghee
Verified
- src
import * as fs from 'fs/promises';
import * as crypto from 'crypto';
import {ENV_FILE, formatChannel, HOST, TOKENS_FILE,CONFIG} from "./config.js";
// Function to generate a secure random token
function generateToken() {
return crypto.randomBytes(16).toString('hex');
}
// Authorized channel-token pairs - Only channels with valid tokens can connect
// Format: { "/channel1": "token123" }
let authorizedTokens = {};
function getToken(channel) {
return authorizedTokens[channel];
}
function setToken(channel, value) {
authorizedTokens[channel] = value;
}
function deleteToken(channel) {
delete authorizedTokens[channel];
}
function clearTokens(channel) {
authorizedTokens = {};
}
// Load authorized tokens from disk
async function loadAuthorizedTokens() {
try {
const data = await fs.readFile(TOKENS_FILE, 'utf8');
authorizedTokens = JSON.parse(data || "{}");
// console.error(`Loaded ${Object.keys(authorizedTokens).length} authorized channel-token pairs from ${TOKENS_FILE}`);
return true;
} catch (error) {
// If file doesn't exist, start with empty tokens
if (error.code === 'ENOENT') {
authorizedTokens = {};
return true;
}
console.error('Error loading authorized tokens:', error);
return false;
}
}
// Save authorized tokens to disk
async function saveAuthorizedTokens() {
try {
// Convert Map to object for JSON serialization
const stringified = JSON.stringify(authorizedTokens, null, 2);
await fs.writeFile(TOKENS_FILE, stringified, 'utf8');
// console.error(`Saved ${stringified} authorized channel-token pairs to ${TOKENS_FILE}`);
return true;
} catch (error) {
console.error('Error saving authorized tokens:', error);
return false;
}
}
// Function to save server token to .env file
async function saveServerTokenToEnv(token) {
try {
let envContent = '';
try {
// Try to read existing .env file
envContent = await fs.readFile(ENV_FILE, 'utf8');
// Check if WEBMCP_SERVER_TOKEN is already defined
if (envContent.includes('WEBMCP_SERVER_TOKEN=')) {
// Replace the existing token
envContent = envContent.replace(/WEBMCP_SERVER_TOKEN=.*(\r?\n|$)/g, `WEBMCP_SERVER_TOKEN=${token}$1`);
} else {
// Add the token to the end
envContent += `\nWEBMCP_SERVER_TOKEN=${token}\n`;
}
} catch (err) {
// File doesn't exist, create new content
envContent = `WEBMCP_SERVER_TOKEN=${token}\n`;
}
// Write the content to the .env file
await fs.writeFile(ENV_FILE, envContent, 'utf8');
console.error(`Server token saved to ${ENV_FILE}`);
return true;
} catch (error) {
console.error('Error saving server token to .env file:', error);
return false;
}
}
async function generateNewRegistrationToken() {
// Generate a random token for registration
const token = generateToken();
// Create a connection object with server address and token
const address = `${HOST}:${CONFIG.port}`;
const serverAddress = `ws://${address}`;
const connectionData = {
server: serverAddress,
token: token
};
// Convert to JSON and base64 encode
const jsonStr = JSON.stringify(connectionData);
const encodedData = Buffer.from(jsonStr).toString('base64');
setToken(formatChannel(address), token);
await saveAuthorizedTokens();
return encodedData;
}
export {generateToken, getToken, setToken, loadAuthorizedTokens, saveAuthorizedTokens, clearTokens, deleteToken, saveServerTokenToEnv, generateNewRegistrationToken};