messenger-proxy 0.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. builder/__init__.py +0 -0
  2. builder/clients/__init__.py +0 -0
  3. builder/clients/csharp/MessengerClient/App.config +14 -0
  4. builder/clients/csharp/MessengerClient/Crypto.cs +85 -0
  5. builder/clients/csharp/MessengerClient/HTTPMessengerClient.cs +173 -0
  6. builder/clients/csharp/MessengerClient/Message.cs +410 -0
  7. builder/clients/csharp/MessengerClient/MessengerClient.cs +188 -0
  8. builder/clients/csharp/MessengerClient/MessengerClient.csproj +62 -0
  9. builder/clients/csharp/MessengerClient/MessengerClient.sln +25 -0
  10. builder/clients/csharp/MessengerClient/Program.cs +171 -0
  11. builder/clients/csharp/MessengerClient/Properties/AssemblyInfo.cs +36 -0
  12. builder/clients/csharp/MessengerClient/RemotePortForwarder.cs +86 -0
  13. builder/clients/csharp/MessengerClient/WebsocketMessengerClient.cs +218 -0
  14. builder/clients/csharp/README.md +41 -0
  15. builder/clients/nodejs/README.md +127 -0
  16. builder/clients/nodejs/builder.py +60 -0
  17. builder/clients/nodejs/electron +39 -0
  18. builder/clients/nodejs/requirements.txt +1 -0
  19. builder/clients/nodejs/templates/messenger-client.js +751 -0
  20. builder/clients/nodejs/webpack.conf.js +50 -0
  21. builder/clients/python/README.md +143 -0
  22. builder/clients/python/builder.py +70 -0
  23. builder/clients/python/messenger-client-http.py +746 -0
  24. builder/clients/python/messenger-client-ws.py +478 -0
  25. builder/clients/python/messenger-client.py +959 -0
  26. builder/clients/python/requirements.txt +1 -0
  27. builder/clients/python/templates/messenger-client.py +896 -0
  28. messenger/__init__.py +10 -0
  29. messenger/aes.py +20 -0
  30. messenger/convert.py +21 -0
  31. messenger/engine.py +76 -0
  32. messenger/forwarder_clients.py +186 -0
  33. messenger/forwarders.py +331 -0
  34. messenger/generator.py +60 -0
  35. messenger/http_ws_server.py +134 -0
  36. messenger/manager.py +737 -0
  37. messenger/message.py +267 -0
  38. messenger/messengers.py +226 -0
  39. messenger/output.py +31 -0
  40. messenger/resources/top_ports.txt +8320 -0
  41. messenger/scanner.py +179 -0
  42. messenger/text.py +35 -0
  43. messenger_proxy-0.4.1.data/scripts/messenger-builder +111 -0
  44. messenger_proxy-0.4.1.data/scripts/messenger-cli +30 -0
  45. messenger_proxy-0.4.1.dist-info/METADATA +109 -0
  46. messenger_proxy-0.4.1.dist-info/RECORD +49 -0
  47. messenger_proxy-0.4.1.dist-info/WHEEL +5 -0
  48. messenger_proxy-0.4.1.dist-info/licenses/LICENSE +28 -0
  49. messenger_proxy-0.4.1.dist-info/top_level.txt +2 -0
builder/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <configuration>
3
+ <startup>
4
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
5
+ </startup>
6
+ <runtime>
7
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
8
+ <dependentAssembly>
9
+ <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
10
+ <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
11
+ </dependentAssembly>
12
+ </assemblyBinding>
13
+ </runtime>
14
+ </configuration>
@@ -0,0 +1,85 @@
1
+ using System;
2
+ using System.Linq;
3
+ using System.Text;
4
+ using System.Security.Cryptography;
5
+
6
+
7
+ namespace MessengerClient
8
+ {
9
+ internal class Crypto
10
+ {
11
+ private const int AesBlockByteSize = 128 / 8;
12
+ private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create();
13
+
14
+ public static byte[] Hash(string encryption_key)
15
+ {
16
+ using (SHA256 sha256 = SHA256.Create())
17
+ {
18
+ return sha256.ComputeHash(Encoding.ASCII.GetBytes(encryption_key));
19
+ }
20
+ }
21
+
22
+ public static byte[] Encrypt(byte[] key, ArraySegment<byte> plainText)
23
+ {
24
+ byte[] plainTextBytes = plainText.Array;
25
+ return Encrypt(key, plainTextBytes);
26
+ }
27
+
28
+ public static byte[] Encrypt(byte[] key, string plainText)
29
+ {
30
+ byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
31
+ return Encrypt(key, plainTextBytes);
32
+ }
33
+
34
+ public static byte[] Encrypt(byte[] key, byte[] plainText)
35
+ {
36
+ using (var aes = Aes.Create())
37
+ {
38
+
39
+ byte[] iv = GenerateRandomBytes(AesBlockByteSize);
40
+
41
+ using (var encryptor = aes.CreateEncryptor(key, iv))
42
+ {
43
+ var cipherText = encryptor
44
+ .TransformFinalBlock(plainText, 0, plainText.Length);
45
+
46
+ var result = MergeArrays(iv, cipherText);
47
+ return result;
48
+ }
49
+ }
50
+ }
51
+
52
+ public static byte[] Decrypt(byte[] key, byte[] encryptedData)
53
+ {
54
+ using (var aes = Aes.Create())
55
+ {
56
+ var iv = encryptedData.Take(AesBlockByteSize).ToArray();
57
+ var cipherText = encryptedData.Skip(AesBlockByteSize).ToArray();
58
+
59
+ using (var encryptor = aes.CreateDecryptor(key, iv))
60
+ {
61
+ return encryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);
62
+ }
63
+ }
64
+ }
65
+
66
+ private static byte[] GenerateRandomBytes(int numberOfBytes)
67
+ {
68
+ var randomBytes = new byte[numberOfBytes];
69
+ Random.GetBytes(randomBytes);
70
+ return randomBytes;
71
+ }
72
+
73
+ private static byte[] MergeArrays(params byte[][] arrays)
74
+ {
75
+ var merged = new byte[arrays.Sum(a => a.Length)];
76
+ var mergeIndex = 0;
77
+ for (int i = 0; i < arrays.GetLength(0); i++)
78
+ {
79
+ arrays[i].CopyTo(merged, mergeIndex);
80
+ mergeIndex += arrays[i].Length;
81
+ }
82
+ return merged;
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,173 @@
1
+ using System;
2
+ using System.Collections.Concurrent;
3
+ using System.Collections.Generic;
4
+ using System.Net;
5
+ using System.Net.Http;
6
+ using System.Threading.Tasks;
7
+
8
+ namespace MessengerClient
9
+ {
10
+ public class HTTPMessengerClient : MessengerClient
11
+ {
12
+ private readonly string _uri;
13
+ private readonly HttpClient _httpClient;
14
+ private readonly byte[] _encryptionKey;
15
+ private readonly ConcurrentQueue<object> _downstreamMessages;
16
+ private string _messengerId;
17
+
18
+ public HTTPMessengerClient(string uri, byte[] encryptionKey, IWebProxy proxy = null)
19
+ {
20
+ _uri = uri;
21
+ _encryptionKey = encryptionKey;
22
+
23
+ var handler = new HttpClientHandler();
24
+ if (proxy != null)
25
+ {
26
+ handler.Proxy = proxy;
27
+ handler.UseProxy = true;
28
+ }
29
+
30
+ _httpClient = new HttpClient(handler);
31
+ _downstreamMessages = new ConcurrentQueue<object>();
32
+ }
33
+
34
+ public override async Task ConnectAsync()
35
+ {
36
+ int retryDelaySeconds = 15;
37
+ int maxTotalWaitSeconds = 1800;
38
+ int elapsedSeconds = 0;
39
+
40
+ while (elapsedSeconds < maxTotalWaitSeconds)
41
+ {
42
+ try
43
+ {
44
+ Console.WriteLine($"Connecting to HTTP server at {_uri}");
45
+
46
+ var downstreamMessage = MessageBuilder.SerializeMessage(_encryptionKey, new CheckInMessage(""));
47
+ HttpContent content = new ByteArrayContent(downstreamMessage);
48
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
49
+
50
+ var response = await _httpClient.PostAsync(_uri, content);
51
+ response.EnsureSuccessStatusCode();
52
+
53
+ byte[] responseBytes = await response.Content.ReadAsByteArrayAsync();
54
+
55
+ var (_, parsedMessage) = MessageParser.DeserializeMessage(_encryptionKey, responseBytes);
56
+
57
+ if (parsedMessage is CheckInMessage checkInMsg)
58
+ {
59
+ _messengerId = checkInMsg.MessengerId;
60
+ Console.WriteLine($"[+] Connected to server with Messenger ID: {_messengerId}");
61
+
62
+ await PollServerAsync(); // Enter main loop
63
+ return; // Exit reconnect loop on success
64
+ }
65
+ else
66
+ {
67
+ throw new InvalidOperationException(
68
+ $"Expected a CheckInMessage, but got {parsedMessage.GetType().Name}"
69
+ );
70
+ }
71
+ }
72
+ catch (Exception ex)
73
+ {
74
+ Console.WriteLine($"[!] Connection attempt failed: {ex.Message}");
75
+ elapsedSeconds += retryDelaySeconds;
76
+ if (elapsedSeconds >= maxTotalWaitSeconds)
77
+ {
78
+ Console.WriteLine("[-] Reconnect timeout after 30 minutes. Giving up.");
79
+ break;
80
+ }
81
+
82
+ Console.WriteLine("[*] Retrying connection in 15 seconds...");
83
+ await Task.Delay(retryDelaySeconds * 1000);
84
+ }
85
+ }
86
+ }
87
+
88
+
89
+ private async Task PollServerAsync()
90
+ {
91
+ while (true)
92
+ {
93
+ try
94
+ {
95
+ var downstreamMessages = new List<object>();
96
+
97
+ CheckInMessage checkInMessage = new CheckInMessage(_messengerId);
98
+ downstreamMessages.Add(checkInMessage);
99
+
100
+ while (_downstreamMessages.TryDequeue(out var message))
101
+ {
102
+ downstreamMessages.Add(message);
103
+ }
104
+
105
+ HttpContent content = new ByteArrayContent(SerializeMessages(_encryptionKey, downstreamMessages));
106
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
107
+ var response = await _httpClient.PostAsync(_uri, content);
108
+
109
+ if (!response.IsSuccessStatusCode)
110
+ {
111
+ Console.WriteLine($"Failed to poll server. HTTP {response.StatusCode}");
112
+ break;
113
+ }
114
+
115
+ var responseData = await response.Content.ReadAsByteArrayAsync();
116
+ var messages = DeserializeMessages(_encryptionKey, responseData);
117
+
118
+ foreach (var message in messages)
119
+ {
120
+ _ = Task.Run(() => HandleMessageAsync(message));
121
+ }
122
+
123
+ await Task.Delay(1000);
124
+ }
125
+ catch (Exception ex)
126
+ {
127
+ Console.WriteLine($"Error polling server: {ex.Message}");
128
+ break;
129
+ }
130
+ }
131
+ }
132
+
133
+ public override async Task SendDownstreamMessageAsync(object message)
134
+ {
135
+ try
136
+ {
137
+ _downstreamMessages.Enqueue(message);
138
+ }
139
+ catch (Exception ex)
140
+ {
141
+ Console.WriteLine($"Error enqueuing downstream message: {ex.Message}");
142
+ }
143
+ }
144
+
145
+ public override async Task HandleMessageAsync(object message)
146
+ {
147
+ switch (message)
148
+ {
149
+ case InitiateForwarderClientReq reqMessage:
150
+ await HandleInitiateForwarderClientReqAsync(reqMessage);
151
+ break;
152
+
153
+ case InitiateForwarderClientRep repMessage:
154
+ await StreamAsync(repMessage.ForwarderClientId);
155
+ break;
156
+
157
+ case SendDataMessage sendDataMessage:
158
+ if (ForwarderClients.TryGetValue(sendDataMessage.ForwarderClientId, out var client))
159
+ {
160
+ await client.GetStream().WriteAsync(sendDataMessage.Data, 0, sendDataMessage.Data.Length);
161
+ }
162
+ break;
163
+
164
+ case CheckInMessage checkInMessage:
165
+ break;
166
+
167
+ default:
168
+ Console.WriteLine("Unknown message type received");
169
+ break;
170
+ }
171
+ }
172
+ }
173
+ }
@@ -0,0 +1,410 @@
1
+ using System;
2
+ using System.Linq;
3
+ using System.Text;
4
+ using System.Security.Cryptography;
5
+
6
+
7
+ // ----------------------------------------------------------------------
8
+ // 1. Message Classes (now using int instead of uint)
9
+ // ----------------------------------------------------------------------
10
+ public class CheckInMessage
11
+ {
12
+ public string MessengerId { get; }
13
+ public CheckInMessage(string messengerId)
14
+ {
15
+ MessengerId = messengerId;
16
+ }
17
+ }
18
+
19
+ public class InitiateForwarderClientReq
20
+ {
21
+ public string ForwarderClientId { get; }
22
+ public string IpAddress { get; }
23
+ public int Port { get; }
24
+
25
+ public InitiateForwarderClientReq(string forwarderClientId, string ipAddress, int port)
26
+ {
27
+ ForwarderClientId = forwarderClientId;
28
+ IpAddress = ipAddress;
29
+ Port = port;
30
+ }
31
+ }
32
+
33
+ public class InitiateForwarderClientRep
34
+ {
35
+ public string ForwarderClientId { get; }
36
+ public string BindAddress { get; }
37
+ public int BindPort { get; }
38
+ public int AddressType { get; }
39
+ public int Reason { get; }
40
+
41
+ public InitiateForwarderClientRep(
42
+ string forwarderClientId,
43
+ string bindAddress,
44
+ int bindPort,
45
+ int addressType,
46
+ int reason)
47
+ {
48
+ ForwarderClientId = forwarderClientId;
49
+ BindAddress = bindAddress;
50
+ BindPort = bindPort;
51
+ AddressType = addressType;
52
+ Reason = reason;
53
+ }
54
+ }
55
+
56
+ public class SendDataMessage
57
+ {
58
+ public string ForwarderClientId { get; }
59
+ public byte[] Data { get; }
60
+
61
+ public SendDataMessage(string forwarderClientId, byte[] data)
62
+ {
63
+ ForwarderClientId = forwarderClientId;
64
+ Data = data;
65
+ }
66
+ }
67
+
68
+
69
+ // ----------------------------------------------------------------------
70
+ // 2. MessageParser: Reading/Decrypting Bytes
71
+ // ----------------------------------------------------------------------
72
+ public static class MessageParser
73
+ {
74
+ /// <summary>
75
+ /// Read the first 4 bytes of <paramref name="data"/> as a big-endian uint32.
76
+ /// Returns (uintValue, leftoverBytes).
77
+ /// </summary>
78
+ public static (uint Value, byte[] Remainder) ReadUInt32(byte[] data)
79
+ {
80
+ if (data.Length < 4)
81
+ throw new ArgumentException("Not enough bytes to read a 32-bit value.");
82
+
83
+ // Big-endian decode into a uint
84
+ uint value = (uint)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
85
+ byte[] remainder = data.Skip(4).ToArray();
86
+
87
+ return (value, remainder);
88
+ }
89
+
90
+ /// <summary>
91
+ /// Reads a length-prefixed UTF-8 string:
92
+ /// 1) read a uint32 length
93
+ /// 2) read 'length' bytes
94
+ /// 3) decode UTF-8
95
+ /// Returns (stringValue, leftoverBytes).
96
+ /// </summary>
97
+ public static (string Value, byte[] Remainder) ReadString(byte[] data)
98
+ {
99
+ var (length, remainder) = ReadUInt32(data);
100
+ if (remainder.Length < length)
101
+ throw new ArgumentException($"Not enough bytes to read string of length {length}.");
102
+
103
+ string s = Encoding.UTF8.GetString(remainder, 0, (int)length);
104
+ byte[] leftover = remainder.Skip((int)length).ToArray();
105
+
106
+ return (s, leftover);
107
+ }
108
+
109
+ /// <summary>
110
+ /// Parses the payload of a 0x04 'CheckIn' message (no decryption).
111
+ /// </summary>
112
+ public static CheckInMessage ParseCheckIn(byte[] value)
113
+ {
114
+ var (messengerId, _) = ReadString(value);
115
+ return new CheckInMessage(messengerId);
116
+ }
117
+
118
+ /// <summary>
119
+ /// Parses the payload of a 0x01 'InitiateForwarderClientReq' message.
120
+ /// </summary>
121
+ public static InitiateForwarderClientReq ParseInitiateForwarderClientReq(byte[] value)
122
+ {
123
+ var (forwarderClientId, remainder) = ReadString(value);
124
+ var (ipAddress, remainder2) = ReadString(remainder);
125
+ var (port, remainder3) = ReadUInt32(remainder2);
126
+
127
+ // cast uint -> int
128
+ return new InitiateForwarderClientReq(
129
+ forwarderClientId,
130
+ ipAddress,
131
+ (int)port
132
+ );
133
+ }
134
+
135
+ /// <summary>
136
+ /// Parses the payload of a 0x02 'InitiateForwarderClientRep' message.
137
+ /// </summary>
138
+ public static InitiateForwarderClientRep ParseInitiateForwarderClientRep(byte[] value)
139
+ {
140
+ var (forwarderClientId, remainder) = ReadString(value);
141
+ var (bindAddress, remainder2) = ReadString(remainder);
142
+ var (bindPort, remainder3) = ReadUInt32(remainder2);
143
+ var (addressType, remainder4) = ReadUInt32(remainder3);
144
+ var (reason, remainder5) = ReadUInt32(remainder4);
145
+
146
+ // cast all uint -> int
147
+ return new InitiateForwarderClientRep(
148
+ forwarderClientId,
149
+ bindAddress,
150
+ (int)bindPort,
151
+ (int)addressType,
152
+ (int)reason
153
+ );
154
+ }
155
+
156
+ /// <summary>
157
+ /// Parses the payload of a 0x03 'SendDataMessage'.
158
+ /// </summary>
159
+ public static SendDataMessage ParseSendData(byte[] value)
160
+ {
161
+ var (forwarderClientId, remainder) = ReadString(value);
162
+ var (encodedData, remainder2) = ReadString(remainder);
163
+
164
+ byte[] rawData = Convert.FromBase64String(encodedData);
165
+ return new SendDataMessage(
166
+ forwarderClientId,
167
+ rawData
168
+ );
169
+ }
170
+
171
+ /// <summary>
172
+ /// High-level parse entrypoint:
173
+ /// 1) read the message_type (uint32)
174
+ /// 2) read the message_length (uint32)
175
+ /// 3) slice out the encrypted payload
176
+ /// 4) decrypt or parse plaintext
177
+ /// Returns (leftoverBytes, parsedMessage).
178
+ /// </summary>
179
+ public static (byte[] leftover, object parsedMessage) DeserializeMessage(
180
+ byte[] encryptionKey,
181
+ byte[] rawData)
182
+ {
183
+ // 1) Read the message type
184
+ var (messageType, dataAfterType) = ReadUInt32(rawData);
185
+
186
+ // 2) Read the total message length
187
+ var (messageLength, dataAfterLength) = ReadUInt32(dataAfterType);
188
+
189
+ // 3) Extract the (messageLength - 8) payload bytes
190
+ int payloadLen = (int)messageLength - 8;
191
+ if (dataAfterLength.Length < payloadLen)
192
+ throw new ArgumentException("Not enough bytes in data for the payload.");
193
+
194
+ byte[] payload = dataAfterLength.Take(payloadLen).ToArray();
195
+ byte[] leftover = dataAfterLength.Skip(payloadLen).ToArray();
196
+
197
+ // 4) Decrypt or parse plaintext, depending on message type
198
+ object parsedMsg;
199
+ switch (messageType)
200
+ {
201
+ case 0x01:
202
+ {
203
+ byte[] decrypted = MessengerClient.Crypto.Decrypt(encryptionKey, payload);
204
+ parsedMsg = ParseInitiateForwarderClientReq(decrypted);
205
+ break;
206
+ }
207
+ case 0x02:
208
+ {
209
+ byte[] decrypted = MessengerClient.Crypto.Decrypt(encryptionKey, payload);
210
+ parsedMsg = ParseInitiateForwarderClientRep(decrypted);
211
+ break;
212
+ }
213
+ case 0x03:
214
+ {
215
+ byte[] decrypted = MessengerClient.Crypto.Decrypt(encryptionKey, payload);
216
+ parsedMsg = ParseSendData(decrypted);
217
+ break;
218
+ }
219
+ case 0x04:
220
+ {
221
+ // According to the Python version, we do NOT decrypt for 0x04
222
+ parsedMsg = ParseCheckIn(payload);
223
+ break;
224
+ }
225
+ default:
226
+ throw new ArgumentException($"Unknown message type: 0x{messageType:X}");
227
+ }
228
+
229
+ return (leftover, parsedMsg);
230
+ }
231
+ }
232
+
233
+
234
+ // ----------------------------------------------------------------------
235
+ // 3. MessageBuilder: Creating/Encrypting Bytes
236
+ // ----------------------------------------------------------------------
237
+ public static class MessageBuilder
238
+ {
239
+ /// <summary>
240
+ /// Given a message object (one of our 4 types), build the fully formed
241
+ /// byte array (header + possibly encrypted payload).
242
+ /// </summary>
243
+ public static byte[] SerializeMessage(byte[] encryptionKey, object msg)
244
+ {
245
+ byte[] payload;
246
+ uint messageType;
247
+
248
+ switch (msg)
249
+ {
250
+ case InitiateForwarderClientReq req:
251
+ messageType = 0x01;
252
+ payload = MessengerClient.Crypto.Encrypt(
253
+ encryptionKey,
254
+ BuildInitiateForwarderClientReq(
255
+ req.ForwarderClientId,
256
+ req.IpAddress,
257
+ req.Port
258
+ )
259
+ );
260
+ break;
261
+
262
+ case InitiateForwarderClientRep rep:
263
+ messageType = 0x02;
264
+ payload = MessengerClient.Crypto.Encrypt(
265
+ encryptionKey,
266
+ BuildInitiateForwarderClientRep(
267
+ rep.ForwarderClientId,
268
+ rep.BindAddress,
269
+ rep.BindPort,
270
+ rep.AddressType,
271
+ rep.Reason
272
+ )
273
+ );
274
+ break;
275
+
276
+ case SendDataMessage sdm:
277
+ messageType = 0x03;
278
+ payload = MessengerClient.Crypto.Encrypt(
279
+ encryptionKey,
280
+ BuildSendData(
281
+ sdm.ForwarderClientId,
282
+ sdm.Data
283
+ )
284
+ );
285
+ break;
286
+
287
+ case CheckInMessage cim:
288
+ messageType = 0x04;
289
+ // The Python code does not encrypt CheckInMessage
290
+ payload = BuildCheckInMessage(cim.MessengerId);
291
+ break;
292
+
293
+ default:
294
+ throw new ArgumentException($"Unknown message type: {msg.GetType().Name}");
295
+ }
296
+
297
+ return BuildMessage(messageType, payload);
298
+ }
299
+
300
+ /// <summary>
301
+ /// Packs [message_type, total_length, payload] together in big-endian format.
302
+ /// </summary>
303
+ public static byte[] BuildMessage(uint messageType, byte[] payload)
304
+ {
305
+ // total_length = 8 (header) + payload length
306
+ uint messageLength = (uint)(8 + payload.Length);
307
+
308
+ // Build the 8-byte header (all big-endian)
309
+ byte[] header = new byte[8];
310
+ WriteUInt32(header, 0, messageType); // message_type
311
+ WriteUInt32(header, 4, messageLength); // total_length
312
+
313
+ // Concatenate header + payload
314
+ return Combine(header, payload);
315
+ }
316
+
317
+ /// <summary>
318
+ /// Encodes a string with a 4-byte length prefix (big-endian), plus UTF-8 data.
319
+ /// </summary>
320
+ public static byte[] BuildString(string value)
321
+ {
322
+ byte[] encoded = Encoding.UTF8.GetBytes(value);
323
+ byte[] lengthBytes = new byte[4];
324
+ WriteUInt32(lengthBytes, 0, (uint)encoded.Length);
325
+
326
+ return Combine(lengthBytes, encoded);
327
+ }
328
+
329
+ public static byte[] BuildCheckInMessage(string messengerId)
330
+ {
331
+ return BuildString(messengerId);
332
+ }
333
+
334
+ public static byte[] BuildInitiateForwarderClientReq(
335
+ string forwarderClientId,
336
+ string ipAddress,
337
+ int port)
338
+ {
339
+ var part1 = BuildString(forwarderClientId);
340
+ var part2 = BuildString(ipAddress);
341
+
342
+ // We'll still write it as a uint on the wire
343
+ byte[] part3 = new byte[4];
344
+ WriteUInt32(part3, 0, (uint)port);
345
+
346
+ return Combine(part1, part2, part3);
347
+ }
348
+
349
+ public static byte[] BuildInitiateForwarderClientRep(
350
+ string forwarderClientId,
351
+ string bindAddress,
352
+ int bindPort,
353
+ int addressType,
354
+ int reason)
355
+ {
356
+ var part1 = BuildString(forwarderClientId);
357
+ var part2 = BuildString(bindAddress);
358
+
359
+ // Next 3 fields => 3*4 bytes => 12 bytes
360
+ byte[] part3 = new byte[12];
361
+ WriteUInt32(part3, 0, (uint)bindPort);
362
+ WriteUInt32(part3, 4, (uint)addressType);
363
+ WriteUInt32(part3, 8, (uint)reason);
364
+
365
+ return Combine(part1, part2, part3);
366
+ }
367
+
368
+ public static byte[] BuildSendData(
369
+ string forwarderClientId,
370
+ byte[] data)
371
+ {
372
+ var part1 = BuildString(forwarderClientId);
373
+ string encodedData = Convert.ToBase64String(data);
374
+ var part2 = BuildString(encodedData);
375
+
376
+ return Combine(part1, part2);
377
+ }
378
+
379
+ // ----------------------------------------------------------------------
380
+ // Helper: Write a uint32 to a byte array in big-endian
381
+ // ----------------------------------------------------------------------
382
+ public static void WriteUInt32(byte[] buffer, int offset, uint value)
383
+ {
384
+ buffer[offset] = (byte)((value >> 24) & 0xFF);
385
+ buffer[offset + 1] = (byte)((value >> 16) & 0xFF);
386
+ buffer[offset + 2] = (byte)((value >> 8) & 0xFF);
387
+ buffer[offset + 3] = (byte)(value & 0xFF);
388
+ }
389
+
390
+ // ----------------------------------------------------------------------
391
+ // Helper: Concatenate multiple byte arrays
392
+ // ----------------------------------------------------------------------
393
+ public static byte[] Combine(params byte[][] arrays)
394
+ {
395
+ int totalLength = 0;
396
+ foreach (var arr in arrays)
397
+ totalLength += arr.Length;
398
+
399
+ byte[] result = new byte[totalLength];
400
+ int offset = 0;
401
+
402
+ foreach (var arr in arrays)
403
+ {
404
+ Buffer.BlockCopy(arr, 0, result, offset, arr.Length);
405
+ offset += arr.Length;
406
+ }
407
+
408
+ return result;
409
+ }
410
+ }