UNPKG

@gluneau/hive-mcp-server

Version:

An MCP server that enables AI assistants to interact with the Hive blockchain

230 lines 12.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.encryptMessage = encryptMessage; exports.decryptMessage = decryptMessage; exports.sendEncryptedMessage = sendEncryptedMessage; exports.getEncryptedMessages = getEncryptedMessages; // Updated messaging tools implementation with fix for encryption/decryption const dhive_1 = require("@hiveio/dhive"); const client_1 = __importDefault(require("../config/client")); const config_1 = __importDefault(require("../config")); const error_1 = require("../utils/error"); const response_1 = require("../utils/response"); const logger_1 = __importDefault(require("../utils/logger")); // Helper function to get a public memo key for a Hive account function getMemoPublicKey(username) { return __awaiter(this, void 0, void 0, function* () { try { const accounts = yield client_1.default.database.getAccounts([username]); if (accounts.length === 0) { throw new Error(`User ${username} not found`); } return accounts[0].memo_key; } catch (error) { throw new Error(`Error fetching memo key for ${username}: ${error instanceof Error ? error.message : String(error)}`); } }); } // Encrypt a message function encryptMessage(params) { return __awaiter(this, void 0, void 0, function* () { try { // Get credentials from environment variables const senderPrivateKey = config_1.default.hive.memoKey; if (!senderPrivateKey) { return (0, response_1.errorResponse)('Error: HIVE_MEMO_KEY environment variable is not set. Encryption requires your private memo key.'); } // Get recipient's public memo key const recipientPublicKey = yield getMemoPublicKey(params.recipient); // Encrypt message - FIX: prepend # to message since Memo.encode checks for this prefix const encryptedMessage = dhive_1.Memo.encode(dhive_1.PrivateKey.fromString(senderPrivateKey), recipientPublicKey, '#' + params.message // Add the # prefix required by Memo.encode ); return (0, response_1.successJson)({ success: true, recipient: params.recipient, encrypted_message: encryptedMessage, note: "This encrypted message can only be decrypted by the recipient using their private memo key." }); } catch (error) { return (0, response_1.errorResponse)((0, error_1.handleError)(error, 'encrypt_message')); } }); } // Decrypt a message function decryptMessage(params) { return __awaiter(this, void 0, void 0, function* () { try { // Get credentials from environment variables const recipientPrivateKey = config_1.default.hive.memoKey; if (!recipientPrivateKey) { return (0, response_1.errorResponse)('Error: HIVE_MEMO_KEY environment variable is not set. Decryption requires your private memo key.'); } // Get sender's public memo key const senderPublicKey = yield getMemoPublicKey(params.sender); try { // Attempt to decrypt message const decryptedMessage = dhive_1.Memo.decode(dhive_1.PrivateKey.fromString(recipientPrivateKey), params.encrypted_message); // FIX: Remove the # prefix that Memo.decode adds to the decrypted message const cleanMessage = decryptedMessage.startsWith('#') ? decryptedMessage.substring(1) : decryptedMessage; return (0, response_1.successJson)({ success: true, sender: params.sender, decrypted_message: cleanMessage }); } catch (decryptError) { return (0, response_1.errorResponse)(`Failed to decrypt message: ${decryptError instanceof Error ? decryptError.message : String(decryptError)}. This could be because the message was not encrypted for you, or the sender information is incorrect.`); } } catch (error) { return (0, response_1.errorResponse)((0, error_1.handleError)(error, 'decrypt_message')); } }); } // Send an encrypted message (combines encryption with token sending) function sendEncryptedMessage(params) { return __awaiter(this, void 0, void 0, function* () { try { // Get credentials from environment variables const username = config_1.default.hive.username; const activeKey = config_1.default.hive.activeKey; const memoKey = config_1.default.hive.memoKey; if (!username || !activeKey) { return (0, response_1.errorResponse)('Error: HIVE_USERNAME or HIVE_ACTIVE_KEY environment variables are not set. Sending requires an active key.'); } if (!memoKey) { return (0, response_1.errorResponse)('Error: HIVE_MEMO_KEY environment variable is not set. Encryption requires your private memo key.'); } // Get recipient's public memo key const recipientPublicKey = yield getMemoPublicKey(params.recipient); // Encrypt message - FIX: prepend # to message since Memo.encode checks for this prefix const encryptedMessage = dhive_1.Memo.encode(dhive_1.PrivateKey.fromString(memoKey), recipientPublicKey, '#' + params.message // Add the # prefix required by Memo.encode ); // Format the amount with 3 decimal places and append HIVE const formattedAmount = `${params.amount.toFixed(3)} HIVE`; // Create the transfer operation const transfer = { from: username, to: params.recipient, amount: formattedAmount, memo: encryptedMessage, }; // Broadcast the transfer using active key const result = yield client_1.default.broadcast.transfer(transfer, dhive_1.PrivateKey.fromString(activeKey)); return (0, response_1.successJson)({ success: true, transaction_id: result.id, transaction_url: `https://www.hiveblockexplorer.com/tx/${result.id}`, block_num: result.block_num, from: username, to: params.recipient, amount: formattedAmount, encrypted_message: encryptedMessage, }); } catch (error) { return (0, response_1.errorResponse)((0, error_1.handleError)(error, 'send_encrypted_message')); } }); } // Get encrypted messages from account history function getEncryptedMessages(params) { return __awaiter(this, void 0, void 0, function* () { try { // Use the provided username or fall back to the configured username const username = params.username || config_1.default.hive.username; if (!username) { return (0, response_1.errorResponse)('Error: No username provided and HIVE_USERNAME environment variable is not set.'); } // The getAccountHistory method needs a starting point (from) parameter // We'll use -1 to get the most recent transactions const from = -1; // Get account history const history = yield client_1.default.database.getAccountHistory(username, from, params.limit * 3 // Request more than needed to filter for encrypted messages ); if (!history || !Array.isArray(history)) { return (0, response_1.successJson)({ account: params.username, messages_count: 0, messages: [], }); } // Filter for transfer operations with encrypted memos let encryptedMessages = history .filter(([_index, operation]) => { // Only include transfer operations if (operation.op[0] !== 'transfer') return false; const opData = operation.op[1]; // Check if memo starts with '#' (encrypted memos start with '#') return opData.memo && opData.memo.startsWith('#'); }) .map(([index, operation]) => { const { timestamp, trx_id } = operation; const opData = operation.op[1]; // Determine if this is an incoming or outgoing message const direction = opData.to === params.username ? 'received' : 'sent'; const otherParty = direction === 'received' ? opData.from : opData.to; return { index, transaction_id: trx_id, timestamp, direction, counterparty: otherParty, amount: opData.amount, encrypted_message: opData.memo, decrypted_message: null, // Will be populated later if decryption is requested }; }) .slice(0, params.limit); // Limit to requested number of messages // Decrypt messages if requested if (params.decrypt && config_1.default.hive.memoKey) { const memoPrivateKey = dhive_1.PrivateKey.fromString(config_1.default.hive.memoKey); for (let i = 0; i < encryptedMessages.length; i++) { const message = encryptedMessages[i]; try { // Decrypt the message using our private memo key // The memo format already contains the necessary information about the sender/recipient const decryptedWithHash = dhive_1.Memo.decode(memoPrivateKey, message.encrypted_message); // FIX: Remove the # prefix that Memo.decode adds to the decrypted message message.decrypted_message = decryptedWithHash.startsWith('#') ? decryptedWithHash.substring(1) : decryptedWithHash; } catch (decryptError) { logger_1.default.warn(`Failed to decrypt message ${i}: ${decryptError instanceof Error ? decryptError.message : String(decryptError)}`); message.decrypted_message = "[Decryption failed]"; } } } return (0, response_1.successJson)({ account: params.username, messages_count: encryptedMessages.length, messages: encryptedMessages, note: params.decrypt ? "Messages were decrypted using your private memo key" : "Set 'decrypt' parameter to true to attempt decryption of messages" }); } catch (error) { return (0, response_1.errorResponse)((0, error_1.handleError)(error, 'get_encrypted_messages')); } }); } //# sourceMappingURL=messaging.js.map