server-function-hub.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. // server/server-function-hub.js
  2. /**
  3. * Promise-Aware Server Function Hub
  4. * Enhanced to properly handle async functions and Promises
  5. */
  6. const WebSocket = require('ws');
  7. const https = require('https');
  8. const fs = require('fs');
  9. const path = require('path');
  10. require('dotenv').config();
  11. console.log('🚀 SERVER-FUNCTION-HUB STARTING UP...');
  12. console.log('📁 Current working directory:', process.cwd());
  13. console.log('🔧 Node version:', process.version);
  14. // Import security helpers
  15. console.log('🔐 Attempting to import security helpers...');
  16. try {
  17. const { processAllEncryptedData } = require('./security-helpers');
  18. console.log('✅ Security helpers imported successfully');
  19. console.log('🔍 processAllEncryptedData function:', typeof processAllEncryptedData);
  20. } catch (error) {
  21. console.log('❌ FAILED to import security helpers:', error.message);
  22. console.log('📍 Error stack:', error.stack);
  23. process.exit(1);
  24. }
  25. // Configuration
  26. const WS_PORT = process.env.WS_PORT || 8080;
  27. const SSL_PREFIX = process.env.SSL_PREFIX || '/etc/letsencrypt/live/';
  28. const DOMAIN = process.env.DOMAIN || 'tuvme.xyz';
  29. console.log('⚙️ Configuration loaded:');
  30. console.log(' WS_PORT:', WS_PORT);
  31. console.log(' DOMAIN:', DOMAIN);
  32. console.log(' SSL_PREFIX:', SSL_PREFIX);
  33. // SSL Certificate paths
  34. const SSL_KEY_PATH = process.env.SSL_KEY_PATH || path.join(SSL_PREFIX, DOMAIN, 'privkey.pem');
  35. const SSL_CERT_PATH = process.env.SSL_CERT_PATH || path.join(SSL_PREFIX, DOMAIN, 'fullchain.pem');
  36. console.log('🔑 SSL Certificate paths:');
  37. console.log(' KEY:', SSL_KEY_PATH);
  38. console.log(' CERT:', SSL_CERT_PATH);
  39. // Check if SSL files exist
  40. console.log('🔍 Checking SSL files...');
  41. try {
  42. fs.accessSync(SSL_KEY_PATH);
  43. console.log('✅ SSL Key file exists');
  44. } catch (error) {
  45. console.log('❌ SSL Key file missing:', SSL_KEY_PATH);
  46. }
  47. try {
  48. fs.accessSync(SSL_CERT_PATH);
  49. console.log('✅ SSL Cert file exists');
  50. } catch (error) {
  51. console.log('❌ SSL Cert file missing:', SSL_CERT_PATH);
  52. }
  53. /**
  54. * Enhanced logging function
  55. */
  56. function log(label, data = null) {
  57. const timestamp = new Date().toISOString();
  58. console.log(`[${timestamp}] [SERVER-FUNCTION-HUB] ${label}`);
  59. if (data) {
  60. console.log(JSON.stringify(data, null, 2));
  61. }
  62. }
  63. /**
  64. * In-memory store for functions
  65. */
  66. const functionStore = new Map();
  67. console.log('📦 Function store initialized');
  68. /**
  69. * Stats
  70. */
  71. const stats = {
  72. totalConnections: 0,
  73. activeConnections: 0,
  74. registrations: 0,
  75. executions: 0,
  76. errors: 0
  77. };
  78. console.log('📊 Stats initialized:', stats);
  79. /**
  80. * Register a function or code snippet
  81. */
  82. function registerFunction(functionId, functionBody, paramNames = []) {
  83. console.log('🔧 REGISTERING FUNCTION:', functionId);
  84. console.log('📝 Function body length:', functionBody.length);
  85. console.log('📋 Parameter names:', paramNames);
  86. stats.registrations++;
  87. // Log full function body without any truncation
  88. log(`======= REGISTERING FUNCTION: ${functionId} =======`);
  89. console.log("FUNCTION BODY BEGIN:");
  90. console.log(functionBody);
  91. console.log("FUNCTION BODY END");
  92. log(`========================================`);
  93. // Store the code info without any validation
  94. functionStore.set(functionId, {
  95. body: functionBody,
  96. params: paramNames
  97. });
  98. console.log('✅ Function stored in functionStore');
  99. console.log('📊 Total functions in store:', functionStore.size);
  100. console.log('🔍 Function store keys:', Array.from(functionStore.keys()));
  101. log(`Code successfully registered: ${functionId}`);
  102. return true;
  103. }
  104. /**
  105. * Helper function to check if a value is a Promise or Promise-like
  106. */
  107. function isPromiseLike(value) {
  108. const result = value && typeof value.then === 'function';
  109. console.log('🔍 isPromiseLike check:', typeof value, '→', result);
  110. return result;
  111. }
  112. /**
  113. * Execute registered function
  114. */
  115. async function executeFunction(functionId, args = []) {
  116. console.log('🚀 EXECUTE FUNCTION CALLED');
  117. console.log('🔍 Function ID:', functionId);
  118. console.log('📊 Arguments count:', args.length);
  119. console.log('📋 Arguments:', args);
  120. stats.executions++;
  121. log(`======= EXECUTING FUNCTION: ${functionId} =======`);
  122. log(`Raw Arguments:`, args);
  123. console.log('🔍 Checking if function exists in store...');
  124. console.log('📦 Current function store size:', functionStore.size);
  125. console.log('🔑 Available function IDs:', Array.from(functionStore.keys()));
  126. console.log('🎯 Looking for:', functionId);
  127. console.log('✅ Function exists?', functionStore.has(functionId));
  128. if (!functionStore.has(functionId)) {
  129. console.log('❌ FUNCTION NOT FOUND!');
  130. log(`Code not found: ${functionId}`);
  131. const error = new Error(`Code not found: ${functionId}`);
  132. console.log('💥 Error object created:', error.message);
  133. throw error;
  134. }
  135. console.log('✅ Function found in store, proceeding with execution...');
  136. try {
  137. const funcInfo = functionStore.get(functionId);
  138. console.log('📝 Retrieved function info:', {
  139. bodyLength: funcInfo.body.length,
  140. params: funcInfo.params
  141. });
  142. console.log('🔐 Starting encryption processing...');
  143. // NEW: Process and decrypt both function body and arguments
  144. const { processAllEncryptedData } = require('./security-helpers');
  145. console.log('🔍 processAllEncryptedData function type:', typeof processAllEncryptedData);
  146. console.log('🔄 Processing encrypted data...');
  147. const { processedBody, processedArgs } = processAllEncryptedData(funcInfo.body, args);
  148. console.log('✅ Encryption processing complete');
  149. // Log the processed arguments for debugging
  150. console.log('🔐 PROCESSED ARGS COMPARISON:');
  151. console.log(' Original args:', args);
  152. console.log(' Processed args:', processedArgs);
  153. log(`PROCESSED ARGS:`, processedArgs);
  154. // Log full stored function body
  155. log(`EXECUTING THIS EXACT CODE:`);
  156. console.log(processedBody);
  157. log(`========================================`);
  158. console.log('🏗️ Creating execution context...');
  159. // Create execution context
  160. const executeCode = (code, processedArgs) => {
  161. console.log('🔧 executeCode function called');
  162. console.log('📝 Code length:', code.length);
  163. console.log('📋 Args:', processedArgs);
  164. // Create a safe execution context with allowed Node.js modules
  165. const vm = require('vm');
  166. console.log('📦 VM module loaded');
  167. const sandbox = {
  168. require,
  169. process,
  170. console,
  171. Buffer,
  172. setTimeout,
  173. clearTimeout,
  174. setInterval,
  175. clearInterval,
  176. setImmediate,
  177. clearImmediate,
  178. args: processedArgs, // Use decrypted arguments
  179. Promise // Explicit Promise reference
  180. };
  181. console.log('🏗️ Sandbox created with keys:', Object.keys(sandbox));
  182. console.log('📋 Sandbox args:', sandbox.args);
  183. // Create context and run code
  184. const context = vm.createContext(sandbox);
  185. console.log('🌍 VM context created');
  186. // FIXED: Instead of double-wrapping in IIFEs, check if the code is already
  187. // returning a Promise or has an async function signature.
  188. // If the code appears to be async, we'll just run it directly.
  189. let codeToRun = code;
  190. console.log('🔍 Analyzing code structure...');
  191. // Check if code appears to be an async IIFE already
  192. const isAsyncIIFE = /^\s*\(?\s*async\s+function/.test(code) ||
  193. code.includes('new Promise');
  194. console.log('🔍 Code analysis results:');
  195. console.log(' isAsyncIIFE:', isAsyncIIFE);
  196. console.log(' contains async function:', /^\s*\(?\s*async\s+function/.test(code));
  197. console.log(' contains Promise:', code.includes('new Promise'));
  198. // If not an async IIFE already, but is a plain function or statement, wrap it
  199. if (!isAsyncIIFE) {
  200. console.log('🔧 Code is not an async IIFE, wrapping in function...');
  201. log(`Code is not an async IIFE, wrapping in function...`);
  202. codeToRun = `(function() { ${code} })()`;
  203. } else {
  204. console.log('✅ Code appears to be async/Promise-based, executing as-is');
  205. log(`Code appears to be async/Promise-based, executing as-is`);
  206. }
  207. log(`EXECUTING FINAL CODE:`);
  208. console.log('🚀 FINAL CODE TO EXECUTE:');
  209. console.log(codeToRun);
  210. console.log('⚡ Running code in VM context...');
  211. // Execute the code
  212. const result = vm.runInContext(codeToRun, context);
  213. console.log('✅ Code execution completed');
  214. console.log('🔍 Raw result type:', typeof result);
  215. console.log('📊 Raw result:', result);
  216. log(`Raw execution result type: ${typeof result}`);
  217. return result;
  218. };
  219. console.log('🎯 Calling executeCode...');
  220. // Execute the code with the processed arguments
  221. let result = executeCode(processedBody, processedArgs);
  222. console.log('📊 Execution result received:', typeof result);
  223. // Log the result type
  224. log(`EXECUTION RESULT TYPE: ${typeof result}`);
  225. // If result is a Promise or Promise-like, await it
  226. if (isPromiseLike(result)) {
  227. console.log('⏳ Result is Promise-like, awaiting...');
  228. log(`DETECTED PROMISE RESULT - AWAITING...`);
  229. try {
  230. console.log('⏳ Starting Promise resolution...');
  231. result = await result;
  232. console.log('✅ Promise resolved successfully');
  233. console.log('📊 Final resolved result:', result);
  234. log(`PROMISE RESOLVED TO:`, result);
  235. } catch (promiseError) {
  236. console.log('💥 Promise rejected with error:', promiseError);
  237. log(`PROMISE REJECTION:`, {
  238. error: promiseError.message,
  239. stack: promiseError.stack
  240. });
  241. throw promiseError;
  242. }
  243. } else {
  244. console.log('✅ Result is not a Promise, using directly');
  245. log(`EXECUTION RESULT (NOT A PROMISE):`, result);
  246. }
  247. console.log('🎉 Function execution completed successfully');
  248. console.log('📊 Final result:', result);
  249. return result;
  250. } catch (error) {
  251. console.log('💥 ERROR in executeFunction:', error);
  252. console.log('📍 Error message:', error.message);
  253. console.log('📍 Error stack:', error.stack);
  254. stats.errors++;
  255. log(`ERROR EXECUTING CODE: ${functionId}`, {
  256. errorType: error.constructor.name,
  257. errorMessage: error.message,
  258. errorStack: error.stack
  259. });
  260. throw error;
  261. }
  262. }
  263. /**
  264. * Start the WebSocket server
  265. */
  266. function startServer() {
  267. console.log('🌐 Starting WebSocket server...');
  268. console.log('🔑 Creating HTTPS server...');
  269. const server = https.createServer({
  270. key: fs.readFileSync(SSL_KEY_PATH),
  271. cert: fs.readFileSync(SSL_CERT_PATH)
  272. });
  273. console.log('✅ HTTPS server created');
  274. console.log('🔌 Creating WebSocket server...');
  275. const wss = new WebSocket.Server({
  276. server,
  277. path: '/ws'
  278. });
  279. console.log('✅ WebSocket server created');
  280. wss.on('connection', (ws, req) => {
  281. console.log('🔗 New WebSocket connection received');
  282. stats.totalConnections++;
  283. stats.activeConnections++;
  284. const connectionId = `conn-${Date.now()}-${stats.totalConnections}`;
  285. console.log('🆔 Connection ID:', connectionId);
  286. console.log('🌍 Client IP:', req.socket.remoteAddress);
  287. console.log('📊 Connection stats:', {
  288. total: stats.totalConnections,
  289. active: stats.activeConnections
  290. });
  291. log(`New connection: ${connectionId}`, { ip: req.socket.remoteAddress });
  292. ws.on('message', async (message) => {
  293. console.log('📨 Message received from client');
  294. console.log('📝 Message length:', message.length);
  295. try {
  296. console.log('🔍 Parsing JSON message...');
  297. const data = JSON.parse(message);
  298. console.log('✅ JSON parsed successfully');
  299. console.log('📊 Message data:', data);
  300. log(`Received message:`, data);
  301. const requestId = data.requestId || 'unknown';
  302. console.log('🆔 Request ID:', requestId);
  303. // Handle function registration
  304. if (data.type === 'register') {
  305. console.log('📝 REGISTRATION REQUEST received');
  306. const { functionId, functionBody, paramNames = [] } = data;
  307. console.log('📋 Registration details:');
  308. console.log(' Function ID:', functionId);
  309. console.log(' Body length:', functionBody?.length);
  310. console.log(' Param names:', paramNames);
  311. log(`Processing code registration: ${functionId}`);
  312. console.log('🔧 Calling registerFunction...');
  313. const success = registerFunction(functionId, functionBody, paramNames);
  314. console.log('📊 Registration result:', success);
  315. console.log('📤 Sending registration response...');
  316. const response = {
  317. requestId,
  318. status: 'ok',
  319. result: { registered: success }
  320. };
  321. console.log('📋 Response:', response);
  322. ws.send(JSON.stringify(response));
  323. console.log('✅ Registration response sent');
  324. }
  325. // Handle function execution
  326. else if (data.type === 'execute') {
  327. console.log('🚀 EXECUTION REQUEST received');
  328. const { functionId, args = [] } = data;
  329. console.log('📋 Execution details:');
  330. console.log(' Function ID:', functionId);
  331. console.log(' Args count:', args.length);
  332. console.log(' Args:', args);
  333. log(`Processing code execution: ${functionId}`);
  334. try {
  335. console.log('⚡ Starting function execution...');
  336. // Now executeFunction is async and will properly await Promises
  337. // It also handles encrypted argument decryption
  338. const result = await executeFunction(functionId, args);
  339. console.log('✅ Function execution completed');
  340. console.log('📊 Execution result:', result);
  341. log(`Final result to send for ${requestId}:`, result);
  342. console.log('📤 Sending execution response...');
  343. const response = {
  344. requestId,
  345. result,
  346. markerId: data.markerId
  347. };
  348. console.log('📋 Response:', response);
  349. ws.send(JSON.stringify(response));
  350. console.log('✅ Execution response sent');
  351. } catch (execError) {
  352. console.log('💥 EXECUTION ERROR:', execError);
  353. console.log('📍 Error message:', execError.message);
  354. console.log('📍 Error stack:', execError.stack);
  355. log(`Error executing code:`, { error: execError.message, stack: execError.stack });
  356. console.log('📤 Sending error response...');
  357. const errorResponse = { requestId, error: execError.message };
  358. console.log('📋 Error response:', errorResponse);
  359. ws.send(JSON.stringify(errorResponse));
  360. console.log('✅ Error response sent');
  361. }
  362. }
  363. // Unknown message type
  364. else {
  365. console.log('❓ Unknown message type:', data.type);
  366. log(`Unknown message type received`, { type: data.type });
  367. const errorResponse = { requestId, error: `Unknown message type: ${data.type}` };
  368. ws.send(JSON.stringify(errorResponse));
  369. }
  370. } catch (error) {
  371. console.log('💥 MESSAGE PROCESSING ERROR:', error);
  372. console.log('📍 Error message:', error.message);
  373. console.log('📍 Raw message:', message.toString().substring(0, 200));
  374. log(`Error processing message:`, { error: error.message, message: message.toString().substring(0, 200) });
  375. stats.errors++;
  376. try {
  377. console.log('📤 Sending generic error response...');
  378. ws.send(JSON.stringify({ error: error.message }));
  379. console.log('✅ Generic error response sent');
  380. } catch (sendError) {
  381. console.log('💥 Error sending error response:', sendError);
  382. log(`Error sending error response:`, { error: sendError.message });
  383. }
  384. }
  385. });
  386. ws.on('close', () => {
  387. console.log('🔌 WebSocket connection closed:', connectionId);
  388. stats.activeConnections--;
  389. console.log('📊 Updated connection stats:', {
  390. total: stats.totalConnections,
  391. active: stats.activeConnections
  392. });
  393. log(`Connection closed: ${connectionId}`);
  394. });
  395. console.log('📤 Sending welcome message...');
  396. const welcomeMessage = {
  397. type: 'system',
  398. message: 'Secure WebSocket server connected',
  399. connectionId,
  400. timestamp: new Date().toISOString()
  401. };
  402. console.log('📋 Welcome message:', welcomeMessage);
  403. ws.send(JSON.stringify(welcomeMessage));
  404. console.log('✅ Welcome message sent');
  405. });
  406. console.log('🎧 Starting server listener...');
  407. server.listen(WS_PORT, () => {
  408. console.log('🎉 SERVER IS LIVE!');
  409. console.log('🌐 Listening on port:', WS_PORT);
  410. console.log('🔗 WebSocket path: /ws');
  411. console.log('🔒 SSL enabled: YES');
  412. log(`Server listening on port ${WS_PORT}`);
  413. });
  414. console.log('✅ Server startup complete');
  415. return wss;
  416. }
  417. // Register a test function
  418. console.log('🧪 Registering test function...');
  419. registerFunction('test', 'return "Hello, World!";', []);
  420. console.log('✅ Test function registered');
  421. // Start server when run directly
  422. if (require.main === module) {
  423. console.log('🚀 Starting server in standalone mode...');
  424. log('Starting server...');
  425. startServer();
  426. console.log('🎉 Server startup initiated!');
  427. }
  428. // Export functions
  429. console.log('📤 Exporting module functions...');
  430. module.exports = {
  431. startServer,
  432. registerFunction,
  433. executeFunction
  434. };
  435. console.log('✅ Module exports ready');
  436. console.log('🎉 SERVER-FUNCTION-HUB INITIALIZATION COMPLETE!');