telegram-ssh-bot 2.0.0 → 2.2.0

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 (184) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -22
  3. package/deploy/.env.example +86 -0
  4. package/dist/config/index.d.ts +68 -0
  5. package/dist/config/index.d.ts.map +1 -0
  6. package/dist/config/index.js +315 -0
  7. package/dist/config/index.js.map +1 -0
  8. package/dist/config/schema.d.ts +6 -0
  9. package/dist/config/schema.d.ts.map +1 -0
  10. package/dist/config/schema.js +50 -0
  11. package/dist/config/schema.js.map +1 -0
  12. package/dist/core/Bot.d.ts +91 -0
  13. package/dist/core/Bot.d.ts.map +1 -0
  14. package/dist/core/Bot.js +263 -0
  15. package/dist/core/Bot.js.map +1 -0
  16. package/dist/core/ConnectionPool.d.ts +125 -0
  17. package/dist/core/ConnectionPool.d.ts.map +1 -0
  18. package/dist/core/ConnectionPool.js +397 -0
  19. package/dist/core/ConnectionPool.js.map +1 -0
  20. package/dist/core/SSHClient.d.ts +112 -0
  21. package/dist/core/SSHClient.d.ts.map +1 -0
  22. package/dist/core/SSHClient.js +367 -0
  23. package/dist/core/SSHClient.js.map +1 -0
  24. package/dist/core/ServerManager.d.ts +80 -0
  25. package/dist/core/ServerManager.d.ts.map +1 -0
  26. package/dist/core/ServerManager.js +207 -0
  27. package/dist/core/ServerManager.js.map +1 -0
  28. package/dist/core/index.d.ts +8 -0
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +8 -0
  31. package/dist/core/index.js.map +1 -0
  32. package/dist/errors/AuthError.d.ts +30 -0
  33. package/dist/errors/AuthError.d.ts.map +1 -0
  34. package/dist/errors/AuthError.js +35 -0
  35. package/dist/errors/AuthError.js.map +1 -0
  36. package/dist/errors/BaseError.d.ts +17 -0
  37. package/dist/errors/BaseError.d.ts.map +1 -0
  38. package/dist/errors/BaseError.js +34 -0
  39. package/dist/errors/BaseError.js.map +1 -0
  40. package/dist/errors/ConfigurationError.d.ts +24 -0
  41. package/dist/errors/ConfigurationError.d.ts.map +1 -0
  42. package/dist/errors/ConfigurationError.js +24 -0
  43. package/dist/errors/ConfigurationError.js.map +1 -0
  44. package/dist/errors/PoolError.d.ts +21 -0
  45. package/dist/errors/PoolError.d.ts.map +1 -0
  46. package/dist/errors/PoolError.js +30 -0
  47. package/dist/errors/PoolError.js.map +1 -0
  48. package/dist/errors/SSHError.d.ts +24 -0
  49. package/dist/errors/SSHError.d.ts.map +1 -0
  50. package/dist/errors/SSHError.js +38 -0
  51. package/dist/errors/SSHError.js.map +1 -0
  52. package/dist/errors/StorageError.d.ts +24 -0
  53. package/dist/errors/StorageError.d.ts.map +1 -0
  54. package/dist/errors/StorageError.js +35 -0
  55. package/dist/errors/StorageError.js.map +1 -0
  56. package/dist/errors/ValidationError.d.ts +29 -0
  57. package/dist/errors/ValidationError.d.ts.map +1 -0
  58. package/dist/errors/ValidationError.js +35 -0
  59. package/dist/errors/ValidationError.js.map +1 -0
  60. package/dist/errors/index.d.ts +11 -0
  61. package/dist/errors/index.d.ts.map +1 -0
  62. package/dist/errors/index.js +18 -0
  63. package/dist/errors/index.js.map +1 -0
  64. package/dist/handlers/BaseHandler.d.ts +50 -0
  65. package/dist/handlers/BaseHandler.d.ts.map +1 -0
  66. package/dist/handlers/BaseHandler.js +87 -0
  67. package/dist/handlers/BaseHandler.js.map +1 -0
  68. package/dist/handlers/CommandHandler.d.ts +23 -0
  69. package/dist/handlers/CommandHandler.d.ts.map +1 -0
  70. package/dist/handlers/CommandHandler.js +99 -0
  71. package/dist/handlers/CommandHandler.js.map +1 -0
  72. package/dist/handlers/HealthHandler.d.ts +25 -0
  73. package/dist/handlers/HealthHandler.d.ts.map +1 -0
  74. package/dist/handlers/HealthHandler.js +51 -0
  75. package/dist/handlers/HealthHandler.js.map +1 -0
  76. package/dist/handlers/HelpHandler.d.ts +32 -0
  77. package/dist/handlers/HelpHandler.d.ts.map +1 -0
  78. package/dist/handlers/HelpHandler.js +76 -0
  79. package/dist/handlers/HelpHandler.js.map +1 -0
  80. package/dist/handlers/ServerHandler.d.ts +72 -0
  81. package/dist/handlers/ServerHandler.d.ts.map +1 -0
  82. package/dist/handlers/ServerHandler.js +272 -0
  83. package/dist/handlers/ServerHandler.js.map +1 -0
  84. package/dist/handlers/index.d.ts +9 -0
  85. package/dist/handlers/index.d.ts.map +1 -0
  86. package/dist/handlers/index.js +9 -0
  87. package/dist/handlers/index.js.map +1 -0
  88. package/dist/index.d.ts +10 -0
  89. package/dist/index.d.ts.map +1 -0
  90. package/dist/index.js +348 -0
  91. package/dist/index.js.map +1 -0
  92. package/dist/middleware/AuthMiddleware.d.ts +28 -0
  93. package/dist/middleware/AuthMiddleware.d.ts.map +1 -0
  94. package/dist/middleware/AuthMiddleware.js +49 -0
  95. package/dist/middleware/AuthMiddleware.js.map +1 -0
  96. package/dist/middleware/RateLimitMiddleware.d.ts +23 -0
  97. package/dist/middleware/RateLimitMiddleware.d.ts.map +1 -0
  98. package/dist/middleware/RateLimitMiddleware.js +34 -0
  99. package/dist/middleware/RateLimitMiddleware.js.map +1 -0
  100. package/dist/middleware/index.d.ts +6 -0
  101. package/dist/middleware/index.d.ts.map +1 -0
  102. package/dist/middleware/index.js +6 -0
  103. package/dist/middleware/index.js.map +1 -0
  104. package/dist/services/BackupService.d.ts +119 -0
  105. package/dist/services/BackupService.d.ts.map +1 -0
  106. package/dist/services/BackupService.js +313 -0
  107. package/dist/services/BackupService.js.map +1 -0
  108. package/dist/services/CryptoService.d.ts +37 -0
  109. package/dist/services/CryptoService.d.ts.map +1 -0
  110. package/dist/services/CryptoService.js +108 -0
  111. package/dist/services/CryptoService.js.map +1 -0
  112. package/dist/services/HealthService.d.ts +126 -0
  113. package/dist/services/HealthService.d.ts.map +1 -0
  114. package/dist/services/HealthService.js +213 -0
  115. package/dist/services/HealthService.js.map +1 -0
  116. package/dist/services/LoggingService.d.ts +115 -0
  117. package/dist/services/LoggingService.d.ts.map +1 -0
  118. package/dist/services/LoggingService.js +334 -0
  119. package/dist/services/LoggingService.js.map +1 -0
  120. package/dist/services/MonitoringService.d.ts +119 -0
  121. package/dist/services/MonitoringService.d.ts.map +1 -0
  122. package/dist/services/MonitoringService.js +267 -0
  123. package/dist/services/MonitoringService.js.map +1 -0
  124. package/dist/services/NotificationService.d.ts +132 -0
  125. package/dist/services/NotificationService.d.ts.map +1 -0
  126. package/dist/services/NotificationService.js +297 -0
  127. package/dist/services/NotificationService.js.map +1 -0
  128. package/dist/services/RateLimiter.d.ts +51 -0
  129. package/dist/services/RateLimiter.d.ts.map +1 -0
  130. package/dist/services/RateLimiter.js +141 -0
  131. package/dist/services/RateLimiter.js.map +1 -0
  132. package/dist/services/ValidationService.d.ts +49 -0
  133. package/dist/services/ValidationService.d.ts.map +1 -0
  134. package/dist/services/ValidationService.js +158 -0
  135. package/dist/services/ValidationService.js.map +1 -0
  136. package/dist/services/index.d.ts +12 -0
  137. package/dist/services/index.d.ts.map +1 -0
  138. package/dist/services/index.js +12 -0
  139. package/dist/services/index.js.map +1 -0
  140. package/dist/types/Bot.d.ts +63 -0
  141. package/dist/types/Bot.d.ts.map +1 -0
  142. package/dist/types/Bot.js +5 -0
  143. package/dist/types/Bot.js.map +1 -0
  144. package/dist/types/Config.d.ts +57 -0
  145. package/dist/types/Config.d.ts.map +1 -0
  146. package/dist/types/Config.js +5 -0
  147. package/dist/types/Config.js.map +1 -0
  148. package/dist/types/Errors.d.ts +37 -0
  149. package/dist/types/Errors.d.ts.map +1 -0
  150. package/dist/types/Errors.js +34 -0
  151. package/dist/types/Errors.js.map +1 -0
  152. package/dist/types/SSH.d.ts +56 -0
  153. package/dist/types/SSH.d.ts.map +1 -0
  154. package/dist/types/SSH.js +6 -0
  155. package/dist/types/SSH.js.map +1 -0
  156. package/dist/types/Server.d.ts +39 -0
  157. package/dist/types/Server.d.ts.map +1 -0
  158. package/dist/types/Server.js +5 -0
  159. package/dist/types/Server.js.map +1 -0
  160. package/dist/types/index.d.ts +10 -0
  161. package/dist/types/index.d.ts.map +1 -0
  162. package/dist/types/index.js +6 -0
  163. package/dist/types/index.js.map +1 -0
  164. package/dist/utils/commandUtils.d.ts +25 -0
  165. package/dist/utils/commandUtils.d.ts.map +1 -0
  166. package/dist/utils/commandUtils.js +94 -0
  167. package/dist/utils/commandUtils.js.map +1 -0
  168. package/dist/utils/fileUtils.d.ts +40 -0
  169. package/dist/utils/fileUtils.d.ts.map +1 -0
  170. package/dist/utils/fileUtils.js +114 -0
  171. package/dist/utils/fileUtils.js.map +1 -0
  172. package/dist/utils/index.d.ts +7 -0
  173. package/dist/utils/index.d.ts.map +1 -0
  174. package/dist/utils/index.js +7 -0
  175. package/dist/utils/index.js.map +1 -0
  176. package/dist/utils/pathUtils.d.ts +40 -0
  177. package/dist/utils/pathUtils.d.ts.map +1 -0
  178. package/dist/utils/pathUtils.js +140 -0
  179. package/dist/utils/pathUtils.js.map +1 -0
  180. package/package.json +31 -5
  181. package/scripts/build.sh +20 -0
  182. package/scripts/postinstall.js +87 -0
  183. package/scripts/release.sh +22 -0
  184. package/scripts/setup-env.js +237 -0
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Server Handler
3
+ * Handles server management commands: /add, /rm, /list, /ssh, /exit, /current
4
+ */
5
+ import { promises as fs } from "fs";
6
+ import { ConnectionFailedError } from "../errors/index.js";
7
+ import { BaseHandler } from "./BaseHandler.js";
8
+ /**
9
+ * Handler for /add command - add a new server
10
+ */
11
+ export class AddServerHandler extends BaseHandler {
12
+ name = "add";
13
+ description = "Add a new server configuration";
14
+ pattern = /^\/add/;
15
+ constructor(serverManager, sshClient, bot, logger) {
16
+ super(serverManager, sshClient, bot, logger);
17
+ }
18
+ async execute(context) {
19
+ const args = context.args.trim();
20
+ if (!args) {
21
+ await this.send(context.chatId, "Usage: /add <host> <username> [password] [port] [note]\n" +
22
+ 'Example: /add 192.168.1.1 root password123 22 "My Server"');
23
+ return;
24
+ }
25
+ try {
26
+ const parts = this.parseArgs(args);
27
+ if (!parts[0] || !parts[1]) {
28
+ await this.send(context.chatId, "❌ Host and username are required.");
29
+ return;
30
+ }
31
+ // Parse and validate port number
32
+ let port = 22;
33
+ if (parts[3]) {
34
+ const parsedPort = parseInt(parts[3], 10);
35
+ if (isNaN(parsedPort)) {
36
+ await this.send(context.chatId, "❌ Invalid port number. Must be a valid integer.");
37
+ return;
38
+ }
39
+ if (parsedPort < 1 || parsedPort > 65535) {
40
+ await this.send(context.chatId, "❌ Port must be between 1 and 65535.");
41
+ return;
42
+ }
43
+ port = parsedPort;
44
+ }
45
+ const config = {
46
+ host: parts[0],
47
+ username: parts[1],
48
+ password: parts[2],
49
+ port,
50
+ note: parts[4],
51
+ };
52
+ const server = await this.serverManager.add(config);
53
+ await this.send(context.chatId, `✅ Server added successfully!\n\n${this.formatServerInfo(server)}`);
54
+ }
55
+ catch (error) {
56
+ const message = error instanceof Error ? error.message : "Failed to add server";
57
+ await this.send(context.chatId, `❌ ${message}`);
58
+ }
59
+ }
60
+ parseArgs(args) {
61
+ // Handle quoted strings for note
62
+ const result = [];
63
+ let current = "";
64
+ let inQuotes = false;
65
+ for (const char of args) {
66
+ if (char === '"') {
67
+ inQuotes = !inQuotes;
68
+ }
69
+ else if (char === " " && !inQuotes) {
70
+ if (current) {
71
+ result.push(current);
72
+ current = "";
73
+ }
74
+ }
75
+ else {
76
+ current += char;
77
+ }
78
+ }
79
+ if (current) {
80
+ result.push(current);
81
+ }
82
+ return result;
83
+ }
84
+ }
85
+ /**
86
+ * Handler for /rm command - remove a server
87
+ */
88
+ export class RemoveServerHandler extends BaseHandler {
89
+ name = "rm";
90
+ description = "Remove a server by index";
91
+ pattern = /^\/rm/;
92
+ constructor(serverManager, sshClient, bot, logger) {
93
+ super(serverManager, sshClient, bot, logger);
94
+ }
95
+ async execute(context) {
96
+ const args = context.args.trim();
97
+ if (!args) {
98
+ await this.send(context.chatId, "Usage: /rm <index>\nUse /list to see server indices.");
99
+ return;
100
+ }
101
+ // BUG-003 FIX: Use parseInt instead of parseFloat
102
+ const index = parseInt(args, 10);
103
+ if (isNaN(index) || index < 1) {
104
+ await this.send(context.chatId, "❌ Invalid index. Please provide a valid number.");
105
+ return;
106
+ }
107
+ try {
108
+ const server = await this.serverManager.getByIndex(index);
109
+ if (!server) {
110
+ await this.send(context.chatId, `❌ Server at index ${index} not found.`);
111
+ return;
112
+ }
113
+ // Disconnect if removing current server
114
+ if (this.sshClient.isConnected() &&
115
+ this.serverManager.getCurrent()?.id === server.id) {
116
+ await this.sshClient.disconnect();
117
+ this.serverManager.clearCurrent();
118
+ }
119
+ await this.serverManager.removeByIndex(index);
120
+ await this.send(context.chatId, `✅ Server removed: \`${server.username}@${server.host}\``);
121
+ }
122
+ catch (error) {
123
+ const message = error instanceof Error ? error.message : "Failed to remove server";
124
+ await this.send(context.chatId, `❌ ${message}`);
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * Handler for /list command - list all servers
130
+ */
131
+ export class ListServerHandler extends BaseHandler {
132
+ name = "list";
133
+ description = "List all configured servers";
134
+ pattern = /^\/list/;
135
+ constructor(serverManager, sshClient, bot, logger) {
136
+ super(serverManager, sshClient, bot, logger);
137
+ }
138
+ async execute(context) {
139
+ const servers = await this.serverManager.list();
140
+ const message = this.formatServerList(servers);
141
+ await this.sendMarkdown(context.chatId, message);
142
+ }
143
+ }
144
+ /**
145
+ * Handler for /ssh command - connect to a server
146
+ */
147
+ export class SSHServerHandler extends BaseHandler {
148
+ name = "ssh";
149
+ description = "Connect to a server by index";
150
+ pattern = /^\/ssh/;
151
+ constructor(serverManager, sshClient, bot, logger) {
152
+ super(serverManager, sshClient, bot, logger);
153
+ }
154
+ async execute(context) {
155
+ const args = context.args.trim();
156
+ if (!args) {
157
+ await this.send(context.chatId, "Usage: /ssh <index>\nUse /list to see server indices.");
158
+ return;
159
+ }
160
+ // BUG-003 FIX: Use parseInt instead of parseFloat
161
+ const index = parseInt(args, 10);
162
+ if (isNaN(index) || index < 1) {
163
+ await this.send(context.chatId, "❌ Invalid index. Please provide a valid number.");
164
+ return;
165
+ }
166
+ const server = await this.serverManager.getByIndex(index);
167
+ if (!server) {
168
+ await this.send(context.chatId, `❌ Server at index ${index} not found.`);
169
+ return;
170
+ }
171
+ // Disconnect current connection
172
+ if (this.sshClient.isConnected()) {
173
+ await this.sshClient.disconnect();
174
+ this.serverManager.clearCurrent();
175
+ }
176
+ await this.send(context.chatId, `🔌 Connecting to \`${server.username}@${server.host}\`...`);
177
+ try {
178
+ // Get decrypted credentials
179
+ const credentials = this.serverManager.getDecryptedCredentials(server);
180
+ // Build SSH config
181
+ const sshConfig = {
182
+ host: server.host,
183
+ port: server.port,
184
+ username: server.username,
185
+ password: credentials.password,
186
+ passphrase: credentials.passphrase,
187
+ };
188
+ // Load private key if needed
189
+ if (server.auth.type === "privateKey" && credentials.privateKeyPath) {
190
+ try {
191
+ const keyBuffer = await fs.readFile(credentials.privateKeyPath);
192
+ sshConfig.privateKey = keyBuffer;
193
+ }
194
+ catch (error) {
195
+ throw new Error(`Failed to read private key: ${credentials.privateKeyPath}`);
196
+ }
197
+ }
198
+ // Connect
199
+ await this.sshClient.connect(sshConfig);
200
+ this.sshClient.setServerId(server.id);
201
+ this.serverManager.setCurrent(server);
202
+ await this.send(context.chatId, `✅ Connected to \`${server.username}@${server.host}\`\n` +
203
+ `Send any command to execute on the server.`);
204
+ this.logger.info("SSH connection established", {
205
+ serverId: server.id,
206
+ host: server.host,
207
+ chatId: context.chatId,
208
+ });
209
+ }
210
+ catch (error) {
211
+ if (error instanceof ConnectionFailedError) {
212
+ await this.send(context.chatId, `❌ Connection failed: ${error.message}`);
213
+ }
214
+ else {
215
+ const message = error instanceof Error ? error.message : "Unknown error";
216
+ await this.send(context.chatId, `❌ Failed to connect: ${message}`);
217
+ }
218
+ this.logger.error("SSH connection failed", error instanceof Error ? error : new Error(String(error)), {
219
+ serverId: server.id,
220
+ host: server.host,
221
+ });
222
+ }
223
+ }
224
+ }
225
+ /**
226
+ * Handler for /exit command - disconnect from current server
227
+ */
228
+ export class ExitServerHandler extends BaseHandler {
229
+ name = "exit";
230
+ description = "Disconnect from current SSH session";
231
+ pattern = /^\/exit/;
232
+ constructor(serverManager, sshClient, bot, logger) {
233
+ super(serverManager, sshClient, bot, logger);
234
+ }
235
+ async execute(context) {
236
+ if (!this.sshClient.isConnected()) {
237
+ await this.send(context.chatId, "❌ Not connected to any server.");
238
+ return;
239
+ }
240
+ const current = this.serverManager.getCurrent();
241
+ await this.sshClient.disconnect();
242
+ this.serverManager.clearCurrent();
243
+ const host = current?.host ?? "unknown";
244
+ await this.send(context.chatId, `👋 Disconnected from \`${host}\``);
245
+ this.logger.info("SSH disconnected", {
246
+ serverId: current?.id,
247
+ chatId: context.chatId,
248
+ });
249
+ }
250
+ }
251
+ /**
252
+ * Handler for /current command - show current server
253
+ */
254
+ export class CurrentServerHandler extends BaseHandler {
255
+ name = "current";
256
+ description = "Show current connected server";
257
+ pattern = /^\/current/;
258
+ constructor(serverManager, sshClient, bot, logger) {
259
+ super(serverManager, sshClient, bot, logger);
260
+ }
261
+ async execute(context) {
262
+ const current = this.serverManager.getCurrent();
263
+ if (!current) {
264
+ await this.send(context.chatId, "❌ Not connected to any server.\nUse /ssh <index> to connect.");
265
+ return;
266
+ }
267
+ const connected = this.sshClient.isConnected();
268
+ const status = connected ? "🟢 Connected" : "🔴 Disconnected";
269
+ await this.sendMarkdown(context.chatId, `${status}\n\n${this.formatServerInfo(current)}`);
270
+ }
271
+ }
272
+ //# sourceMappingURL=ServerHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerHandler.js","sourceRoot":"","sources":["../../src/handlers/ServerHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Handler modules index - exports all handlers
3
+ */
4
+ export { BaseHandler } from "./BaseHandler.js";
5
+ export { SSHCommandHandler } from "./CommandHandler.js";
6
+ export { HealthHandler } from "./HealthHandler.js";
7
+ export { HelpHandler, StartHandler } from "./HelpHandler.js";
8
+ export { AddServerHandler, CurrentServerHandler, ExitServerHandler, ListServerHandler, RemoveServerHandler, SSHServerHandler, } from "./ServerHandler.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Handler modules index - exports all handlers
3
+ */
4
+ export { BaseHandler } from "./BaseHandler.js";
5
+ export { SSHCommandHandler } from "./CommandHandler.js";
6
+ export { HealthHandler } from "./HealthHandler.js";
7
+ export { HelpHandler, StartHandler } from "./HelpHandler.js";
8
+ export { AddServerHandler, CurrentServerHandler, ExitServerHandler, ListServerHandler, RemoveServerHandler, SSHServerHandler, } from "./ServerHandler.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Telegram SSH Bot - Entry Point
4
+ *
5
+ * A secure Telegram bot for managing SSH connections
6
+ *
7
+ * @version 2.0.0
8
+ */
9
+ import "dotenv/config";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,348 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Telegram SSH Bot - Entry Point
4
+ *
5
+ * A secure Telegram bot for managing SSH connections
6
+ *
7
+ * @version 2.0.0
8
+ */
9
+ import "dotenv/config";
10
+ import { ConfigReloader, loadConfig, validateOwnerIds, } from "./config/index.js";
11
+ import { Bot, ConnectionPool, SSHClient, ServerManager } from "./core/index.js";
12
+ import { HealthHandler } from "./handlers/HealthHandler.js";
13
+ import { AddServerHandler, CurrentServerHandler, ExitServerHandler, HelpHandler, ListServerHandler, RemoveServerHandler, SSHCommandHandler, SSHServerHandler, StartHandler, } from "./handlers/index.js";
14
+ import { AuthMiddleware, RateLimitMiddleware } from "./middleware/index.js";
15
+ import { BackupService, CryptoService, HealthService, LoggingService, MonitoringService, NotificationService, RateLimiter, ValidationService, } from "./services/index.js";
16
+ /**
17
+ * Application class with enhanced graceful shutdown
18
+ */
19
+ class Application {
20
+ config;
21
+ configReloader;
22
+ logger;
23
+ cryptoService;
24
+ validationService;
25
+ rateLimiter;
26
+ sshClient;
27
+ connectionPool;
28
+ serverManager;
29
+ bot;
30
+ healthService;
31
+ monitoringService;
32
+ backupService;
33
+ notificationService;
34
+ state = "idle";
35
+ startTime;
36
+ shutdownTimeout = null;
37
+ isShuttingDown = false;
38
+ constructor() {
39
+ this.startTime = new Date();
40
+ }
41
+ /**
42
+ * Initialize the application
43
+ */
44
+ async initialize() {
45
+ if (this.state !== "idle") {
46
+ throw new Error(`Cannot initialize from state: ${this.state}`);
47
+ }
48
+ this.state = "initializing";
49
+ try {
50
+ // Load configuration
51
+ this.config = await loadConfig();
52
+ validateOwnerIds(this.config);
53
+ // Initialize config reloader for hot reload
54
+ this.configReloader = new ConfigReloader(this.config);
55
+ this.setupConfigReload();
56
+ // Initialize services
57
+ this.logger = new LoggingService(this.config.logging);
58
+ this.cryptoService = new CryptoService(this.config.security.encryptionKey);
59
+ this.validationService = new ValidationService({
60
+ allowedCommands: this.config.security.allowedCommands,
61
+ blockedCommands: this.config.security.blockedCommands,
62
+ });
63
+ this.rateLimiter = new RateLimiter(this.config.security.rateLimit);
64
+ this.rateLimiter.startAutoCleanup();
65
+ // Initialize health service
66
+ this.healthService = new HealthService({
67
+ version: "2.0.0",
68
+ startTime: this.startTime,
69
+ });
70
+ // Initialize notification service
71
+ this.notificationService = new NotificationService({
72
+ enabled: true,
73
+ notifyOnStartup: true,
74
+ notifyOnShutdown: true,
75
+ notifyOnErrors: true,
76
+ notifyOnSecurity: true,
77
+ adminChatId: this.config.telegram.chatId,
78
+ }, this.logger);
79
+ // Initialize backup service
80
+ this.backupService = new BackupService({
81
+ enabled: this.config.backup.enabled,
82
+ backupDir: "./backups",
83
+ maxBackups: this.config.backup.maxCount,
84
+ backupInterval: this.config.backup.intervalMs,
85
+ backupBeforeWrite: true,
86
+ }, this.logger);
87
+ await this.backupService.initialize();
88
+ // Initialize monitoring service
89
+ this.monitoringService = new MonitoringService({
90
+ enabled: this.config.monitoring.enabled,
91
+ checkInterval: this.config.monitoring.intervalMs,
92
+ timeout: 10000,
93
+ alertThreshold: 3,
94
+ cooldownPeriod: 300000,
95
+ }, this.logger);
96
+ this.setupMonitoring();
97
+ // Initialize core components
98
+ this.sshClient = new SSHClient({
99
+ connectionTimeout: this.config.ssh.connectionTimeout,
100
+ commandTimeout: this.config.ssh.commandTimeout,
101
+ });
102
+ // Initialize connection pool
103
+ this.connectionPool = new ConnectionPool({
104
+ maxConnections: this.config.ssh.maxConnections,
105
+ connectionTimeout: this.config.ssh.connectionTimeout,
106
+ commandTimeout: this.config.ssh.commandTimeout,
107
+ idleTimeout: 300000, // 5 minutes
108
+ healthCheckInterval: 60000, // 1 minute
109
+ maxHealthCheckFailures: 3,
110
+ }, this.logger);
111
+ await this.connectionPool.initialize();
112
+ this.serverManager = new ServerManager(this.config.storage.serversFile, this.cryptoService, this.logger);
113
+ // Initialize server manager
114
+ await this.serverManager.initialize();
115
+ // Initialize bot
116
+ this.bot = new Bot({
117
+ token: this.config.telegram.token,
118
+ ownerIds: this.config.telegram.ownerIds,
119
+ polling: this.config.telegram.polling,
120
+ }, this.logger);
121
+ // Set bot for notification service
122
+ this.notificationService.setBot(this.bot);
123
+ // Setup middleware
124
+ this.setupMiddleware();
125
+ // Register handlers
126
+ this.registerHandlers();
127
+ // Update health service
128
+ this.healthService.setBotHealth(true);
129
+ this.healthService.setStorageHealth(true);
130
+ this.state = "running";
131
+ this.logger.info("Application initialized", {
132
+ ownerCount: this.config.telegram.ownerIds.length,
133
+ serversFile: this.config.storage.serversFile,
134
+ });
135
+ }
136
+ catch (error) {
137
+ this.state = "idle";
138
+ throw error;
139
+ }
140
+ }
141
+ /**
142
+ * Setup configuration hot reload
143
+ */
144
+ setupConfigReload() {
145
+ this.configReloader.on("reload", (event) => {
146
+ this.logger.info("Configuration reloaded", {
147
+ changedKeys: event.changedKeys,
148
+ });
149
+ this.notificationService.notifyConfigReloaded(true);
150
+ });
151
+ this.configReloader.on("error", (error) => {
152
+ this.logger.error("Configuration reload failed", error);
153
+ this.notificationService.notifyConfigReloaded(false);
154
+ });
155
+ this.configReloader.startWatching();
156
+ }
157
+ /**
158
+ * Setup monitoring service
159
+ */
160
+ setupMonitoring() {
161
+ this.monitoringService.on("alert:triggered", (payload) => {
162
+ this.logger.warn("Monitoring alert triggered", {
163
+ serverId: payload.server.id,
164
+ status: payload.status,
165
+ });
166
+ this.notificationService.notifyConnectionLost(payload.server, payload.status.error);
167
+ });
168
+ this.monitoringService.on("server:recovered", (payload) => {
169
+ this.logger.info("Server recovered", {
170
+ serverId: payload.server.id,
171
+ });
172
+ this.notificationService.notifyConnectionRestored(payload.server);
173
+ });
174
+ }
175
+ /**
176
+ * Setup middleware stack
177
+ */
178
+ setupMiddleware() {
179
+ // Auth middleware - only allow authorized users
180
+ const authMiddleware = new AuthMiddleware(this.config.telegram.ownerIds, this.logger);
181
+ this.bot.use(authMiddleware);
182
+ // Rate limiting middleware
183
+ const rateLimitMiddleware = new RateLimitMiddleware(this.rateLimiter);
184
+ this.bot.use(rateLimitMiddleware);
185
+ this.logger.debug("Middleware configured");
186
+ }
187
+ /**
188
+ * Register command handlers
189
+ */
190
+ registerHandlers() {
191
+ // Server management handlers
192
+ this.bot.registerCommand(new AddServerHandler(this.serverManager, this.sshClient, this.bot, this.logger));
193
+ this.bot.registerCommand(new RemoveServerHandler(this.serverManager, this.sshClient, this.bot, this.logger));
194
+ this.bot.registerCommand(new ListServerHandler(this.serverManager, this.sshClient, this.bot, this.logger));
195
+ this.bot.registerCommand(new SSHServerHandler(this.serverManager, this.sshClient, this.bot, this.logger));
196
+ this.bot.registerCommand(new ExitServerHandler(this.serverManager, this.sshClient, this.bot, this.logger));
197
+ this.bot.registerCommand(new CurrentServerHandler(this.serverManager, this.sshClient, this.bot, this.logger));
198
+ // SSH command handler (for non-command messages)
199
+ this.bot.registerCommand(new SSHCommandHandler(this.serverManager, this.sshClient, this.bot, this.logger, this.validationService));
200
+ // Help handlers
201
+ this.bot.registerCommand(new HelpHandler(this.serverManager, this.sshClient, this.bot, this.logger));
202
+ this.bot.registerCommand(new StartHandler(this.serverManager, this.sshClient, this.bot, this.logger));
203
+ // Health handler
204
+ this.bot.registerCommand(new HealthHandler(this.serverManager, this.sshClient, this.bot, this.logger, this.healthService));
205
+ this.logger.debug("Handlers registered");
206
+ }
207
+ /**
208
+ * Start the application
209
+ */
210
+ async start() {
211
+ if (this.state !== "running") {
212
+ throw new Error(`Cannot start from state: ${this.state}`);
213
+ }
214
+ await this.bot.start();
215
+ // Send startup notification
216
+ await this.notificationService.notifyStartup("2.0.0");
217
+ this.logger.info("Bot started successfully");
218
+ }
219
+ /**
220
+ * Stop the application gracefully
221
+ */
222
+ async stop(options) {
223
+ const opts = {
224
+ reason: options?.reason ?? "Manual shutdown",
225
+ timeout: options?.timeout ?? 30000, // 30 seconds default
226
+ notifyAdmin: options?.notifyAdmin ?? true,
227
+ };
228
+ if (this.isShuttingDown) {
229
+ this.logger.warn("Shutdown already in progress");
230
+ return;
231
+ }
232
+ this.isShuttingDown = true;
233
+ this.state = "shutting_down";
234
+ this.logger.info("Starting graceful shutdown", { reason: opts.reason });
235
+ // Set timeout for forced shutdown
236
+ this.shutdownTimeout = setTimeout(() => {
237
+ this.logger.error("Graceful shutdown timeout exceeded, forcing exit");
238
+ process.exit(1);
239
+ }, opts.timeout);
240
+ try {
241
+ // Notify admin about shutdown
242
+ if (opts.notifyAdmin) {
243
+ await this.notificationService.notifyShutdown(opts.reason);
244
+ }
245
+ // Stop accepting new requests
246
+ this.healthService.setBotHealth(false);
247
+ // Stop monitoring
248
+ this.monitoringService.stop();
249
+ // Stop rate limiter auto cleanup
250
+ this.rateLimiter.stopAutoCleanup();
251
+ // Stop config watcher
252
+ this.configReloader.stopWatching();
253
+ // Disconnect SSH client
254
+ if (this.sshClient.isConnected()) {
255
+ this.logger.info("Disconnecting SSH client");
256
+ await this.sshClient.disconnect();
257
+ }
258
+ // Drain connection pool
259
+ this.logger.info("Draining connection pool");
260
+ await this.connectionPool.drain();
261
+ // Stop backup service
262
+ this.backupService.stop();
263
+ // Stop bot
264
+ this.logger.info("Stopping bot");
265
+ await this.bot.stop();
266
+ // Clear shutdown timeout
267
+ if (this.shutdownTimeout) {
268
+ clearTimeout(this.shutdownTimeout);
269
+ this.shutdownTimeout = null;
270
+ }
271
+ this.state = "stopped";
272
+ this.logger.info("Application stopped gracefully");
273
+ }
274
+ catch (error) {
275
+ this.logger.error("Error during shutdown", error);
276
+ throw error;
277
+ }
278
+ }
279
+ /**
280
+ * Get application state
281
+ */
282
+ getState() {
283
+ return this.state;
284
+ }
285
+ /**
286
+ * Get health service
287
+ */
288
+ getHealthService() {
289
+ return this.healthService;
290
+ }
291
+ }
292
+ /**
293
+ * Main entry point
294
+ */
295
+ async function main() {
296
+ const app = new Application();
297
+ // Track if we're already shutting down
298
+ let isShuttingDown = false;
299
+ /**
300
+ * Handle shutdown signals gracefully
301
+ */
302
+ const handleShutdown = async (signal) => {
303
+ if (isShuttingDown) {
304
+ console.log(`\nAlready shutting down, please wait...`);
305
+ return;
306
+ }
307
+ isShuttingDown = true;
308
+ console.log(`\nReceived ${signal}, initiating graceful shutdown...`);
309
+ try {
310
+ await app.stop({ reason: `Received ${signal}` });
311
+ process.exit(0);
312
+ }
313
+ catch (error) {
314
+ console.error("Error during shutdown:", error);
315
+ process.exit(1);
316
+ }
317
+ };
318
+ // Register signal handlers
319
+ process.on("SIGINT", () => handleShutdown("SIGINT"));
320
+ process.on("SIGTERM", () => handleShutdown("SIGTERM"));
321
+ process.on("SIGHUP", () => handleShutdown("SIGHUP"));
322
+ // Handle uncaught exceptions
323
+ process.on("uncaughtException", async (error) => {
324
+ console.error("Uncaught exception:", error);
325
+ try {
326
+ await handleShutdown("uncaughtException");
327
+ }
328
+ catch (e) {
329
+ console.error("Error during shutdown:", e);
330
+ }
331
+ process.exit(1);
332
+ });
333
+ // Handle unhandled promise rejections
334
+ process.on("unhandledRejection", (reason, promise) => {
335
+ console.error("Unhandled rejection at:", promise, "reason:", reason);
336
+ });
337
+ try {
338
+ await app.initialize();
339
+ await app.start();
340
+ }
341
+ catch (error) {
342
+ console.error("Failed to start application:", error);
343
+ process.exit(1);
344
+ }
345
+ }
346
+ // Run the application
347
+ main();
348
+ //# sourceMappingURL=index.js.map