2026-01-22 01:08:24 +00:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ZoloBridge.mqh |
|
|
|
|
|
//| Copyright 2024, GenX Solutions |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#property copyright "Copyright 2024, GenX Solutions"
|
|
|
|
|
#property strict
|
|
|
|
|
|
2026-01-22 01:39:56 +00:00
|
|
|
#ifndef ZOLO_BRIDGE_MQH
|
|
|
|
|
#define ZOLO_BRIDGE_MQH
|
|
|
|
|
|
2026-01-22 01:08:24 +00:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Helper: Sanitize JSON String |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-02-15 05:01:53 +00:00
|
|
|
string Zolo_SanitizeJsonString(string text)
|
2026-01-22 01:08:24 +00:00
|
|
|
{
|
2026-02-15 05:01:53 +00:00
|
|
|
string sanitized_result = text;
|
2026-01-22 01:08:24 +00:00
|
|
|
// Replace backslash first to avoid double escaping
|
2026-02-15 05:01:53 +00:00
|
|
|
StringReplace(sanitized_result, "\\", "\\\\");
|
|
|
|
|
StringReplace(sanitized_result, "\"", "\\\"");
|
|
|
|
|
StringReplace(sanitized_result, "\n", " ");
|
|
|
|
|
StringReplace(sanitized_result, "\r", " ");
|
|
|
|
|
StringReplace(sanitized_result, "\t", " ");
|
|
|
|
|
return sanitized_result;
|
2026-01-22 01:08:24 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-28 07:20:11 +00:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Helper: Encrypt String (AES-256 + Base64) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-02-15 05:01:53 +00:00
|
|
|
string Zolo_EncryptWithAES256(string text, string key)
|
2026-01-28 07:20:11 +00:00
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
2026-02-15 05:01:53 +00:00
|
|
|
uchar encrypted_result[];
|
|
|
|
|
int encode_result = CryptEncode(CRYPT_AES256, data, keyHash, encrypted_result);
|
2026-01-28 07:20:11 +00:00
|
|
|
|
2026-02-15 05:01:53 +00:00
|
|
|
if (encode_result <= 0)
|
2026-01-28 07:20:11 +00:00
|
|
|
{
|
|
|
|
|
Print("ZoloBridge: Encryption failed. Error: ", GetLastError());
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Base64 encode
|
|
|
|
|
uchar b64Data[];
|
2026-02-15 05:01:53 +00:00
|
|
|
CryptEncode(CRYPT_BASE64, encrypted_result, empty, b64Data);
|
|
|
|
|
string base64_encoded = CharArrayToString(b64Data);
|
2026-01-28 07:20:11 +00:00
|
|
|
|
2026-02-15 05:01:53 +00:00
|
|
|
return base64_encoded;
|
2026-01-28 07:20:11 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-22 01:08:24 +00:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ZOLO Bridge Function |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-02-15 05:01:53 +00:00
|
|
|
void SendSignalToBridge(string message, bool enable, string url, string key="")
|
2026-01-22 01:08:24 +00:00
|
|
|
{
|
|
|
|
|
if (!enable || url == "") return;
|
|
|
|
|
|
2026-02-15 05:01:53 +00:00
|
|
|
string final_message = message;
|
2026-01-28 07:20:11 +00:00
|
|
|
if(key != "")
|
|
|
|
|
{
|
2026-02-15 05:01:53 +00:00
|
|
|
final_message = Zolo_EncryptWithAES256(message, key);
|
2026-01-28 07:20:11 +00:00
|
|
|
// If encryption fails (returns empty), we might want to abort or send plaintext.
|
|
|
|
|
// For security, aborting is better.
|
2026-02-15 05:01:53 +00:00
|
|
|
if(final_message == "") return;
|
2026-01-28 07:20:11 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-15 05:01:53 +00:00
|
|
|
string sanitized_message = Zolo_SanitizeJsonString(final_message);
|
|
|
|
|
string body = "{\"event\":\"signal\",\"message\":\"" + sanitized_message + "\"}";
|
2026-01-22 01:08:24 +00:00
|
|
|
|
|
|
|
|
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";
|
|
|
|
|
|
2026-02-15 05:01:53 +00:00
|
|
|
int response_code = WebRequest("POST", url, headers, 5000, data, result, result_headers);
|
2026-01-22 01:08:24 +00:00
|
|
|
|
2026-02-15 05:01:53 +00:00
|
|
|
if (response_code != 200)
|
2026-01-22 01:08:24 +00:00
|
|
|
{
|
|
|
|
|
// Only print on failure to reduce log noise
|
2026-02-15 05:01:53 +00:00
|
|
|
PrintFormat("ZOLO WebRequest failed. Code: %d. URL: %s", response_code, url);
|
|
|
|
|
if(response_code == -1) Print("Error: ", GetLastError());
|
2026-01-22 01:08:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-22 01:39:56 +00:00
|
|
|
|
|
|
|
|
#endif // ZOLO_BRIDGE_MQH
|