messenger-proxy 0.4.2__tar.gz → 0.4.4__tar.gz

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 (62) hide show
  1. {messenger_proxy-0.4.2/messenger_proxy.egg-info → messenger_proxy-0.4.4}/PKG-INFO +4 -4
  2. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/README.md +3 -3
  3. messenger_proxy-0.4.4/builder/clients/csharp/README.md +137 -0
  4. messenger_proxy-0.4.4/builder/clients/csharp/builder.py +68 -0
  5. {messenger_proxy-0.4.2/builder/clients/csharp → messenger_proxy-0.4.4/builder/clients/csharp/templates}/MessengerClient/Crypto.cs +5 -4
  6. messenger_proxy-0.4.4/builder/clients/csharp/templates/MessengerClient/HTTPMessengerClient.cs +174 -0
  7. {messenger_proxy-0.4.2/builder/clients/csharp → messenger_proxy-0.4.4/builder/clients/csharp/templates}/MessengerClient/Message.cs +7 -66
  8. {messenger_proxy-0.4.2/builder/clients/csharp → messenger_proxy-0.4.4/builder/clients/csharp/templates}/MessengerClient/MessengerClient.cs +19 -12
  9. messenger_proxy-0.4.4/builder/clients/csharp/templates/MessengerClient/MessengerClient.csproj +14 -0
  10. messenger_proxy-0.4.4/builder/clients/csharp/templates/MessengerClient/Program.cs +197 -0
  11. {messenger_proxy-0.4.2/builder/clients/csharp → messenger_proxy-0.4.4/builder/clients/csharp/templates}/MessengerClient/RemotePortForwarder.cs +3 -19
  12. messenger_proxy-0.4.2/builder/clients/csharp/MessengerClient/WebsocketMessengerClient.cs → messenger_proxy-0.4.4/builder/clients/csharp/templates/MessengerClient/WebSocketMessengerClient.cs +74 -47
  13. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/nodejs/README.md +29 -14
  14. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/nodejs/builder.py +18 -5
  15. messenger_proxy-0.4.2/builder/clients/nodejs/electron → messenger_proxy-0.4.4/builder/clients/nodejs/templates/electron-main.js +10 -12
  16. messenger_proxy-0.4.4/builder/clients/nodejs/templates/electron-renderer.html +10 -0
  17. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/nodejs/templates/messenger-client.js +129 -51
  18. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/python/README.md +3 -3
  19. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/python/builder.py +2 -0
  20. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/python/templates/messenger-client.py +55 -33
  21. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/__init__.py +1 -1
  22. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4/messenger_proxy.egg-info}/PKG-INFO +4 -4
  23. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger_proxy.egg-info/SOURCES.txt +12 -12
  24. messenger_proxy-0.4.2/builder/clients/csharp/MessengerClient/HTTPMessengerClient.cs +0 -173
  25. messenger_proxy-0.4.2/builder/clients/csharp/MessengerClient/MessengerClient.csproj +0 -62
  26. messenger_proxy-0.4.2/builder/clients/csharp/MessengerClient/MessengerClient.sln +0 -25
  27. messenger_proxy-0.4.2/builder/clients/csharp/MessengerClient/Program.cs +0 -171
  28. messenger_proxy-0.4.2/builder/clients/csharp/MessengerClient/Properties/AssemblyInfo.cs +0 -36
  29. messenger_proxy-0.4.2/builder/clients/csharp/README.md +0 -41
  30. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/LICENSE +0 -0
  31. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/MANIFEST.in +0 -0
  32. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/__init__.py +0 -0
  33. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/__init__.py +0 -0
  34. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/csharp/.gitignore +0 -0
  35. {messenger_proxy-0.4.2/builder/clients/csharp → messenger_proxy-0.4.4/builder/clients/csharp/templates}/MessengerClient/App.config +0 -0
  36. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/nodejs/.gitignore +0 -0
  37. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/nodejs/requirements.txt +0 -0
  38. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/nodejs/webpack.conf.js +0 -0
  39. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/python/.github/workflows/python-version-tests.yml +0 -0
  40. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/python/.gitignore +0 -0
  41. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/builder/clients/python/requirements.txt +0 -0
  42. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/aes.py +0 -0
  43. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/convert.py +0 -0
  44. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/engine.py +0 -0
  45. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/forwarder_clients.py +0 -0
  46. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/forwarders.py +0 -0
  47. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/generator.py +0 -0
  48. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/http_ws_server.py +0 -0
  49. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/manager.py +0 -0
  50. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/message.py +0 -0
  51. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/messengers.py +0 -0
  52. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/output.py +0 -0
  53. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/resources/top_ports.txt +0 -0
  54. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/scanner.py +0 -0
  55. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger/text.py +0 -0
  56. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger-builder +0 -0
  57. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger-cli +0 -0
  58. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger_proxy.egg-info/dependency_links.txt +0 -0
  59. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger_proxy.egg-info/requires.txt +0 -0
  60. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/messenger_proxy.egg-info/top_level.txt +0 -0
  61. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/setup.cfg +0 -0
  62. {messenger_proxy-0.4.2 → messenger_proxy-0.4.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: messenger-proxy
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: Messenger uses a client-server architecture to establish a SOCKS5 tunnel. Once the client connects, the server will create a local SOCKS5 tunnel that can be used to interact with the local network the client is connected to.
5
5
  Home-page: https://github.com/skylerknecht/messenger
6
6
  Author: Skyler Knecht
@@ -67,7 +67,7 @@ operator~# messenger-cli -e readme
67
67
  | |\/| |/ _ \/ __/ __|/ _ \ '_ \ / _` |/ _ \ '__|
68
68
  | | | | __/\__ \__ \ __/ | | | (_| | __/ |
69
69
  |_| |_|\___||___/___/\___|_| |_|\__, |\___|_|
70
- by Skyler Knecht and Kevin Clark |___/ v0.4.2
70
+ by Skyler Knecht and Kevin Clark |___/ v0.4.4
71
71
  [*] The AES encryption key is readme
72
72
  [*] Waiting for messengers on http+ws://0.0.0.0:8080/
73
73
  (messenger)~#
@@ -108,8 +108,8 @@ operator~# ./client.py
108
108
  | Clients | Messenger Builder | Protocols | Local/Remote Port Forwarding | SOCKS5 TCP | SOCKS5 UDP |
109
109
  |--------------------------------------------------------------------|-------------------|-------------------|------------------------------|------------|---------------|
110
110
  | [Python](https://github.com/skylerknecht/messenger-client-python) | Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
111
- | [C#](https://github.com/skylerknecht/messenger-client-python) | Not Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
112
- | [Node JS](https://github.com/skylerknecht/messenger-client-nodejs) | Not Supported | WebSockets | Supported | Supported | Not Supported |
111
+ | [C#](https://github.com/skylerknecht/messenger-client-csharp) | Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
112
+ | [Node JS](https://github.com/skylerknecht/messenger-client-nodejs) | Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
113
113
 
114
114
  ## Credits
115
115
 
@@ -37,7 +37,7 @@ operator~# messenger-cli -e readme
37
37
  | |\/| |/ _ \/ __/ __|/ _ \ '_ \ / _` |/ _ \ '__|
38
38
  | | | | __/\__ \__ \ __/ | | | (_| | __/ |
39
39
  |_| |_|\___||___/___/\___|_| |_|\__, |\___|_|
40
- by Skyler Knecht and Kevin Clark |___/ v0.4.2
40
+ by Skyler Knecht and Kevin Clark |___/ v0.4.4
41
41
  [*] The AES encryption key is readme
42
42
  [*] Waiting for messengers on http+ws://0.0.0.0:8080/
43
43
  (messenger)~#
@@ -78,8 +78,8 @@ operator~# ./client.py
78
78
  | Clients | Messenger Builder | Protocols | Local/Remote Port Forwarding | SOCKS5 TCP | SOCKS5 UDP |
79
79
  |--------------------------------------------------------------------|-------------------|-------------------|------------------------------|------------|---------------|
80
80
  | [Python](https://github.com/skylerknecht/messenger-client-python) | Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
81
- | [C#](https://github.com/skylerknecht/messenger-client-python) | Not Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
82
- | [Node JS](https://github.com/skylerknecht/messenger-client-nodejs) | Not Supported | WebSockets | Supported | Supported | Not Supported |
81
+ | [C#](https://github.com/skylerknecht/messenger-client-csharp) | Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
82
+ | [Node JS](https://github.com/skylerknecht/messenger-client-nodejs) | Supported | HTTP & WebSockets | Supported | Supported | Not Supported |
83
83
 
84
84
  ## Credits
85
85
 
@@ -0,0 +1,137 @@
1
+ # C# Messenger Client
2
+
3
+ ## Overview
4
+
5
+ The Client is a .NET Framework 4.7.2 Messenger Client targeting Windows environments. The framework is preinstalled on Windows 10/11 and most enterprise systems, requiring no additional runtime to deploy.
6
+
7
+ ## Primary Capabilities
8
+
9
+ | Capability | Support Status |
10
+ |----------------------------|--------------------------------------------------------|
11
+ | Transports | HTTP and WebSockets |
12
+ | Encryption | AES-256-CBC with random IV prefix. |
13
+ | Reconnection procedure | Defaults to five (5) attempts over sixty (60) seconds. |
14
+ | SOCKS5 TCP | Supported |
15
+ | SOCKS5 UDP | Not Supported |
16
+
17
+ ## Client-Specific Capabilities
18
+
19
+ | Capability | Support Status |
20
+ |-------------------------------|--------------------------------------------------------------------------------------------------------|
21
+ | Compilation | Outputs a project directory requiring compilation with `dotnet build` (.NET SDK). |
22
+
23
+ ## Quick Start
24
+
25
+ ```
26
+ operator~# python builder.py --encryption-key test
27
+ [+] Wrote C# client to 'MessengerClient'
28
+
29
+ operator~# cd MessengerClient/MessengerClient
30
+ operator~# dotnet build -c Release
31
+ operator~# bin\Release\net472\MessengerClient.exe
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ To build the client, execute `builder.py` or `messenger-builder` from the [Messenger Repository](https://github.com/skylerknecht/messenger).
37
+
38
+ Both scripts accept the same options and will generate a C# Messenger Client project directory. If provided options, the builder scripts
39
+ will hard-code the options into the source files. Once built, the operator can specify command-line arguments that will override
40
+ the hardcoded options. The output is a .NET Framework 4.7.2 project that can be compiled with
41
+ `dotnet build` on any platform. Those options and their definitions are shown below.
42
+
43
+ ## Client Options
44
+
45
+ | Option | Flag | Default Value |
46
+ |-----------------------------------------------|---------------------------|------------------------|
47
+ | [Server URL](#server-url) | `--server-url` | localhost:8080 |
48
+ | [Encryption Key](#encryption-key) | `--encryption-key` | None |
49
+ | [User Agent](#user-agent) | `--user-agent` | [Specified Here](https://github.com/skylerknecht/messenger-client-csharp/blob/main/builder.py#L7) |
50
+ | [Proxy](#proxy) | `--proxy` | None |
51
+ | [Remote Port Forwards](#remote-port-forwards) | `--remote-port-forwards` | None |
52
+ | [Retry Duration](#retry-duration) | `--retry-duration` | One Minute |
53
+ | [Retry Attempts](#retry-attempts) | `--retry-attempts` | Five |
54
+ | [Name](#name) | `--name` | MessengerClient |
55
+
56
+ ### Server URL
57
+
58
+ Once the Messenger Server is running, the operator will be provided a server URL that can be set with `--server-url`.
59
+
60
+ ```
61
+ builder.py --server-url http://localhost:8080
62
+ ```
63
+
64
+ The client will attempt to establish a connection to the server based on the protocol specified in the server URL. For HTTP, leave the protocol as
65
+ `http://`, for websockets use `ws://`. Given that the server is listening with SSL encryption, provide the SSL
66
+ alternative to each protocol.
67
+
68
+ #### Encryption Key
69
+
70
+ Messenger Server will also provide an encryption key upon startup that can be hardcoded.
71
+
72
+ ```
73
+ builder.py --encryption-key SuP3rs_crEtk3y
74
+ ```
75
+
76
+ Since the server expects encryption, the default will likely cause issues; therefore, the client outputs an
77
+ error.
78
+
79
+ #### User Agent
80
+
81
+ For HTTP-based protocols, the operator can control the user-agent header.
82
+
83
+ ```
84
+ builder.py --user-agent "Test User Agent"
85
+ ```
86
+
87
+ #### Proxy
88
+
89
+ Enterprise environments typically have outbound proxies. Operators can provide a proxy using the HTTP-proxy schema.
90
+
91
+ ```
92
+ builder.py --proxy http://user:password@localhost:8080
93
+ ```
94
+
95
+ #### Remote Port Forwards
96
+
97
+ Messenger expects clients to attempt to set up remote port forwards on the client side. The operator can specify multiple port forwards
98
+ with the schema `LISTENING-HOST:LISTENING-PORT:DESTINATION-HOST:DESTINATION-PORT`.
99
+
100
+ ```
101
+ builder.py --remote-port-forwards localhost:8080:remotehost:8080
102
+ ```
103
+
104
+ This will forward all local connections on 8080 to a remote host on 8080. Given that the operator has not permitted the connection server-side,
105
+ they will see the following message.
106
+
107
+ ```
108
+ [!] Messenger `test` has no Remote Port Forwarder configured for remotehost:8080, denying forward!
109
+ ```
110
+
111
+ #### Retry Duration
112
+
113
+ Clients will disconnect for various reasons. Given that the client does not completely exit, it will attempt to reconnect. Operators can
114
+ control how long the client will attempt to reconnect by specifying a retry duration. This value is expected to be in seconds. For example,
115
+ if the retry duration is set to 120, then the client will attempt to reconnect for two minutes.
116
+
117
+ ```
118
+ builder.py --retry-duration 100
119
+ ```
120
+
121
+ To disable reconnection attempts, set the retry attempts option to 0.
122
+
123
+ #### Retry Attempts
124
+
125
+ In combination with the retry duration, retry attempts determine the minimum time the client waits between reconnection attempts.
126
+
127
+ ```
128
+ builder.py --retry-attempts 100
129
+ ```
130
+
131
+ #### Name
132
+
133
+ The build process outputs a project directory, and operators can control its name.
134
+
135
+ ```
136
+ builder.py --name CustomClient
137
+ ```
@@ -0,0 +1,68 @@
1
+ import argparse
2
+ import shutil
3
+
4
+ from pathlib import Path
5
+ from jinja2 import Environment, FileSystemLoader, select_autoescape
6
+
7
+ USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"
8
+
9
+ def add_arguments(parser):
10
+ builder = parser.add_argument_group("Builder options")
11
+ builder.add_argument("--name", default="MessengerClient",
12
+ help="Name of the output directory.")
13
+
14
+ cfg = parser.add_argument_group("Client configuration")
15
+ cfg.add_argument("--server-url", default="localhost:8080",
16
+ help="Server URL the client should connect to.")
17
+ cfg.add_argument("-e", "--encryption-key", default="",
18
+ help="AES encryption key to embed (optional).")
19
+ cfg.add_argument("--user-agent", default=USER_AGENT,
20
+ help="Custom HTTP/WebSocket User-Agent string (optional).")
21
+ cfg.add_argument("--proxy", default="",
22
+ help="Proxy to use (optional).")
23
+ cfg.add_argument("--remote-port-forwards", nargs="*", default=[],
24
+ help="Space delimited remote port forwards LISTENING-IP:LISTENING-PORT:REMOTE-IP:REMOTE-PORT (optional).")
25
+
26
+ retry = parser.add_argument_group("Retry behavior")
27
+ retry.add_argument("--retry-duration", type=float, default=60.0,
28
+ help="Total time to retry connecting.")
29
+ retry.add_argument("--retry-attempts", type=int, default=5,
30
+ help="Number of retry attempts before giving up.")
31
+
32
+
33
+ def build(args):
34
+ template_dir = Path(__file__).resolve().parent / "templates"
35
+ if not template_dir.is_dir():
36
+ raise RuntimeError(f"Template directory not found: {template_dir}")
37
+
38
+ env = Environment(
39
+ loader=FileSystemLoader(str(template_dir)),
40
+ autoescape=select_autoescape(enabled_extensions=("j2",)),
41
+ trim_blocks=True,
42
+ lstrip_blocks=True,
43
+ )
44
+
45
+ out_dir = Path(args.name)
46
+
47
+ for src in sorted(template_dir.rglob("*")):
48
+ if src.is_dir():
49
+ continue
50
+ rel = src.relative_to(template_dir)
51
+ dest = out_dir / rel
52
+ dest.parent.mkdir(parents=True, exist_ok=True)
53
+
54
+ if src.suffix == ".cs":
55
+ template = env.get_template(str(rel).replace("\\", "/"))
56
+ rendered = template.render(**vars(args))
57
+ dest.write_text(rendered, encoding="utf-8")
58
+ else:
59
+ shutil.copy2(src, dest)
60
+
61
+ print(f"[+] Wrote C# client to '{out_dir}'")
62
+
63
+
64
+ if __name__ == "__main__":
65
+ parser = argparse.ArgumentParser(usage=argparse.SUPPRESS)
66
+ add_arguments(parser)
67
+ parsed_args = parser.parse_args()
68
+ build(parsed_args)
@@ -1,4 +1,4 @@
1
- using System;
1
+ using System;
2
2
  using System.Linq;
3
3
  using System.Text;
4
4
  using System.Security.Cryptography;
@@ -15,13 +15,14 @@ namespace MessengerClient
15
15
  {
16
16
  using (SHA256 sha256 = SHA256.Create())
17
17
  {
18
- return sha256.ComputeHash(Encoding.ASCII.GetBytes(encryption_key));
18
+ return sha256.ComputeHash(Encoding.UTF8.GetBytes(encryption_key));
19
19
  }
20
20
  }
21
21
 
22
22
  public static byte[] Encrypt(byte[] key, ArraySegment<byte> plainText)
23
23
  {
24
- byte[] plainTextBytes = plainText.Array;
24
+ byte[] plainTextBytes = new byte[plainText.Count];
25
+ Array.Copy(plainText.Array, plainText.Offset, plainTextBytes, 0, plainText.Count);
25
26
  return Encrypt(key, plainTextBytes);
26
27
  }
27
28
 
@@ -82,4 +83,4 @@ namespace MessengerClient
82
83
  return merged;
83
84
  }
84
85
  }
85
- }
86
+ }
@@ -0,0 +1,174 @@
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 double _retryDuration;
16
+ private readonly int _retryAttempts;
17
+ private readonly ConcurrentQueue<object> _downstreamMessages;
18
+ private string _messengerId;
19
+
20
+ public HTTPMessengerClient(string uri, byte[] encryptionKey, string userAgent, double retryDuration, int retryAttempts, IWebProxy proxy = null)
21
+ {
22
+ _uri = uri;
23
+ _encryptionKey = encryptionKey;
24
+ _retryDuration = retryDuration;
25
+ _retryAttempts = retryAttempts;
26
+
27
+ var handler = new HttpClientHandler();
28
+ if (proxy != null)
29
+ {
30
+ handler.Proxy = proxy;
31
+ handler.UseProxy = true;
32
+ }
33
+
34
+ _httpClient = new HttpClient(handler);
35
+ _httpClient.DefaultRequestHeaders.Add("User-Agent", userAgent);
36
+ _downstreamMessages = new ConcurrentQueue<object>();
37
+ }
38
+
39
+ public override async Task ConnectAsync()
40
+ {
41
+ int retryDelay = (int)((_retryDuration / _retryAttempts) * 1000);
42
+ int consecutiveFailures = 0;
43
+
44
+ while (consecutiveFailures < _retryAttempts)
45
+ {
46
+ try
47
+ {
48
+ Console.WriteLine($"Connecting to HTTP server at {_uri}");
49
+
50
+ var downstreamMessage = MessageBuilder.SerializeMessage(_encryptionKey, new CheckInMessage(_messengerId));
51
+ HttpContent content = new ByteArrayContent(downstreamMessage);
52
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
53
+
54
+ var response = await _httpClient.PostAsync(_uri, content);
55
+ response.EnsureSuccessStatusCode();
56
+
57
+ if (string.IsNullOrEmpty(_messengerId))
58
+ {
59
+ byte[] responseBytes = await response.Content.ReadAsByteArrayAsync();
60
+ var (_, parsedMessage) = MessageParser.DeserializeMessage(_encryptionKey, responseBytes);
61
+
62
+ if (parsedMessage is CheckInMessage checkInMsg)
63
+ {
64
+ _messengerId = checkInMsg.MessengerId;
65
+ Console.WriteLine($"[+] Connected with Messenger ID: {_messengerId}");
66
+ }
67
+ else
68
+ {
69
+ throw new InvalidOperationException(
70
+ $"Expected CheckInMessage, got {parsedMessage.GetType().Name}"
71
+ );
72
+ }
73
+ }
74
+
75
+ consecutiveFailures = 0;
76
+ await PollServerAsync();
77
+ }
78
+ catch (Exception ex)
79
+ {
80
+ consecutiveFailures++;
81
+ Console.WriteLine($"[!] Connection failed: {ex.Message}");
82
+ if (consecutiveFailures < _retryAttempts)
83
+ {
84
+ Console.WriteLine("[*] Retrying connection...");
85
+ await Task.Delay(retryDelay);
86
+ }
87
+ }
88
+ }
89
+
90
+ Console.WriteLine($"[-] Reconnect failed after {_retryAttempts} attempts. Giving up.");
91
+ }
92
+
93
+
94
+ private async Task PollServerAsync()
95
+ {
96
+ while (true)
97
+ {
98
+ var downstreamMessages = new List<object>();
99
+
100
+ CheckInMessage checkInMessage = new CheckInMessage(_messengerId);
101
+ downstreamMessages.Add(checkInMessage);
102
+
103
+ while (_downstreamMessages.TryDequeue(out var message))
104
+ {
105
+ downstreamMessages.Add(message);
106
+ }
107
+
108
+ HttpContent content = new ByteArrayContent(SerializeMessages(_encryptionKey, downstreamMessages));
109
+ content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
110
+ var response = await _httpClient.PostAsync(_uri, content);
111
+
112
+ if (!response.IsSuccessStatusCode)
113
+ throw new HttpRequestException($"Poll failed: HTTP {response.StatusCode}");
114
+
115
+ var responseData = await response.Content.ReadAsByteArrayAsync();
116
+ var messages = DeserializeMessages(_encryptionKey, responseData);
117
+
118
+ foreach (var msg in messages)
119
+ {
120
+ _ = Task.Run(() => HandleMessageAsync(msg));
121
+ }
122
+
123
+ await Task.Delay(1000);
124
+ }
125
+ }
126
+
127
+ public override Task SendDownstreamMessageAsync(object message)
128
+ {
129
+ _downstreamMessages.Enqueue(message);
130
+ return Task.CompletedTask;
131
+ }
132
+
133
+ public override async Task HandleMessageAsync(object message)
134
+ {
135
+ switch (message)
136
+ {
137
+ case InitiateForwarderClientReq reqMessage:
138
+ await HandleInitiateForwarderClientReqAsync(reqMessage);
139
+ break;
140
+
141
+ case InitiateForwarderClientRep repMessage:
142
+ if (!ForwarderClients.TryGetValue(repMessage.ForwarderClientId, out var repClient))
143
+ break;
144
+ if (repMessage.Reason != 0)
145
+ {
146
+ if (ForwarderClients.TryRemove(repMessage.ForwarderClientId, out var denied))
147
+ denied.Close();
148
+ break;
149
+ }
150
+ await StreamAsync(repMessage.ForwarderClientId);
151
+ break;
152
+
153
+ case SendDataMessage sendDataMessage:
154
+ if (sendDataMessage.Data.Length == 0)
155
+ {
156
+ if (ForwarderClients.TryRemove(sendDataMessage.ForwarderClientId, out var closedClient))
157
+ closedClient.Close();
158
+ }
159
+ else if (ForwarderClients.TryGetValue(sendDataMessage.ForwarderClientId, out var client))
160
+ {
161
+ await client.GetStream().WriteAsync(sendDataMessage.Data, 0, sendDataMessage.Data.Length);
162
+ }
163
+ break;
164
+
165
+ case CheckInMessage checkInMessage:
166
+ break;
167
+
168
+ default:
169
+ Console.WriteLine("Unknown message type received");
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ }
@@ -1,4 +1,4 @@
1
- using System;
1
+ using System;
2
2
  using System.Linq;
3
3
  using System.Text;
4
4
  using System.Security.Cryptography;
@@ -71,29 +71,17 @@ public class SendDataMessage
71
71
  // ----------------------------------------------------------------------
72
72
  public static class MessageParser
73
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
74
  public static (uint Value, byte[] Remainder) ReadUInt32(byte[] data)
79
75
  {
80
76
  if (data.Length < 4)
81
77
  throw new ArgumentException("Not enough bytes to read a 32-bit value.");
82
78
 
83
- // Big-endian decode into a uint
84
79
  uint value = (uint)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
85
80
  byte[] remainder = data.Skip(4).ToArray();
86
81
 
87
82
  return (value, remainder);
88
83
  }
89
84
 
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
85
  public static (string Value, byte[] Remainder) ReadString(byte[] data)
98
86
  {
99
87
  var (length, remainder) = ReadUInt32(data);
@@ -106,25 +94,18 @@ public static class MessageParser
106
94
  return (s, leftover);
107
95
  }
108
96
 
109
- /// <summary>
110
- /// Parses the payload of a 0x04 'CheckIn' message (no decryption).
111
- /// </summary>
112
97
  public static CheckInMessage ParseCheckIn(byte[] value)
113
98
  {
114
99
  var (messengerId, _) = ReadString(value);
115
100
  return new CheckInMessage(messengerId);
116
101
  }
117
102
 
118
- /// <summary>
119
- /// Parses the payload of a 0x01 'InitiateForwarderClientReq' message.
120
- /// </summary>
121
103
  public static InitiateForwarderClientReq ParseInitiateForwarderClientReq(byte[] value)
122
104
  {
123
105
  var (forwarderClientId, remainder) = ReadString(value);
124
106
  var (ipAddress, remainder2) = ReadString(remainder);
125
107
  var (port, remainder3) = ReadUInt32(remainder2);
126
108
 
127
- // cast uint -> int
128
109
  return new InitiateForwarderClientReq(
129
110
  forwarderClientId,
130
111
  ipAddress,
@@ -132,9 +113,6 @@ public static class MessageParser
132
113
  );
133
114
  }
134
115
 
135
- /// <summary>
136
- /// Parses the payload of a 0x02 'InitiateForwarderClientRep' message.
137
- /// </summary>
138
116
  public static InitiateForwarderClientRep ParseInitiateForwarderClientRep(byte[] value)
139
117
  {
140
118
  var (forwarderClientId, remainder) = ReadString(value);
@@ -143,7 +121,6 @@ public static class MessageParser
143
121
  var (addressType, remainder4) = ReadUInt32(remainder3);
144
122
  var (reason, remainder5) = ReadUInt32(remainder4);
145
123
 
146
- // cast all uint -> int
147
124
  return new InitiateForwarderClientRep(
148
125
  forwarderClientId,
149
126
  bindAddress,
@@ -153,9 +130,6 @@ public static class MessageParser
153
130
  );
154
131
  }
155
132
 
156
- /// <summary>
157
- /// Parses the payload of a 0x03 'SendDataMessage'.
158
- /// </summary>
159
133
  public static SendDataMessage ParseSendData(byte[] value)
160
134
  {
161
135
  var (forwarderClientId, remainder) = ReadString(value);
@@ -168,33 +142,23 @@ public static class MessageParser
168
142
  );
169
143
  }
170
144
 
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
145
  public static (byte[] leftover, object parsedMessage) DeserializeMessage(
180
146
  byte[] encryptionKey,
181
147
  byte[] rawData)
182
148
  {
183
- // 1) Read the message type
184
149
  var (messageType, dataAfterType) = ReadUInt32(rawData);
185
-
186
- // 2) Read the total message length
187
150
  var (messageLength, dataAfterLength) = ReadUInt32(dataAfterType);
188
151
 
189
- // 3) Extract the (messageLength - 8) payload bytes
190
- int payloadLen = (int)messageLength - 8;
152
+ if (messageLength < 8)
153
+ throw new ArgumentException("Invalid message: length field too small.");
154
+
155
+ int payloadLen = (int)(messageLength - 8);
191
156
  if (dataAfterLength.Length < payloadLen)
192
157
  throw new ArgumentException("Not enough bytes in data for the payload.");
193
158
 
194
159
  byte[] payload = dataAfterLength.Take(payloadLen).ToArray();
195
160
  byte[] leftover = dataAfterLength.Skip(payloadLen).ToArray();
196
161
 
197
- // 4) Decrypt or parse plaintext, depending on message type
198
162
  object parsedMsg;
199
163
  switch (messageType)
200
164
  {
@@ -218,7 +182,6 @@ public static class MessageParser
218
182
  }
219
183
  case 0x04:
220
184
  {
221
- // According to the Python version, we do NOT decrypt for 0x04
222
185
  parsedMsg = ParseCheckIn(payload);
223
186
  break;
224
187
  }
@@ -236,10 +199,6 @@ public static class MessageParser
236
199
  // ----------------------------------------------------------------------
237
200
  public static class MessageBuilder
238
201
  {
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
202
  public static byte[] SerializeMessage(byte[] encryptionKey, object msg)
244
203
  {
245
204
  byte[] payload;
@@ -286,7 +245,6 @@ public static class MessageBuilder
286
245
 
287
246
  case CheckInMessage cim:
288
247
  messageType = 0x04;
289
- // The Python code does not encrypt CheckInMessage
290
248
  payload = BuildCheckInMessage(cim.MessengerId);
291
249
  break;
292
250
 
@@ -297,26 +255,17 @@ public static class MessageBuilder
297
255
  return BuildMessage(messageType, payload);
298
256
  }
299
257
 
300
- /// <summary>
301
- /// Packs [message_type, total_length, payload] together in big-endian format.
302
- /// </summary>
303
258
  public static byte[] BuildMessage(uint messageType, byte[] payload)
304
259
  {
305
- // total_length = 8 (header) + payload length
306
260
  uint messageLength = (uint)(8 + payload.Length);
307
261
 
308
- // Build the 8-byte header (all big-endian)
309
262
  byte[] header = new byte[8];
310
- WriteUInt32(header, 0, messageType); // message_type
311
- WriteUInt32(header, 4, messageLength); // total_length
263
+ WriteUInt32(header, 0, messageType);
264
+ WriteUInt32(header, 4, messageLength);
312
265
 
313
- // Concatenate header + payload
314
266
  return Combine(header, payload);
315
267
  }
316
268
 
317
- /// <summary>
318
- /// Encodes a string with a 4-byte length prefix (big-endian), plus UTF-8 data.
319
- /// </summary>
320
269
  public static byte[] BuildString(string value)
321
270
  {
322
271
  byte[] encoded = Encoding.UTF8.GetBytes(value);
@@ -339,7 +288,6 @@ public static class MessageBuilder
339
288
  var part1 = BuildString(forwarderClientId);
340
289
  var part2 = BuildString(ipAddress);
341
290
 
342
- // We'll still write it as a uint on the wire
343
291
  byte[] part3 = new byte[4];
344
292
  WriteUInt32(part3, 0, (uint)port);
345
293
 
@@ -356,7 +304,6 @@ public static class MessageBuilder
356
304
  var part1 = BuildString(forwarderClientId);
357
305
  var part2 = BuildString(bindAddress);
358
306
 
359
- // Next 3 fields => 3*4 bytes => 12 bytes
360
307
  byte[] part3 = new byte[12];
361
308
  WriteUInt32(part3, 0, (uint)bindPort);
362
309
  WriteUInt32(part3, 4, (uint)addressType);
@@ -376,9 +323,6 @@ public static class MessageBuilder
376
323
  return Combine(part1, part2);
377
324
  }
378
325
 
379
- // ----------------------------------------------------------------------
380
- // Helper: Write a uint32 to a byte array in big-endian
381
- // ----------------------------------------------------------------------
382
326
  public static void WriteUInt32(byte[] buffer, int offset, uint value)
383
327
  {
384
328
  buffer[offset] = (byte)((value >> 24) & 0xFF);
@@ -387,9 +331,6 @@ public static class MessageBuilder
387
331
  buffer[offset + 3] = (byte)(value & 0xFF);
388
332
  }
389
333
 
390
- // ----------------------------------------------------------------------
391
- // Helper: Concatenate multiple byte arrays
392
- // ----------------------------------------------------------------------
393
334
  public static byte[] Combine(params byte[][] arrays)
394
335
  {
395
336
  int totalLength = 0;