//+------------------------------------------------------------------+ //| ZoloBridge.mqh | //| Copyright 2024, GenX Solutions | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, GenX Solutions" #property strict #ifndef ZOLO_BRIDGE_MQH #define ZOLO_BRIDGE_MQH //+------------------------------------------------------------------+ //| Helper: Sanitize JSON String | //+------------------------------------------------------------------+ string Zolo_SanitizeJsonString(string text) { string sanitized_result = text; // Replace backslash first to avoid double escaping StringReplace(sanitized_result, "\\", "\\\\"); StringReplace(sanitized_result, "\"", "\\\""); StringReplace(sanitized_result, "\n", " "); StringReplace(sanitized_result, "\r", " "); StringReplace(sanitized_result, "\t", " "); return sanitized_result; } //+------------------------------------------------------------------+ //| Helper: Encrypt String (AES-256 + Base64) | //+------------------------------------------------------------------+ string Zolo_EncryptWithAES256(string text, string key) { if (key == "") return text; uchar data[]; StringToCharArray(text, data, 0, WHOLE_ARRAY, CP_UTF8); if(ArraySize(data) > 0) ArrayResize(data, ArraySize(data)-1); // Remove null uchar keyData[]; StringToCharArray(key, keyData, 0, WHOLE_ARRAY, CP_UTF8); if(ArraySize(keyData) > 0) ArrayResize(keyData, ArraySize(keyData)-1); // Hash key to ensure 32 bytes for AES-256 uchar keyHash[]; uchar empty[]; CryptEncode(CRYPT_HASH_SHA256, keyData, empty, keyHash); uchar encrypted_result[]; int encode_result = CryptEncode(CRYPT_AES256, data, keyHash, encrypted_result); if (encode_result <= 0) { Print("ZoloBridge: Encryption failed. Error: ", GetLastError()); return ""; } // Base64 encode uchar b64Data[]; CryptEncode(CRYPT_BASE64, encrypted_result, empty, b64Data); string base64_encoded = CharArrayToString(b64Data); return base64_encoded; } //+------------------------------------------------------------------+ //| ZOLO Bridge Function | //+------------------------------------------------------------------+ void SendSignalToBridge(string message, bool enable, string url, string key="") { if (!enable || url == "") return; string final_message = message; if(key != "") { final_message = Zolo_EncryptWithAES256(message, key); // If encryption fails (returns empty), we might want to abort or send plaintext. // For security, aborting is better. if(final_message == "") return; } string sanitized_message = Zolo_SanitizeJsonString(final_message); string body = "{\"event\":\"signal\",\"message\":\"" + sanitized_message + "\"}"; char data[]; int len = StringToCharArray(body, data, 0, WHOLE_ARRAY, CP_UTF8); if (len > 0) ArrayResize(data, len - 1); // Remove null terminator char result[]; string result_headers; string headers = "Content-Type: application/json"; int response_code = WebRequest("POST", url, headers, 5000, data, result, result_headers); if (response_code != 200) { // Only print on failure to reduce log noise PrintFormat("ZOLO WebRequest failed. Code: %d. URL: %s", response_code, url); if(response_code == -1) Print("Error: ", GetLastError()); } } #endif // ZOLO_BRIDGE_MQH